diff --git a/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202.dts b/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202.dts index 75671d295274..5c96c4bc4dbc 100644 --- a/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202.dts +++ b/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202.dts @@ -42,6 +42,8 @@ i2c2 = &i2c2; i2c3 = &i2c3; i2c4 = &i2c_AO; + spi0 = &spicc_a; + spi1 = &spicc1; }; memory@00000000 { @@ -1856,6 +1858,72 @@ status = "disable"; }; +ðmac { + 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"; diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts index 9f27260ed76f..a89303387873 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts @@ -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>; diff --git a/arch/arm/configs/meson64_a32_defconfig b/arch/arm/configs/meson64_a32_defconfig index 12d1f13d63f7..5881014709fa 100644 --- a/arch/arm/configs/meson64_a32_defconfig +++ b/arch/arm/configs/meson64_a32_defconfig @@ -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 diff --git a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts index 30d8a299f5c2..97b8502c2cfd 100644 --- a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts +++ b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts @@ -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>; diff --git a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts index c84f3d484537..e5f588198c05 100644 --- a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts +++ b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts @@ -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>; diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index 4d13a128e170..8a6cf11686e5 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -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 diff --git a/drivers/amlogic/spicc/spicc.c b/drivers/amlogic/spicc/spicc.c index d1bf8a6360c9..26c16231ce54 100644 --- a/drivers/amlogic/spicc/spicc.c +++ b/drivers/amlogic/spicc/spicc.c @@ -35,6 +35,9 @@ #include #include #include +#ifdef CONFIG_MTD_SPI_NOR +#include +#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"); diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 21dde5249085..d0c0ff2ae4a3 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -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) }, { }, };