spi nor: spicc: change to use spicc to access spi nor [1/1]

PD#TV-8401

Problem:
Customer needs to access spi nor by the spicc.

Solution:
add spi nor interfaces in spicc driver.
add gd25q80c/FM25Q08A surpport

Verify:
tl1 x301

Change-Id: If94858d46c31fea6b37034a8b1dfe94a9e9f4603
Signed-off-by: Sunny Luo <sunny.luo@amlogic.com>
This commit is contained in:
Sunny Luo
2019-08-12 13:04:33 +08:00
committed by Luke Go
parent 61beb18a8f
commit 3d98c25680
8 changed files with 336 additions and 29 deletions

View File

@@ -42,6 +42,8 @@
i2c2 = &i2c2;
i2c3 = &i2c3;
i2c4 = &i2c_AO;
spi0 = &spicc_a;
spi1 = &spicc1;
};
memory@00000000 {
@@ -1856,6 +1858,72 @@
status = "disable";
};
&ethmac {
status = "okay";
pinctrl-names = "internal_eth_pins";
pinctrl-0 = <&internal_eth_pins>;
mc_val = <0x4be04>;
internal_phy=<1>;
};
&uart_A {
status = "okay";
};
&dwc3 {
status = "okay";
};
&usb2_phy_v2 {
status = "okay";
portnum = <3>;
};
&usb3_phy_v2 {
status = "okay";
portnum = <0>;
otg = <0>;
};
&dwc2_a {
status = "okay";
/** 0: normal, 1: otg+dwc3 host only, 2: otg+dwc3 device only*/
controller-type = <1>;
};
&spicc0 {
status = "disabled";
pinctrl-names = "default";
pinctrl-0 = <&spicc0_pins_h>;
cs-gpios = <&gpio GPIOH_20 0>;
};
&spicc_a {
status = "okay";
pinctrl-names= "default";
pinctrl-0=<&spicc0_pins_h>;
cs-gpios = <&gpio GPIOH_20 GPIO_ACTIVE_HIGH>;
spi-nor@0 {
compatible = "jedec,spi-nor";
status = "okay";
frequency = <40000000>;
};
};
&meson_fb {
status = "okay";
display_size_default = <1920 1080 1920 2160 32>;
mem_size = <0x00800000 0x1980000 0x100000 0x800000>;
logo_addr = "0x7f800000";
mem_alloc = <0>;
pxp_mode = <0>; /** 0:normal mode 1:pxp mode */
};
&pwm_AO_cd {
status = "okay";
};
&pcie_A {
reset-gpio = <&gpio GPIOX_7 GPIO_ACTIVE_HIGH>;
status = "disable";

View File

@@ -40,7 +40,7 @@
i2c2 = &i2c2;
i2c3 = &i2c3;
i2c4 = &i2c_AO;
spi0 = &spicc0;
spi0 = &spicc_a;
spi1 = &spicc1;
};
@@ -2046,12 +2046,24 @@
};
&spicc0 {
status = "okay";
status = "disabled";
pinctrl-names = "default";
pinctrl-0 = <&spicc0_pins_h>;
cs-gpios = <&gpio GPIOH_20 0>;
};
&spicc_a {
status = "okay";
pinctrl-names= "default";
pinctrl-0=<&spicc0_pins_h>;
cs-gpios = <&gpio GPIOH_20 GPIO_ACTIVE_HIGH>;
spi-nor@0 {
compatible = "jedec,spi-nor";
status = "okay";
frequency = <40000000>;
};
};
&meson_fb {
status = "okay";
display_size_default = <1920 1080 1920 2160 32>;

View File

@@ -389,6 +389,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_OOPS=y
CONFIG_MTD_NAND=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_UBI=y
CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y

View File

@@ -40,6 +40,7 @@
i2c2 = &i2c2;
i2c3 = &i2c3;
i2c4 = &i2c_AO;
spi0 = &spicc_a;
};
memory@00000000 {
@@ -1818,12 +1819,24 @@
};
&spicc0 {
status = "okay";
status = "disabled";
pinctrl-names = "default";
pinctrl-0 = <&spicc0_pins_h>;
cs-gpios = <&gpio GPIOH_20 0>;
};
&spicc_a {
status = "okay";
pinctrl-names= "default";
pinctrl-0=<&spicc0_pins_h>;
cs-gpios = <&gpio GPIOH_20 GPIO_ACTIVE_HIGH>;
spi-nor@0 {
compatible = "jedec,spi-nor";
status = "okay";
frequency = <40000000>;
};
};
&meson_fb {
status = "okay";
display_size_default = <1920 1080 1920 2160 32>;

View File

@@ -40,6 +40,7 @@
i2c2 = &i2c2;
i2c3 = &i2c3;
i2c4 = &i2c_AO;
spi0 = &spicc_a;
};
memory@00000000 {
@@ -1813,12 +1814,24 @@
};
&spicc0 {
status = "okay";
status = "disabled";
pinctrl-names = "default";
pinctrl-0 = <&spicc0_pins_h>;
cs-gpios = <&gpio GPIOH_20 0>;
};
&spicc_a {
status = "okay";
pinctrl-names= "default";
pinctrl-0=<&spicc0_pins_h>;
cs-gpios = <&gpio GPIOH_20 GPIO_ACTIVE_HIGH>;
spi-nor@0 {
compatible = "jedec,spi-nor";
status = "okay";
frequency = <40000000>;
};
};
&meson_fb {
status = "okay";
display_size_default = <1920 1080 1920 2160 32>;

View File

@@ -384,6 +384,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_OOPS=y
CONFIG_MTD_NAND=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_UBI=y
CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y

View File

@@ -35,6 +35,9 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/of_irq.h>
#ifdef CONFIG_MTD_SPI_NOR
#include <linux/mtd/spi-nor.h>
#endif
#include "spicc.h"
/* #define CONFIG_SPICC_LOG */
@@ -104,6 +107,13 @@ struct spicc {
int log_size;
int log_count;
#endif
#ifdef CONFIG_MTD_SPI_NOR
struct device *dev;
struct spi_nor *nor;
int nor_cs;
/* used by nor core */
struct mutex nor_lock;
#endif
};
#ifdef CONFIG_SPICC_LOG
@@ -339,7 +349,7 @@ static void spicc_set_clk(struct spicc *spicc, int speed)
sys_clk_rate = clk_get_rate(spicc->clk);
if (spicc_get_flag(spicc, FLAG_ENHANCE)) {
div = sys_clk_rate/speed;
div = DIV_ROUND_UP(sys_clk_rate, speed);
if (div < 2)
div = 2;
div = (div >> 1) - 1;
@@ -733,6 +743,136 @@ int dirspi_register_board_info(struct spi_board_info const *info,
}
EXPORT_SYMBOL_GPL(dirspi_register_board_info);
#ifdef CONFIG_MTD_SPI_NOR
static int meson_snor_prep(struct spi_nor *nor, enum spi_nor_ops ops)
{
struct spicc *spicc = nor->priv;
mutex_lock(&spicc->nor_lock);
return 0;
}
static void meson_snor_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
{
struct spicc *spicc = nor->priv;
mutex_unlock(&spicc->nor_lock);
}
static int meson_snor_read_reg(struct spi_nor *nor, u8 opcode,
u8 *buf, int len)
{
struct spicc *spicc = nor->priv;
int ret;
gpio_direction_output(spicc->nor_cs, 0);
ret = spicc_hw_xfer(spicc, &opcode, 0, 1);
if (!ret)
ret = spicc_hw_xfer(spicc, 0, buf, len);
gpio_direction_output(spicc->nor_cs, 1);
return ret;
}
ssize_t meson_snor_read(struct spi_nor *nor, loff_t from,
size_t len, u_char *read_buf)
{
struct spicc *spicc = nor->priv;
u8 tx_buf[4];
int ret;
gpio_direction_output(spicc->nor_cs, 0);
tx_buf[0] = nor->read_opcode;
tx_buf[1] = (from >> 16) & 0xff;
tx_buf[2] = (from >> 8) & 0xff;
tx_buf[3] = from & 0xff;
ret = spicc_hw_xfer(spicc, tx_buf, 0, 4);
if (!ret)
ret = spicc_hw_xfer(spicc, 0, read_buf, len);
gpio_direction_output(spicc->nor_cs, 1);
return ret ? 0 : len;
}
static int meson_snor_write_reg(struct spi_nor *nor, u8 opcode,
u8 *buf, int len)
{
struct spicc *spicc = nor->priv;
int ret;
gpio_direction_output(spicc->nor_cs, 0);
ret = spicc_hw_xfer(spicc, &opcode, 0, 1);
if (!ret)
ret = spicc_hw_xfer(spicc, buf, 0, len);
gpio_direction_output(spicc->nor_cs, 1);
return ret;
}
static ssize_t meson_snor_write(struct spi_nor *nor, loff_t to,
size_t len, const u_char *write_buf)
{
struct spicc *spicc = nor->priv;
u8 tx_buf[4];
int ret;
gpio_direction_output(spicc->nor_cs, 0);
tx_buf[0] = nor->program_opcode;
tx_buf[1] = (to >> 16) & 0xff;
tx_buf[2] = (to >> 8) & 0xff;
tx_buf[3] = to & 0xff;
ret = spicc_hw_xfer(spicc, tx_buf, 0, 4);
if (!ret)
ret = spicc_hw_xfer(spicc, (u8 *)write_buf, 0, len);
gpio_direction_output(spicc->nor_cs, 1);
return ret ? 0 : len;
}
static struct spi_nor *meson_snor_init(struct spicc *spicc,
struct device_node *np)
{
struct device *dev = spicc->dev;
struct spi_nor *nor;
struct mtd_info *mtd;
nor = devm_kzalloc(dev, sizeof(*nor), GFP_KERNEL);
if (!nor)
return 0;
nor->dev = dev;
spi_nor_set_flash_node(nor, np);
nor->priv = spicc;
nor->prepare = meson_snor_prep;
nor->unprepare = meson_snor_unprep;
nor->read_reg = meson_snor_read_reg;
nor->write_reg = meson_snor_write_reg;
nor->read = meson_snor_read;
nor->write = meson_snor_write;
nor->erase = NULL;
mtd = &nor->mtd;
mtd->name = (np->name) ? np->name : "meson_snor";
if (!spi_nor_scan(nor, NULL, SPI_NOR_NORMAL)) {
if (!mtd_device_register(mtd, NULL, 0))
return nor;
}
devm_kfree(dev, nor);
return 0;
}
#endif /* end CONFIG_MTD_SPI_NOR */
/* setting clock and pinmux here */
static int spicc_setup(struct spi_device *spi)
{
@@ -1107,8 +1247,77 @@ static int spicc_probe(struct platform_device *pdev)
struct spi_master *master;
struct spicc *spicc;
int i, ret;
#ifdef CONFIG_MTD_SPI_NOR
struct device_node *child, *np = pdev->dev.of_node;
int speed;
#endif
WARN_ON(!pdev->dev.of_node);
spicc = devm_kzalloc(&pdev->dev, sizeof(*spicc), GFP_KERNEL);
if (!spicc)
return -ENOMEM;
dev_set_drvdata(&pdev->dev, spicc);
ret = of_spicc_get_data(spicc, pdev);
if (ret) {
dev_err(&pdev->dev, "of error=%d\n", ret);
goto err1;
}
spicc_hw_init(spicc);
spicc_log_init(spicc);
spicc_log(spicc, 0, 0, PROBE_BEGIN);
spin_lock_init(&spicc->lock);
init_completion(&spicc->completion);
if (spicc->irq) {
if (request_irq(spicc->irq, spicc_xfer_complete_isr,
IRQF_SHARED, "spicc", spicc)) {
dev_err(&pdev->dev, "request irq(%d) failed!\n",
spicc->irq);
spicc->irq = 0;
} else
disable_irq_nosync(spicc->irq);
}
spicc_log(spicc, &spicc->irq, 1, REQUEST_IRQ);
#ifdef CONFIG_MTD_SPI_NOR
spicc->dev = &pdev->dev;
child = of_get_next_available_child(np, NULL);
if (child && of_device_is_compatible(child, "jedec,spi-nor")) {
if (of_gpio_named_count(np, "cs-gpios") != 1) {
dev_err(&pdev->dev, "nor: cs-gpios error\n");
ret = -EINVAL;
goto err1;
}
spicc->nor_cs = of_get_named_gpio(np, "cs-gpios", 0);
if (!gpio_is_valid(spicc->nor_cs)) {
dev_err(&pdev->dev, "nor: invalid cs-gpio\n");
ret = -EINVAL;
goto err1;
}
ret = gpio_request(spicc->nor_cs, dev_name(&pdev->dev));
if (ret) {
dev_err(&pdev->dev, "nor: request cs-gpio failed\n");
goto err1;
}
gpio_direction_output(spicc->nor_cs, 1);
ret = of_property_read_u32(child, "frequency", &speed);
if (!ret)
spicc_set_clk(spicc, speed);
mutex_init(&spicc->nor_lock);
spicc->nor = meson_snor_init(spicc, child);
}
if (spicc->nor)
return 0;
mutex_destroy(&spicc->nor_lock);
dev_warn(&pdev->dev, "no snor on spicc bus\n");
#endif
master = spi_alloc_master(&pdev->dev, sizeof(*spicc));
if (IS_ERR_OR_NULL(master)) {
dev_err(&pdev->dev, "allocate spi master failed!\n");
@@ -1116,16 +1325,6 @@ static int spicc_probe(struct platform_device *pdev)
}
spicc = spi_master_get_devdata(master);
spicc->master = master;
dev_set_drvdata(&pdev->dev, spicc);
ret = of_spicc_get_data(spicc, pdev);
if (ret) {
dev_err(&pdev->dev, "of error=%d\n", ret);
goto err;
}
spicc_hw_init(spicc);
spicc_log_init(spicc);
spicc_log(spicc, 0, 0, PROBE_BEGIN);
master->dev.of_node = pdev->dev.of_node;
master->bus_num = spicc->device_id;
master->setup = spicc_setup;
@@ -1152,21 +1351,8 @@ static int spicc_probe(struct platform_device *pdev)
ret = -EBUSY;
goto err;
}
spin_lock_init(&spicc->lock);
INIT_LIST_HEAD(&spicc->msg_queue);
init_completion(&spicc->completion);
if (spicc->irq) {
if (request_irq(spicc->irq, spicc_xfer_complete_isr,
IRQF_SHARED, "spicc", spicc)) {
dev_err(&pdev->dev, "master %d request irq(%d) failed!\n",
master->bus_num, spicc->irq);
spicc->irq = 0;
} else
disable_irq_nosync(spicc->irq);
}
spicc_log(spicc, &spicc->irq, 1, REQUEST_IRQ);
/*setup class*/
spicc->cls.name = kzalloc(10, GFP_KERNEL);
sprintf((char *)spicc->cls.name, "spicc%d", master->bus_num);
@@ -1185,6 +1371,9 @@ static int spicc_probe(struct platform_device *pdev)
return ret;
err:
spi_master_put(master);
err1:
devm_kfree(&pdev->dev, spicc);
return ret;
}
@@ -1196,6 +1385,9 @@ static int spicc_remove(struct platform_device *pdev)
spicc_log_exit(spicc);
spi_unregister_master(spicc->master);
destroy_workqueue(spicc->wq);
#ifdef CONFIG_MTD_SPI_NOR
mutex_destroy(&spicc->nor_lock);
#endif
if (spicc->pinctrl)
devm_pinctrl_put(spicc->pinctrl);
return 0;
@@ -1254,7 +1446,7 @@ static void __exit spicc_exit(void)
platform_driver_unregister(&spicc_driver);
}
subsys_initcall(spicc_init);
module_init(spicc_init);
module_exit(spicc_exit);
MODULE_DESCRIPTION("Amlogic SPICC driver");

View File

@@ -830,6 +830,11 @@ static const struct flash_info spi_nor_ids[] = {
{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
/* GigaDevice */
{
"gd25q80c", INFO(0xc84014, 0, 64 * 1024, 16,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
"gd25q32", INFO(0xc84016, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
@@ -1009,6 +1014,8 @@ static const struct flash_info spi_nor_ids[] = {
{ "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{"FM25Q08A", INFO(0xa14014, 0x0, 64 * 1024, 16, SECT_4K) },
{ },
};