From patchwork Tue Nov 30 10:02:41 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Savinay Dharmappa X-Patchwork-Id: 366681 Received: from devils.ext.ti.com (devils.ext.ti.com [198.47.26.153]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oAUAIVM5007013 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 30 Nov 2010 10:18:52 GMT Received: from dlep35.itg.ti.com ([157.170.170.118]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id oAUAGqHh012017 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 30 Nov 2010 04:16:52 -0600 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep35.itg.ti.com (8.13.7/8.13.7) with ESMTP id oAUAGp8a024539; Tue, 30 Nov 2010 04:16:51 -0600 (CST) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 96B4980628; Tue, 30 Nov 2010 04:16:51 -0600 (CST) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp53.itg.ti.com (dflp53.itg.ti.com [128.247.5.6]) by linux.omap.com (Postfix) with ESMTP id A2E5B80626 for ; Tue, 30 Nov 2010 04:16:50 -0600 (CST) Received: from tidmzi-ftp.india.ext.ti.com (localhost [127.0.0.1]) by dflp53.itg.ti.com (8.13.8/8.13.8) with SMTP id oAUAGlKh024725; Tue, 30 Nov 2010 04:16:48 -0600 (CST) Received: from symphonyindia.ti.com (symphony-ftp [192.168.247.11]) by tidmzi-ftp.india.ext.ti.com (Postfix) with SMTP id 90F6E3887A; Tue, 30 Nov 2010 15:46:36 +0530 (IST) Received: from localhost.localdomain ([192.168.247.76]) by symphonyindia.ti.com (8.13.1/8.12.10) with ESMTP id oAUA9XQr032164; Tue, 30 Nov 2010 15:39:33 +0530 From: Savinay Dharmappa To: davinci-linux-open-source@linux.davincidsp.com Subject: [PATCH v4 2/2] davinci: Platform support for OMAP-L137/AM17x NOR flash driver Date: Tue, 30 Nov 2010 15:32:41 +0530 Message-Id: <1291111361-25848-1-git-send-email-savinay.dharmappa@ti.com> X-Mailer: git-send-email 1.5.6 Cc: Aleksey Makarov , linux-mtd@lists.infradead.org X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com X-Greylist: Sender succeeded STARTTLS authentication, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 30 Nov 2010 10:18:53 +0000 (UTC) diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 84066e8..72d4fd0 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -142,6 +142,14 @@ config DA830_UI_NAND help Say Y here to use the NAND flash. Do not forget to setup the switch correctly. + +config DA830_UI_NOR + bool "NOR flash" + help + Configure this option to specify the that AEMIF CE2/CE3 will be used to + communicate to the NOR flash. Do not forget to setup the switch SW1 + on UI card correctly. + endchoice config MACH_DAVINCI_DA850_EVM diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index b52a3a1..93daf52 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -429,6 +431,219 @@ static inline void da830_evm_init_nand(int mux_mode) static inline void da830_evm_init_nand(int mux_mode) { } #endif +#ifdef CONFIG_DA830_UI_NOR +/* + * Number of lines going to the NOR flash that are used as + * AEMIF address lines B_EMIF_BA0-B_EMIF_A12 on CS2. + */ +#define NOR_WINDOW_SIZE_LOG2 15 +#define NOR_WINDOW_SIZE (1 << NOR_WINDOW_SIZE_LOG2) + +static struct { + struct clk *clk; + void __iomem *latch_addr; + void __iomem *aemif_addr; +} da830_evm_nor; + +static struct davinci_aemif_timing da830_evm_norflash_timing = { + .wsetup = 0, + .wstrobe = 40, + .whold = 0, + .rsetup = 0, + .rstrobe = 130, + .rhold = 0, + .ta = 20, +}; + +static void da830_evm_nor_set_window(unsigned long offset, void *data) +{ + /* + * CS2 and CS3 lines are used to address NOR flash. Address lines + * A0-A14 from NOR flash are connected to AEMIF address lines + * B_EMIF_BA0-B_EMIF_A12 on CS2. Address lines A15-A23 of the NOR + * flash are latched from AEMIF address lines B_EMIF_A0-B_EMIF_A6 + * on CS3. The offset argument received by this function is the offset + * within NOR flash. Upper address is obtained by shifting the offset + * by the number of CS2 address lines used (13) and masking it with + * complement of 3 (2 address lines used to address banks) and adding + * the resultant offset value to CS3 base address. Writing to this + * address will latch the upper address lines. + */ + writeb(0x0, da830_evm_nor.latch_addr + + (~3UL & (offset >> (NOR_WINDOW_SIZE_LOG2 - 2)))); +} + +static void da830_evm_nor_done(void *data) +{ + clk_disable(da830_evm_nor.clk); + clk_put(da830_evm_nor.clk); + iounmap(da830_evm_nor.latch_addr); + release_mem_region(DA8XX_AEMIF_CS3_BASE, PAGE_SIZE); + iounmap(da830_evm_nor.aemif_addr); + release_mem_region(DA8XX_AEMIF_CTL_BASE, SZ_32K); +} + +static int da830_evm_nor_init(void *data, int cs) +{ + struct resource *res = NULL; + + /* Turn on AEMIF clocks */ + da830_evm_nor.clk = clk_get(NULL, "aemif"); + if (IS_ERR(da830_evm_nor.clk)) { + pr_err("%s: could not get AEMIF clock\n", __func__); + da830_evm_nor.clk = NULL; + return -ENODEV; + } + clk_enable(da830_evm_nor.clk); + + res = request_mem_region(DA8XX_AEMIF_CTL_BASE, SZ_32K, "AEMIF control"); + if (res == NULL) { + pr_err("%s: could not request AEMIF control region\n", + __func__); + goto err_clk; + } + + da830_evm_nor.aemif_addr = ioremap_nocache(DA8XX_AEMIF_CTL_BASE, + SZ_32K); + if (da830_evm_nor.aemif_addr == NULL) { + pr_err("%s: could not remap AEMIF control region\n", __func__); + goto err_aemif_region; + } + + /* Setup AEMIF -- timings, etc. */ + + /* Set maximum wait cycles */ + davinci_aemif_setup_timing(&da830_evm_norflash_timing, + da830_evm_nor.aemif_addr, cs); + + davinci_aemif_setup_timing(&da830_evm_norflash_timing, + da830_evm_nor.aemif_addr, cs + 1); + + /* Setup the window to access the latch */ + res = request_mem_region(DA8XX_AEMIF_CS3_BASE, PAGE_SIZE, + "DA830 UI NOR address latch"); + if (res == NULL) { + pr_err("%s: could not request address latch region\n", + __func__); + goto err_aemif_ioremap; + } + + da830_evm_nor.latch_addr = + ioremap_nocache(DA8XX_AEMIF_CS3_BASE, PAGE_SIZE); + if (da830_evm_nor.latch_addr == NULL) { + pr_err("%s: could not remap address latch region\n", __func__); + goto err_latch_region; + } + return 0; + +err_latch_region: + release_mem_region(DA8XX_AEMIF_CS3_BASE, PAGE_SIZE); + +err_aemif_ioremap: + iounmap(da830_evm_nor.aemif_addr); + +err_aemif_region: + release_mem_region(DA8XX_AEMIF_CTL_BASE, SZ_32K); + +err_clk: + clk_disable(da830_evm_nor.clk); + clk_put(da830_evm_nor.clk); + + return -ENOMEM; +} + +static struct mtd_partition da830_evm_nor_partitions[] = { + /* bootloader (U-Boot, etc) in first 2 sectors */ + [0] = { + .name = "bootloader", + .offset = 0, + .size = SZ_128K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + /* bootloader parameters in the next 1 sector */ + [1] = { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = SZ_64K, + }, + /* kernel */ + [2] = { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + }, + /* file system */ + [3] = { + .name = "filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + } +}; + +static struct latch_addr_flash_data da830_evm_nor_pdata = { + .width = 1, + .size = SZ_4M, + .init = da830_evm_nor_init, + .done = da830_evm_nor_done, + .set_window = da830_evm_nor_set_window, + .nr_parts = ARRAY_SIZE(da830_evm_nor_partitions), + .parts = da830_evm_nor_partitions, +}; + +static struct resource da830_evm_nor_resource[] = { + [0] = { + .start = DA8XX_AEMIF_CS2_BASE, + .end = DA8XX_AEMIF_CS2_BASE + NOR_WINDOW_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = DA8XX_AEMIF_CS3_BASE, + .end = DA8XX_AEMIF_CS3_BASE + PAGE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = DA8XX_AEMIF_CTL_BASE, + .end = DA8XX_AEMIF_CTL_BASE + SZ_32K - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device da830_evm_nor_device = { + .name = "latch-addr-flash", + .id = 0, + .dev = { + .platform_data = &da830_evm_nor_pdata, + }, + .num_resources = ARRAY_SIZE(da830_evm_nor_resource), + .resource = da830_evm_nor_resource, +}; + +static inline void da830_evm_init_nor(int mux_mode) +{ + int ret; + + if (HAS_MMC) { + pr_warning("WARNING: both MMC/SD and NOR are " + "enabled, but they share AEMIF pins.\n" + "\tDisable MMC/SD for NOR support.\n"); + return; + } + + ret = davinci_cfg_reg_list(da830_evm_emif25_pins); + if (ret) + pr_warning("da830_evm_init: EMIF 2.5 mux setup failed: %d\n", + ret); + + ret = platform_device_register(&da830_evm_nor_device); + if (ret) + pr_warning("da830_evm_init: NOR device not registered.\n"); + + gpio_direction_output(mux_mode, 1); +} +#else +static inline void da830_evm_init_nor(int mux_mode) { } +#endif /* CONFIG_DA830_UI_NOR */ + #ifdef CONFIG_DA830_UI_LCD static inline void da830_evm_init_lcdc(int mux_mode) { @@ -469,6 +684,8 @@ static int __init da830_evm_ui_expander_setup(struct i2c_client *client, da830_evm_init_nand(gpio + 6); + da830_evm_init_nor(gpio + 6); + return 0; }