AM62x添加GPMC NOR FLASH應用
本文硬件平臺采用飛凌AM6254開發板,主要講解AM62x開發板將GPMC總線引出到P34引腳,添加GPMC NOR FLASH應用方法,本文使用的思路和方法僅供參考使用,其它arm開發板雖然芯片不同,但思路和方法有很多的共性,希望對您在板卡的使用中能夠有所幫助,更多ARM開發板相關資訊,關注飛凌嵌入式。
ARM平臺介紹
FET6254-C核心板基于TI Sitara? AM62x系列工業級處理器設計。其采用Arm Cortex-A53架構,主頻最高可達1.4GHz;并集成了廣泛的接口,如2路支持TSN的千兆以太網、USB 2.0、LVDS、RGB parallel、UART、OSPI、CAN-FD、Camera、Audio。
AM62x開發板將GPMC總線引出到P34引腳,添加GPMC NOR FLASH應用方法如下。
一、設備樹修改
diff --git a/arch/arm64/boot/dts/ti/OK6254-C.dts b/arch/arm64/boot/dts/ti/OK6254-C.dts
index 5d4923bff..ad5228be3 100644
--- a/arch/arm64/boot/dts/ti/OK6254-C.dts
+++ b/arch/arm64/boot/dts/ti/OK6254-C.dts
@@ -525,6 +525,32 @@
AM62X_IOPAD(0x128, PIN_OUTPUT, 7) /* (B23) CSI_PWDN.GPIO0_72 */
>;
};
+
+ gpmc0_pins_default: gpmc0-pins-default {
+ pinctrl-single,pins = <
+ AM62X_IOPAD(0x078, PIN_INPUT, 0) /* (U24) GPMC0_AD15.GPMC0_AD15 */
+ AM62X_IOPAD(0x074, PIN_INPUT, 0) /* (U25) GPMC0_AD14.GPMC0_AD14 */
+ AM62X_IOPAD(0x070, PIN_INPUT, 0) /* (T24) GPMC0_AD13.GPMC0_AD13 */
+ AM62X_IOPAD(0x06C, PIN_INPUT, 0) /* (T22) GPMC0_AD12.GPMC0_AD12 */
+ AM62X_IOPAD(0x068, PIN_INPUT, 0) /* (R21) GPMC0_AD11.GPMC0_AD11 */
+ AM62X_IOPAD(0x064, PIN_INPUT, 0) /* (T25) GPMC0_AD10.GPMC0_AD10 */
+ AM62X_IOPAD(0x060, PIN_INPUT, 0) /* (R25) GPMC0_AD9.GPMC0_AD9 */
+ AM62X_IOPAD(0x05C, PIN_INPUT, 0) /* (R24) GPMC0_AD8.GPMC0_AD8 */
+ AM62X_IOPAD(0x058, PIN_INPUT, 0) /* (R23) GPMC0_AD7.GPMC0_AD7 */
+ AM62X_IOPAD(0x054, PIN_INPUT, 0) /* (P21) GPMC0_AD6.GPMC0_AD6 */
+ AM62X_IOPAD(0x050, PIN_INPUT, 0) /* (P22) GPMC0_AD5.GPMC0_AD5 */
+ AM62X_IOPAD(0x04C, PIN_INPUT, 0) /* (P24) GPMC0_AD4.GPMC0_AD4 */
+ AM62X_IOPAD(0x048, PIN_INPUT, 0) /* (N25) GPMC0_AD3.GPMC0_AD3 */
+ AM62X_IOPAD(0x044, PIN_INPUT, 0) /* (N24) GPMC0_AD2.GPMC0_AD2 */
+ AM62X_IOPAD(0x040, PIN_INPUT, 0) /* (N23) GPMC0_AD1.GPMC0_AD1 */
+ AM62X_IOPAD(0x03C, PIN_INPUT, 0) /* (M25) GPMC0_AD0.GPMC0_AD0 */
+ AM62X_IOPAD(0x084, PIN_OUTPUT, 0) /* (L23) GPMC0_ADVn_ALE.GPMC0_ADVn_ALE */
+ AM62X_IOPAD(0x088, PIN_OUTPUT, 0) /* (L24) GPMC0_OEn_REn.GPMC0_OEn_REn */
+ AM62X_IOPAD(0x08C, PIN_OUTPUT, 0) /* (L25) GPMC0_WEn.GPMC0_WEn */
+ AM62X_IOPAD(0x098, PIN_INPUT_PULLUP, 0) /* (U23) GPMC0_WAIT0.GPMC0_WAIT0 */
+ AM62X_IOPAD(0x0A8, PIN_OUTPUT, 0) /* (M21) GPMC0_CSn0.GPMC0_CSn0 */
+ >;
+ };
};
&mcu_pmx0 {
@@ -937,3 +963,52 @@
ti,system-suspend-controller;
ti,ctx-memory-region = <&lpm_ctx_ddr>;
};
+
+&gpmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpmc0_pins_default>;
+ ranges = <0 0 0x00 0x50000000 0x02000000>;
+
+ nor@0,0 {
+ compatible = "fl,gpmc-nor";
+
+ reg = <0 0x0 0x02000000>;
+ linux,mtd-name = "cfi_probe";
+ probe-type = "CFI"; /* CFI or JEDEC */
+ //big-endian;
+
+ bank-width = <2>;
+ gpmc,mux-add-data = <2>;
+ gpmc,burst-length = <16>; //16words
+ gpmc,burst-read;
+ gpmc,burst-write;
+ gpmc,page-burst-access-ns = <0>;
+
+ gpmc,sync-clk-ps = <0>;
+ gpmc,cs-on-ns = <7>;
+ gpmc,cs-rd-off-ns = <120>;
+ gpmc,cs-wr-off-ns = <120>;
+
+ gpmc,adv-on-ns = <7>;
+ gpmc,adv-rd-off-ns = <15>;
+ gpmc,adv-wr-off-ns = <15>;
+
+ gpmc,we-on-ns = <30>;
+ gpmc,we-off-ns = <93>;
+
+ gpmc,oe-on-ns = <28>;
+ gpmc,oe-off-ns = <120>;
+
+ gpmc,access-ns = <120>;
+
+ gpmc,rd-cycle-ns = <120>;
+ gpmc,wr-cycle-ns = <120>;
+
+ gpmc,bus-turnaround-ns = <0>;
+ gpmc,cycle2cycle-delay-ns = <0>;
+ gpmc,clk-activation-ns = <0>;
+ gpmc,wr-access-ns = <112>;
+
+ gpmc,wr-data-mux-bus-ns = <52>;
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi
index e23350dce..cbc9bb54b 100644
--- a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi
@@ -981,4 +981,32 @@
reg-names = "esm";
forlinx,esm-pins = <5>;
};
+
+ gpmc0: memory-controller@3b000000 {
+ compatible = "ti,am64-gpmc";
+ power-domains = <&k3_pds 80 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&k3_clks 80 0>;
+ clock-names = "fck";
+ reg = <0x00 0x03b000000 0x00 0x400>,
+ <0x00 0x050000000 0x00 0x08000000>;
+ reg-names = "cfg", "data";
+ interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+ gpmc,num-cs = <3>;
+ gpmc,num-waitpins = <2>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ elm0: ecc@25010000 {
+ compatible = "ti,am3352-elm";
+ reg = <0x00 0x25010000 0x00 0x2000>;
+ interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&k3_pds 54 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&k3_clks 54 0>;
+ clock-names = "fck";
+ };
};
diff --git a/arch/arm64/boot/dts/ti/k3-am62.dtsi b/arch/arm64/boot/dts/ti/k3-am62.dtsi
index 71665fa1f..d1f11ffd7 100644
--- a/arch/arm64/boot/dts/ti/k3-am62.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am62.dtsi
@@ -79,6 +79,8 @@
<0x00 0x0e000000 0x00 0x0e000000 0x00 0x01d20000>, /* Second peripheral window */
<0x00 0x20000000 0x00 0x20000000 0x00 0x0a008000>, /* Third peripheral window */
<0x00 0x30200000 0x00 0x30200000 0x00 0x00010000>, /* DSS */
+ <0x00 0x3b000000 0x00 0x3b000000 0x00 0x00000400>, /* GPMC0_CFG */
+ <0x00 0x50000000 0x00 0x50000000 0x00 0x08000000>, /* GPMC0_DATA */
<0x00 0x43600000 0x00 0x43600000 0x00 0x00010000>, /* sa3 sproxy data */
<0x00 0x44043000 0x00 0x44043000 0x00 0x00000fe0>, /* TI SCI DEBUG */
<0x00 0x44860000 0x00 0x44860000 0x00 0x00040000>, /* sa3 sproxy config */
二、驅動修改及添加
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index d9bf1c2ac..874298ffb 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -165,7 +165,7 @@
#define GPMC_CONFIG1_FCLK_DIV4 (GPMC_CONFIG1_FCLK_DIV(3))
#define GPMC_CONFIG7_CSVALID (1 << 6)
-#define GPMC_CONFIG7_BASEADDRESS_MASK 0x3f
+#define GPMC_CONFIG7_BASEADDRESS_MASK 0x5f
#define GPMC_CONFIG7_CSVALID_MASK BIT(6)
#define GPMC_CONFIG7_MASKADDRESS_OFFSET 8
#define GPMC_CONFIG7_MASKADDRESS_MASK (0xf << GPMC_CONFIG7_MASKADDRESS_OFFSET)
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 96a27e064..d2137cb72 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -432,6 +432,15 @@ static void fixup_s29ns512p_sectors(struct mtd_info *mtd)
mtd->name);
}
+
+static void fixup_s29gl**s_sectors(struct mtd_info *mtd)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ cfi->cfiq->DevSize = 26;
+ cfi->cfiq->EraseRegionInfo[0] = 0x020001ff;
+}
+
/* Used to fix CFI-Tables of chips without Extended Query Tables */
static struct cfi_fixup cfi_nopri_fixup_table[] = {
{ CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */
@@ -463,6 +472,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors },
{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors },
{ CFI_MFR_AMD, 0x3f00, fixup_s29ns512p_sectors },
+ { CFI_MFR_AMD, 0x2201, fixup_s29gl**s_sectors },
{ CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */
{ CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */
{ CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */
diff --git a/drivers/mtd/gpmc_nor.c b/drivers/mtd/gpmc_nor.c
new file mode 100755
index 000000000..0e3d70e77
--- /dev/null
+++ b/drivers/mtd/gpmc_nor.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Normal mappings of chips in omap-nor memory
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/of.h>
+#include <linux/omap-gpmc.h>
+
+struct gpmc_nor_mtd {
+ struct mtd_info *mtd;
+ struct map_info *map;
+ struct resource *res;
+ const char *probe_type;
+
+ /* gpmc */
+ int gpmc_cs;
+};
+
+
+#define DRIVER_NAME "gpmc-nor"
+
+static struct mtd_partition board_nor_parts[] = {
+ [0] = {
+ .name = DRIVER_NAME,
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static const char *gpmc_nor_select_probe_type(struct platform_device *dev)
+{
+ struct device_node *dp = dev->dev.of_node;
+ const char *probe_type;
+
+ of_property_read_string(dp, "probe-type", &probe_type);
+ if (!probe_type)
+ return NULL;
+
+ if (!strcmp(probe_type, "CFI")) {
+ probe_type = "cfi_probe";
+ } else if (!strcmp(probe_type, "JEDEC")) {
+ probe_type = "jedec_probe";
+ } else if (!strcmp(probe_type, "ROM")) {
+ probe_type = "map_rom";
+ } else {
+ dev_warn(&dev->dev,
+ "obsolete_probe: don't know probe type '%s', mapping as cfi\n",
+ probe_type);
+ probe_type = "cfi_probe";
+ }
+
+ return probe_type;
+}
+
+static int gpmc_nor_parse_dt(struct platform_device *dev)
+{
+ struct gpmc_nor_mtd *gpmc_nor_mtd = platform_get_drvdata(dev);
+ struct device_node *dp = dev->dev.of_node;
+ int err;
+ u32 bankwidth;
+ u32 cs;
+ int swap = CFI_LITTLE_ENDIAN;
+
+ if (!dp)
+ return -EINVAL;
+
+ gpmc_nor_mtd->probe_type = gpmc_nor_select_probe_type(dev);
+
+ err = of_property_read_u32(dp, "reg", &cs);
+ if (err) {
+ dev_err(&dev->dev, "reg not found in DT\n");
+ return -EINVAL;
+ }
+ gpmc_nor_mtd->gpmc_cs = cs;
+
+ err = of_property_read_u32(dp, "bank-width", &bankwidth);
+ if (err) {
+ dev_err(&dev->dev, "Can't get bank width from device tree\n");
+ return err;
+ }
+
+ if (of_property_read_bool(dp, "big-endian"))
+ swap = CFI_BIG_ENDIAN;
+ else if (of_property_read_bool(dp, "little-endian"))
+ swap = CFI_LITTLE_ENDIAN;
+
+ gpmc_nor_mtd->map->name = gpmc_nor_mtd->probe_type;
+ gpmc_nor_mtd->map->bankwidth = bankwidth;
+ gpmc_nor_mtd->map->swap = swap;
+ gpmc_nor_mtd->map->device_node = dp;
+
+ /*
+ * On some platforms (e.g. MPC5200) a direct 1:1 mapping
+ * may cause problems with JFFS2 usage, as the local bus (LPB)
+ * doesn't support unaligned accesses as implemented in the
+ * JFFS2 code via memcpy(). By setting NO_XIP, the
+ * flash will not be exposed directly to the MTD users
+ * (e.g. JFFS2) any more.
+ */
+ if (of_property_read_bool(dp, "no-unaligned-direct-access"))
+ gpmc_nor_mtd->map->phys = NO_XIP;
+ else
+ gpmc_nor_mtd->map->phys = 0;
+ return 0;
+}
+
+static int gpmc_nor_remove(struct platform_device *pdev)
+{
+ struct gpmc_nor_mtd *gpmc_nor_mtd = platform_get_drvdata(pdev);
+
+ if (gpmc_nor_mtd && gpmc_nor_mtd->mtd) {
+ mtd_device_unregister(gpmc_nor_mtd->mtd);
+ map_destroy(gpmc_nor_mtd->mtd);
+ }
+
+ return 0;
+}
+
+static int gpmc_nor_probe(struct platform_device *pdev)
+{
+ struct gpmc_nor_mtd *gpmc_nor_mtd;
+ int err;
+
+ if (! pdev->dev.of_node) {
+ dev_err(&pdev->dev, "failed to find of node\n");
+ return -ENOMEM;
+ }
+
+ gpmc_nor_mtd = devm_kzalloc(&pdev->dev, sizeof(struct gpmc_nor_mtd), GFP_KERNEL);
+ if (!gpmc_nor_mtd)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, gpmc_nor_mtd);
+
+ gpmc_nor_mtd->map = devm_kzalloc(&pdev->dev, sizeof(struct map_info), GFP_KERNEL);
+ if (!gpmc_nor_mtd->map)
+ return -ENOMEM;
+
+ err = gpmc_nor_parse_dt(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to parse dt\n");
+ return -ENOMEM;
+ }
+
+ gpmc_nor_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!gpmc_nor_mtd->res) {
+ dev_err(&pdev->dev, "failed to get memory resource\n");
+ return -ENOENT;
+ }
+
+ gpmc_nor_mtd->map->phys = gpmc_nor_mtd->res->start;
+ gpmc_nor_mtd->map->size = resource_size(gpmc_nor_mtd->res);
+ gpmc_nor_mtd->map->virt = devm_ioremap_resource(&pdev->dev, gpmc_nor_mtd->res);
+ if (IS_ERR(gpmc_nor_mtd->map->virt))
+ return PTR_ERR(gpmc_nor_mtd->map->virt);
+
+ printk("gpmc map phys:%x virt:%x size:%x\n", gpmc_nor_mtd->map->phys, gpmc_nor_mtd->map->virt,
+ gpmc_nor_mtd->map->size);
+ **_map_init(gpmc_nor_mtd->map);
+
+ gpmc_cs_write_reg(0, 0x00,(2 << 23)|(0 << 22)|(0 << 21)|(0 << 18)|(1 << 12)|(2 << 8));
+ gpmc_nor_mtd->mtd = do_map_probe(gpmc_nor_mtd->probe_type, gpmc_nor_mtd->map);
+ if (!gpmc_nor_mtd->mtd) {
+ dev_err(&pdev->dev, "probing failed\n");
+ return -ENXIO;
+ }
+
+ gpmc_nor_mtd->mtd->dev.parent = &pdev->dev;
+
+ mtd_set_of_node(gpmc_nor_mtd->mtd, pdev->dev.of_node);
+
+ err = mtd_device_register(gpmc_nor_mtd->mtd, board_nor_parts, 1);
+ if (err) {
+ dev_err(&pdev->dev, "failed to add partitions\n");
+ goto err_destroy;
+ }
+
+ return 0;
+
+err_destroy:
+ gpmc_nor_remove(pdev);
+ return err;
+}
+
+static const struct of_device_id gpmc_nor_ids[] = {
+ { .compatible = "fl,gpmc-nor" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, gpmc_nor_ids);
+
+static struct platform_driver gpmc_nor_driver = {
+ .probe = gpmc_nor_probe,
+ .remove = gpmc_nor_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = gpmc_nor_ids,
+ },
+};
+
+module_platform_driver(gpmc_nor_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ZZY <zzy@forlinx>");
+MODULE_DESCRIPTION("FL gpmc NOR");
+
三、makefile添加編譯
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 593d0593a..92bc1c1b3 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -31,3 +31,4 @@ obj-y += chips/ lpddr/ maps/ devices/ nand/ tests/
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
obj-$(CONFIG_MTD_UBI) += ubi/
obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/
+obj-y += gpmc_nor.o
相關產品 >
-
FET62xx-C核心板
FET6254-C核心板基于TI Sitara? AM62x系列工業級處理器設計。采用Arm Cortex A53架構,并集成了廣泛的接口,如2路支持TSN的千兆以太網、USB 2.0CAN-FD,AM6254核心板兼容AM62x全系列處理器,提供單核、雙核、四核可選,功能引腳完全兼容,飛凌嵌入式已經適配AM6254 AM6231 AM6232三款芯片為您帶來靈活的成本組合方案,AM62x可應用于廣泛的工業環境,如人機界面(HMI)、工業計算機、邊緣計算、零售自動化、充電樁控制單元(TCU)、醫療設備等。
了解詳情 -
OK62xx-C開發板
AM62x 開發板是圍繞飛凌AM62x核心板設計的獨立測試和開發平臺。AM62x處理器由四核64位Arm -Cortex -A53微處理器 和Cortex-M4F組成。AM62x開發板整板工業級設計,并在開發過程中進行嚴苛的環境溫度測試、壓力測試、長期穩定性運行測試,使AM62x可在各種嚴苛環境穩定運行 了解詳情