AM62x添加GPMC NOR FLASH应用

原创 2022-08-17 08:48:00 AM62x am62x am6254

本文硬件平台采用飞凌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

相关产品 >

  • FET6254-C核心板

    FET6254-C核心板基于TI Sitara™ AM62x系列工业级处理器设计。采用Arm Cortex A53架构,并集成了广泛的接口,如2路支持TSN的千兆以太网、USB 2.0CAN-FD,AM6254核心板兼容AM62x全系列处理器,提供单核、双核、四核可选,功能引脚完全兼容,为您带来灵活的成本组合方案,AM62x可应用于广泛的工业环境,如人机界面(HMI)、工业计算机、边缘计算、零售自动化、充电桩控制单元(TCU)、医疗设备等。

    了解详情
    FET6254-C核心板
  • OK6254-C开发板

    AM62x 开发板是围绕飞凌AM62x核心板设计的独立测试和开发平台。AM62x处理器由四核64位Arm -Cortex -A53微处理器 和Cortex-M4F组成。AM62x开发板整板工业级设计,并在开发过程中进行严苛的环境温度测试、压力测试、长期稳定性运行测试,使AM62x可在各种严苛环境稳定运行 了解详情
    OK6254-C开发板

推荐阅读 换一批 换一批