OMAP GPMC driver conversion
Subsystems (10)
v4 cover OMAP GPMC driver conversion
Hi,
GPMC driver conversion patch series. Some peripherals has GPMC helper functions, these has been modified to cater to the needs of GPMC driver. All the boards using GPMC has been adapted to use the new GPMC driver.
GPMC HWMOD entry for OMAP2/3 has been added. On OMAP3, kernel does spit "omap_hwmod: gpmc: cannot be enabled for reset (3)", but peripherals connected via GPMC are working. Really shaky about OMAP2 GPMC HWMOD entry. Would be helpful if someone can help me in resolving warning on OMAP3 & verify whether OMAP2 entry is proper. The series adapts to HWMOD.
Drivers, NAND & OneNAND of OMAP has been modified to make use of GPMC changes & cleaned up the now unnecessary exported symbol usages.
This series has been made on top of,
5e136da Linux-omap rebuilt: Updated to -rc5,
A patch by Javier Martinez Canillas <[email protected]>,
OMAP3: igep0020: Add support for Micron NAND Flash storage memory, has also been incorporated into the series as this was necessary for igep0020 board.
This has been tested on omap3 evm (SMSC911x) & beagle board (NAND)
I would need help to get these changes tested on other boards using GPMC. Expected problematic boards are those having OMAP2xxx SoCs, apollon board. In the case of apollon, in addition to it being OMAP2xxx, it was modified to use gpmc_smc91x_init instead of directly writing to configuration registers.
Additional features that currently boards in mainline does not make use of like, waitpin interrupt handling, changes to leverage revision 6 IP differences has not been incorporated.
GPMC driver now provides NAND driver with GPMC-NAND registers so that OMAP NAND driver can handle those by itself instead of using exported symbols.
Acquiring CS for NAND has also been incorporated, it has been made as a separate patch as it is felt that this should probably go away, explained in the relevant patch.
GPMC (General Purpose Memory Controller) in brief:
GPMC is an unified memory controller dedicated to interfacing external memory devices like
Asynchronous SRAM like memories and application specific integrated circuit devices. Asynchronous, synchronous, and page mode burst NOR flash devices NAND flash Pseudo-SRAM devices
GPMC details can be referred in AM335X Technical Reference Manual @ http://www.ti.com/lit/pdf/spruh73
v4: Handle wait pin (except for interrupts), enhance configuration
& timing interface of GPMC to take care of all boards. Dynamic allocation of interrupt instead of static. Convert remaining peripherals to work with GPMC driver. Handle acquiring NAND CS#, adapt to HWMOD, update HWMOD OMAP2/3 entries, other minor commenst on v3.
v3: Single device structure passed from platform for peripherals using
multiple CS instead of using multiple device structure having a few redundant data, handle interrupts, GPMC NAND handling by GPMC NAND driver instead of GPMC driver
v2: Avoid code movement that kept similar code together (for easy review)
TODO: Cleanup
Regards
Afzal
Afzal Mohammed (38):
ARM: OMAP2+: gpmc: driver conversion
ARM: OMAP2+: gpmc: Adapt to HWMOD
ARM: OMAP2+: gpmc: register details for nand driver
ARM: OMAP2+: gpmc: Acquire NAND CS value
ARM: OMAP2+: nand: create platform data structure
ARM: OMAP2+: onenand: return value in init function
ARM: OMAP2+: gpmc-nand: Adapt to use gpmc driver
ARM: OMAP2+: gpmc-onenand: Adapt to use gpmc driver
ARM: OMAP2+: flash: Adapt to gpmc driver
ARM: OMAP2+: gpmc-smsc911x: Adapt to use gpmc driver
ARM: OMAP2+: gpmc-smc91x: Adapt to use gpmc driver
ARM: OMAP2+: gpmc-tusb6010: Adapt to gpmc driver
ARM: OMAP3: hwmod data: add gpmc
ARM: OMAP2xxx: hwmod data: add gpmc
mtd: nand: omap2: obtain memory from resource
mtd: nand: omap2: use gpmc provided irqs
mtd: nand: omap2: handle nand on gpmc
mtd: onenand: omap: obtain memory from resource
ARM: OMAP2+: board omap3evm: gpmc driver adaptation
ARM: OMAP2+: board omap3beagle: gpmc driver adaptation
ARM: OMAP2+: board apollon: gpmc driver adaptation
ARM: OMAP2+: board h4: gpmc driver adaptation
ARM: OMAP2+: board 3630sdp: gpmc driver adaptation
ARM: OMAP2+: board 3430sdp: gpmc driver adaptation
ARM: OMAP2+: board 2430sdp: gpmc driver adaptation
ARM: OMAP2+: board cm-t3517: gpmc driver adaptation
ARM: OMAP2+: board cm-t35: gpmc driver adaptation
ARM: OMAP2+: board ldp: gpmc driver adaptation
ARM: OMAP2+: board n8x0: gpmc driver adaptation
ARM: OMAP2+: board omap3logic: gpmc driver adaptation
ARM: OMAP2+: board omap3pandora: gpmc driver adaptation
ARM: OMAP2+: board omap3stalker: gpmc driver adaptation
ARM: OMAP2+: board omap4pcm049: gpmc driver adaptation
ARM: OMAP2+: board overo: gpmc driver adaptation
ARM: OMAP2+: board rm680: gpmc driver adaptation
ARM: OMAP2+: board rx51: gpmc driver adaptation
ARM: OMAP2+: board zoom-debugboard: gpmc driver adaptation
ARM: OMAP2+: board igep0020: gpmc driver adaptation
Javier Martinez Canillas (1):
OMAP3: igep0020: Add support for Micron NAND Flash storage memory
arch/arm/mach-omap2/board-2430sdp.c | 44 +- arch/arm/mach-omap2/board-3430sdp.c | 18 +- arch/arm/mach-omap2/board-3630sdp.c | 23 +- arch/arm/mach-omap2/board-apollon.c | 152 +-- arch/arm/mach-omap2/board-cm-t35.c | 21 +- arch/arm/mach-omap2/board-cm-t3517.c | 10 +- arch/arm/mach-omap2/board-devkit8000.c | 6 +- arch/arm/mach-omap2/board-flash.c | 160 ++-- arch/arm/mach-omap2/board-flash.h | 36 +- arch/arm/mach-omap2/board-h4.c | 130 +-- arch/arm/mach-omap2/board-igep0020.c | 99 +- arch/arm/mach-omap2/board-ldp.c | 26 +- arch/arm/mach-omap2/board-n8x0.c | 18 +- arch/arm/mach-omap2/board-omap3beagle.c | 22 +- arch/arm/mach-omap2/board-omap3evm.c | 14 +- arch/arm/mach-omap2/board-omap3logic.c | 13 +- arch/arm/mach-omap2/board-omap3pandora.c | 11 +- arch/arm/mach-omap2/board-omap3stalker.c | 13 +- arch/arm/mach-omap2/board-omap3touchbook.c | 6 +- arch/arm/mach-omap2/board-omap4pcm049.c | 13 +- arch/arm/mach-omap2/board-overo.c | 32 +- arch/arm/mach-omap2/board-rm680.c | 10 +- arch/arm/mach-omap2/board-rx51-peripherals.c | 17 +- arch/arm/mach-omap2/board-zoom-debugboard.c | 47 +- arch/arm/mach-omap2/board-zoom.c | 5 +- arch/arm/mach-omap2/common-board-devices.c | 46 - arch/arm/mach-omap2/common-board-devices.h | 1 - arch/arm/mach-omap2/gpmc-nand.c | 84 +- arch/arm/mach-omap2/gpmc-onenand.c | 111 +-- arch/arm/mach-omap2/gpmc-smc91x.c | 87 +- arch/arm/mach-omap2/gpmc-smsc911x.c | 59 +- arch/arm/mach-omap2/gpmc.c | 980 +++++++++++++++++--- arch/arm/mach-omap2/omap_hwmod_2420_data.c | 18 + arch/arm/mach-omap2/omap_hwmod_2430_data.c | 18 + arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 41 + arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 52 ++ arch/arm/mach-omap2/omap_hwmod_common_data.h | 1 + arch/arm/mach-omap2/prcm-common.h | 2 + arch/arm/mach-omap2/usb-tusb6010.c | 177 ++-- arch/arm/plat-omap/include/plat/gpmc-smc91x.h | 10 +- arch/arm/plat-omap/include/plat/gpmc-smsc911x.h | 9 +- arch/arm/plat-omap/include/plat/gpmc.h | 110 ++- arch/arm/plat-omap/include/plat/nand.h | 10 +- arch/arm/plat-omap/include/plat/onenand.h | 7 +- drivers/mtd/nand/omap2.c | 296 ++++-- drivers/mtd/onenand/omap2.c | 29 +- include/linux/usb/musb.h | 4 +- 47 files changed, 2110 insertions(+), 988 deletions(-)
Signature · 1 line
1.7.10
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Convert GPMC code to driver. Boards using GPMC should provide driver with type of configuration, timing, CS. Platform devices would then be created for each connected peripheral (details also to be passed by board so that it reaches respective driver). And GPMC driver would populate memory resource details for the connected peripheral driver. Boards should inform gpmc driver with platform data destined for peripheral driver. gpmc driver will provide the same information to peripheral driver.
A peripheral connected to GPMC can have multiple address spaces using different chip select. Hence GPMC driver has been provided capability to create platform device for peripheral using mutiple CS. The peripheral that made it necessary was tusb6010.
Interrupts of GPMC are presented to drivers of connected peripherals as resource. A fictitious interrupt controller chip handles these interrupts at GPMC hardware level. Clients can use normal interrupt APIs. Platform information of peripheral passed to GPMC driver should indicate interrupts to be used via flags.
Driver is capable of configuring waitpin, waitpin details has to be provided per CS. Wait pin has been considered as exclusive resource as multiple peripherals should not using the same pin, at the same it is valid for mutiple CS to use same waitpin provided they are a part of single peripheral (eg. tusb6010)
An exported symbol for reconfiguring GPMC settings has been provided. OneNAND is the one that neccessitated this.
Acquiring CS# for NAND is done on a few boards. It means, depending on bootloader to embed this information. Probably CS# being used can be set in the Kernel, and acquiring it can be removed. If ever this capbility is needed, GPMC driver has to be made aware of handling it.
Modifications has been made keeping in mind that the driver would have to move to driver folder. This explains requirement of clk_prd field; even though clk_prd variable is not necessary as gpmc_get_fclk_period is present in the same file as of now, this will help in moving the driver easily to drivers folder.
Code related to GPMC clock may have to continue live in platform folders as input clock is beyond the control of GPMC and calculating timing for the peripheral may need other helpers. This explains presence of 'gpmc_cs_calc_divider' along with 'gpmc_calc_divider', both doing same work, latter meant to go with driver, former for calculation in platform code.
Thanks to Vaibhav Hiremath & Jonathan Hunter on their various good suggestions which resulted in improving the code.
--- arch/arm/mach-omap2/gpmc.c | 877 ++++++++++++++++++++++++++++---- arch/arm/plat-omap/include/plat/gpmc.h | 93 +++- 2 files changed, 872 insertions(+), 98 deletions(-)
arch/arm/mach-omap2/gpmc.c +783 -94
@@ -14,8 +14,11 @@*/ #undef DEBUG +#include <linux/platform_device.h> +#include <linux/irq.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> #include <linux/clk.h>
@@ -53,6 +56,45 @@#define GPMC_CS0_OFFSET 0x60#define GPMC_CS_SIZE 0x30 +/* GPMC register bits */ +#define GPMC_CONFIG1_TIMEPARAGRANULARITY BIT(4) +#define GPMC_CONFIG1_DEVICETYPE_NAND GPMC_CONFIG1_DEVICETYPE(0x2) +#define GPMC_CONFIG1_WAIT_PIN_SEL_MASK GPMC_CONFIG1_WAIT_PIN_SEL(0x3) +#define GPMC_CONFIG1_WAIT_MON_TIME (val) ((val & 0x3) << 18) +#define GPMC_CONFIG1_WRITEMULTIPLE BIT(28) +#define GPMC_CONFIG1_READMULTIPLE BIT(30) +#define GPMC_CONFIG1_WRAPBURST BIT(31) +#define GPMC_CONFIG_WAITPIN_POLARITY_SHIFT 0x8 +#define GPMC_CONFIG1_WAITPIN_MONITOR_TIME (val) ((val & 0x3) << 18) +#define GPMC_CONFIG1_WAITPIN_MONITOR_TIME_1 \ + GPMC_CONFIG1_WAITPIN_MONITOR_TIME(0x1) +#define GPMC_CONFIG1_WAITPIN_MONITOR_TIME_2 \ + GPMC_CONFIG1_WAITPIN_MONITOR_TIME(0x2) +#define GPMC_CONFIG1_CLOCKACTIVATION_TIME (val) ((val & 0x3) << 25) +#define GPMC_CONFIG1_CLOCKACTIVATION_TIME_1 \ + GPMC_CONFIG1_CLOCKACTIVATION_TIME(0x1) +#define GPMC_CONFIG1_CLOCKACTIVATION_TIME_2 \ + GPMC_CONFIG1_CLOCKACTIVATION_TIME(0x2) + +#define GPMC_CONFIG2_CSEXTRADELAY BIT(7) + +#define GPMC_CONFIG3_ADVEXTRADELAY BIT(7) + +#define GPMC_CONFIG4_OEEXTRADELAY BIT(7) +#define GPMC_CONFIG4_WEEXTRADELAY BIT(23) + +#define GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN BIT(6) +#define GPMC_CONFIG6_CYCLE2CYCLESAMECSEN BIT(7) + +#define GPMC_IRQ_BIT_FIFOEVENT BIT(0) +#define GPMC_IRQ_BIT_TERMINALCOUNT BIT(1) + +#define GPMC_WAITPIN_IDX0 0x0 +#define GPMC_WAITPIN_IDX1 0x1 +#define GPMC_WAITPIN_IDX2 0x2 +#define GPMC_WAITPIN_IDX3 0x3 +#define GPMC_NR_WAITPIN 0x4 +#define GPMC_MEM_START 0x00000000#define GPMC_MEM_END 0x3FFFFFFF#define BOOT_ROM_SPACE 0x100000/* 1MB */
@@ -64,6 +106,55 @@#define ENABLE_PREFETCH (0x1 << 7)#define DMA_MPU_MODE 2 +#define DRIVER_NAME "omap-gpmc" + +#define GPMC_NR_IRQ 2 + +#define HIGH 1 +#define LOW -1 + +struct gpmc_device { +char *name; +int id; +void *pdata; +unsigned pdata_size; +struct resource *per_res; +unsigned per_res_cnt; +struct resource *gpmc_res; +unsigned gpmc_res_cnt; +bool have_waitpin; +unsigned waitpin; +int waitpin_polarity; +}; + +struct gpmc_irq { +unsigned irq; +u32 bitmask; +}; + +struct gpmc { +struct device *dev; +unsigned long clk_prd; +void __iomem *io_base; +unsigned long phys_base; +u32 memsize; +unsigned cs_map; +int ecc_used; +spinlock_t mem_lock; +struct resource mem_root; +struct resource cs_mem[GPMC_CS_NUM ]; +/* XXX: Or allocate dynamically ? */ +struct gpmc_device device[GPMC_CS_NUM ]; +unsigned num_device; +unsigned master_irq; +unsigned irq_start; +struct gpmc_irq irq[GPMC_NR_IRQ ]; +struct irq_chip irq_chip; +bool wp; +unsigned waitpin_map; +unsigned revision; +}; +/* Structure to save gpmc cs context */ struct gpmc_cs_config {u32 config1;
@@ -91,58 +182,50 @@ struct omap3_gpmc_regs {struct gpmc_cs_config cs_context[GPMC_CS_NUM ]; }; -static struct resource gpmc_mem_root; -static struct resource gpmc_cs_mem[GPMC_CS_NUM ]; -static DEFINE_SPINLOCK (gpmc_mem_lock); -static unsigned int gpmc_cs_map;/* flag for cs which are initialized */ -static int gpmc_ecc_used = -EINVAL ;/* cs using ecc engine */ - -static void __iomem *gpmc_base; -static struct clk *gpmc_l3_clk; -static irqreturn_t gpmc_handle_irq (int irq,void *dev); +static struct gpmc *gpmc;static void gpmc_write_reg (int idx,u32 val) { -__raw_writel (val, gpmc_base + idx); +writel (val, gpmc->io_base + idx); }static u32 gpmc_read_reg (int idx) { -return __raw_readl (gpmc_base + idx); +return readl (gpmc->io_base + idx); }static void gpmc_cs_write_byte (int cs,int idx,u8 val) {void __iomem *reg_addr; - reg_addr = gpmc_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; -__raw_writeb (val, reg_addr); + reg_addr = gpmc->io_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; +writeb (val, reg_addr); }static u8 gpmc_cs_read_byte (int cs,int idx) {void __iomem *reg_addr; - reg_addr = gpmc_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; -return __raw_readb (reg_addr); + reg_addr = gpmc->io_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; +return readb (reg_addr); }void gpmc_cs_write_reg (int cs,int idx,u32 val) {void __iomem *reg_addr; - reg_addr = gpmc_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; -__raw_writel (val, reg_addr); + reg_addr = gpmc->io_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; +writel (val, reg_addr); }u32 gpmc_cs_read_reg (int cs,int idx) {void __iomem *reg_addr; - reg_addr = gpmc_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; -return __raw_readl (reg_addr); + reg_addr = gpmc->io_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; +return readl (reg_addr); }/* TODO: Add support for gpmc_fck to clock framework and use it */
@@ -207,7 +290,8 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,if (time ==0 ) ticks =0 ;else - ticks =gpmc_ns_to_ticks (time); + ticks = (time *1000 + gpmc->clk_prd -1 ) / gpmc->clk_prd; + nr_bits = end_bit - st_bit +1 ;if (ticks >=1 << nr_bits) {#ifdef DEBUG
@@ -222,7 +306,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,#ifdef DEBUG printk (KERN_INFO "GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n" , - cs, name, ticks,gpmc_get_fclk_period () * ticks /1000 , + cs, name, ticks, gpmc->clk_prd * ticks /1000 , (l >> st_bit) & mask, time);#endif l &= ~(mask << st_bit);
@@ -243,6 +327,21 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, return -1#endif +int gpmc_calc_divider (unsigned int sync_clk) +{ +int div; +u32 l; + + l = sync_clk + (gpmc->clk_prd -1 ); + div = l / gpmc->clk_prd; +if (div >4 ) +return -1 ; +if (div <=0 ) + div =1 ; + +return div; +} +int gpmc_cs_calc_divider (int cs,unsigned int sync_clk) {int div;
@@ -258,12 +357,53 @@ int gpmc_cs_calc_divider(int cs, unsigned int sync_clk)return div; } +static void gpmc_cs_onoff_timings (int cs,const struct gpmc_onoff_timings *p) +{ +u32 l; + + l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG2 ); +if (p->cs_extra_delay) + l |=GPMC_CONFIG2_CSEXTRADELAY ; +else + l &= ~GPMC_CONFIG2_CSEXTRADELAY ; +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG2 , l); + + l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG3 ); +if (p->adv_extra_delay) + l |=GPMC_CONFIG3_ADVEXTRADELAY ; +else + l &= ~GPMC_CONFIG3_ADVEXTRADELAY ; +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG3 , l); + + l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG4 ); +if (p->oe_extra_delay) + l |=GPMC_CONFIG4_OEEXTRADELAY ; +else + l &= ~GPMC_CONFIG4_OEEXTRADELAY ; +if (p->we_extra_delay) + l |=GPMC_CONFIG4_WEEXTRADELAY ; +else + l &= ~GPMC_CONFIG4_WEEXTRADELAY ; +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG4 , l); + + l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG6 ); +if (p->cycle2cyclesamecsen) + l |=GPMC_CONFIG6_CYCLE2CYCLESAMECSEN ; +else + l &= ~GPMC_CONFIG6_CYCLE2CYCLESAMECSEN ; +if (p->cycle2cyclediffcsen) + l |=GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN ; +else + l &= ~GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN ; +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG6 , l); +} +int gpmc_cs_set_timings (int cs,const struct gpmc_timings *t) {int div;u32 l; - div =gpmc_cs_calc_divider (cs, t->sync_clk); + div =gpmc_calc_divider (t->sync_clk);if (div <0 )return -1 ;
@@ -286,7 +426,10 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)GPMC_SET_ONE (GPMC_CS_CONFIG5 ,24 ,27 , page_burst_access); -if (cpu_is_omap34xx ()) { +GPMC_SET_ONE (GPMC_CS_CONFIG6 ,8 ,11 , cycle2cycle_delay); +GPMC_SET_ONE (GPMC_CS_CONFIG6 ,0 ,3 , busturnaround); + +if (gpmc->revision >=5 ) {GPMC_SET_ONE (GPMC_CS_CONFIG6 ,16 ,19 , wr_data_mux_bus);GPMC_SET_ONE (GPMC_CS_CONFIG6 ,24 ,28 , wr_access); }
@@ -298,13 +441,15 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)if (l & (GPMC_CONFIG1_READTYPE_SYNC |GPMC_CONFIG1_WRITETYPE_SYNC )) {#ifdef DEBUG printk (KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n" , - cs, (div *gpmc_get_fclk_period ()) /1000 , div); + cs, (div * gpmc->clk_prd) /1000 , div);#endif l &= ~0x03 ; l |= (div -1 );gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , l); } +gpmc_cs_onoff_timings (cs, &t->control); +return 0 ; }
@@ -332,7 +477,7 @@ static void gpmc_cs_disable_mem(int cs)gpmc_cs_write_reg (cs,GPMC_CS_CONFIG7 , l); } -static void gpmc_cs_get_memconf (int cs,u32 *base,u32 *size) +static __devinit void gpmc_cs_get_memconf (int cs,u32 *base,u32 *size) {u32 l;u32 mask;
@@ -351,23 +496,23 @@ static int gpmc_cs_mem_enabled(int cs)return l &GPMC_CONFIG7_CSVALID ; } -int gpmc_cs_set_reserved (int cs,int reserved) +static int gpmc_cs_set_reserved (int cs,int reserved) {if (cs >GPMC_CS_NUM )return -ENODEV ; - gpmc_cs_map &= ~(1 << cs); - gpmc_cs_map |= (reserved ?1 :0 ) << cs; + gpmc->cs_map &= ~(1 << cs); + gpmc->cs_map |= (reserved ?1 :0 ) << cs;return 0 ; } -int gpmc_cs_reserved (int cs) +static int gpmc_cs_reserved (int cs) {if (cs >GPMC_CS_NUM )return -ENODEV ; -return gpmc_cs_map & (1 << cs); +return gpmc->cs_map & (1 << cs); }static unsigned long gpmc_mem_align (unsigned long size)
@@ -384,24 +529,25 @@ static unsigned long gpmc_mem_align(unsigned long size)return size; } -static int gpmc_cs_insert_mem (int cs,unsigned long base,unsigned long size) +static __devinit +int gpmc_cs_insert_mem (int cs,unsigned long base,unsigned long size) { -struct resource *res = &gpmc_cs_mem[cs]; +struct resource *res = &gpmc->cs_mem[cs];int r; size =gpmc_mem_align (size); -spin_lock (&gpmc_mem_lock); +spin_lock (&gpmc->mem_lock); res->start = base; res->end = base + size -1 ; - r =request_resource (&gpmc_mem_root, res); -spin_unlock (&gpmc_mem_lock); + r =request_resource (&gpmc->mem_root, res); +spin_unlock (&gpmc->mem_lock);return r; }int gpmc_cs_request (int cs,unsigned long size,unsigned long *base) { -struct resource *res = &gpmc_cs_mem[cs]; +struct resource *res = &gpmc->cs_mem[cs];int r =-1 ;if (cs >GPMC_CS_NUM )
@@ -411,7 +557,7 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)if (size > (1 <<GPMC_SECTION_SHIFT ))return -ENOMEM ; -spin_lock (&gpmc_mem_lock); +spin_lock (&gpmc->mem_lock);if (gpmc_cs_reserved (cs)) { r = -EBUSY ; goto out;
@@ -419,7 +565,7 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)if (gpmc_cs_mem_enabled (cs)) r =adjust_resource (res, res->start & ~(size -1 ), size);if (r <0 ) - r =allocate_resource (&gpmc_mem_root, res, size,0 , ~0 , + r =allocate_resource (&gpmc->mem_root, res, size,0 , ~0 , size,NULL ,NULL );if (r <0 ) goto out;
@@ -428,24 +574,24 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) *base = res->start;gpmc_cs_set_reserved (cs,1 ); out: -spin_unlock (&gpmc_mem_lock); +spin_unlock (&gpmc->mem_lock);return r; }EXPORT_SYMBOL (gpmc_cs_request);void gpmc_cs_free (int cs) { -spin_lock (&gpmc_mem_lock); +spin_lock (&gpmc->mem_lock);if (cs >=GPMC_CS_NUM || cs <0 || !gpmc_cs_reserved (cs)) {printk (KERN_ERR "Trying to free non-reserved GPMC CS%d\n" , cs);BUG (); -spin_unlock (&gpmc_mem_lock); +spin_unlock (&gpmc->mem_lock);return ; }gpmc_cs_disable_mem (cs); -release_resource (&gpmc_cs_mem[cs]); +release_resource (&gpmc->cs_mem[cs]);gpmc_cs_set_reserved (cs,0 ); -spin_unlock (&gpmc_mem_lock); +spin_unlock (&gpmc->mem_lock); }EXPORT_SYMBOL (gpmc_cs_free);
@@ -668,7 +814,7 @@ int gpmc_prefetch_reset(int cs) }EXPORT_SYMBOL (gpmc_prefetch_reset); -static void __init gpmc_mem_init (void ) +static __devinit void gpmc_mem_init (void ) {int cs;unsigned long boot_rom_space =0 ;
@@ -680,8 +826,8 @@ static void __init gpmc_mem_init(void)/* In apollon the CS0 is mapped as 0x0000 0000 */ if (machine_is_omap_apollon ()) boot_rom_space =0 ; - gpmc_mem_root.start =GPMC_MEM_START + boot_rom_space; - gpmc_mem_root.end =GPMC_MEM_END ; + gpmc->mem_root.start =GPMC_MEM_START + boot_rom_space; + gpmc->mem_root.end =GPMC_MEM_END ;/* Reserve all regions that has been set up by bootloader */ for (cs =0 ; cs <GPMC_CS_NUM ; cs++) {
@@ -697,26 +843,15 @@ static void __init gpmc_mem_init(void)static int __init gpmc_init (void ) { -u32 l, irq; -int cs, ret = -EINVAL ; -int gpmc_irq; +int ret = -EINVAL ;char *ck =NULL ;if (cpu_is_omap24xx ()) { ck ="core_l3_ck" ; -if (cpu_is_omap2420 ()) - l =OMAP2420_GPMC_BASE ; -else - l =OMAP34XX_GPMC_BASE ; - gpmc_irq =INT_34XX_GPMC_IRQ ; }else if (cpu_is_omap34xx ()) { ck ="gpmc_fck" ; - l =OMAP34XX_GPMC_BASE ; - gpmc_irq =INT_34XX_GPMC_IRQ ; }else if (cpu_is_omap44xx ()) { ck ="gpmc_ck" ; - l =OMAP44XX_GPMC_BASE ; - gpmc_irq =OMAP44XX_IRQ_GPMC ; }if (WARN_ON (!ck))
@@ -728,53 +863,607 @@ static int __init gpmc_init(void)BUG (); } - gpmc_base =ioremap (l,SZ_4K ); -if (!gpmc_base) { -clk_put (gpmc_l3_clk); -printk (KERN_ERR "Could not get GPMC register memory\n" ); -BUG (); +clk_enable (gpmc_l3_clk); + +return 0 ; +} +postcore_initcall (gpmc_init); + +static inline int gpmc_waitpin_is_reserved (struct gpmc *gpmc,unsigned waitpin) +{ +return gpmc->waitpin_map & (0x1 << waitpin); +} + +static inline void gpmc_reserve_waitpin (struct gpmc *gpmc,unsigned waitpin) +{ + gpmc->waitpin_map &= ~(0x1 << waitpin); + gpmc->waitpin_map |= (0x1 << waitpin); +} + +static int gpmc_waitpin_request (struct gpmc *gpmc,unsigned waitpin) +{ +if (!(waitpin <GPMC_NR_WAITPIN )) +return -ENODEV ; + +if (gpmc_waitpin_is_reserved (gpmc, waitpin)) +return -EBUSY ; +else +gpmc_reserve_waitpin (gpmc, waitpin); + +return 0 ; +} + +static int gpmc_setup_waitpin (struct gpmc *gpmc,struct gpmc_device *gd) +{ +int ret; + +if (!gd->have_waitpin) +return 0 ; + + ret =gpmc_waitpin_request (gpmc, gd->waitpin); +if (IS_ERR_VALUE (ret)) { +dev_err (gpmc->dev,"waitpin %u reserved\n" , gd->waitpin); +return ret; + }else if (gd->waitpin_polarity) { +u32 l =gpmc_read_reg (GPMC_CONFIG ); +u32 shift = gd->waitpin +GPMC_CONFIG_WAITPIN_POLARITY_SHIFT ; + +if (gd->waitpin_polarity ==HIGH ) + l |=1 << shift; +else + l &= ~(1 << shift); + +gpmc_write_reg (GPMC_CONFIG , l); } +return 0 ; +} -clk_enable (gpmc_l3_clk); +static int gpmc_setup_cs_waitpin (struct gpmc *gpmc,struct gpmc_device *gd, +unsigned cs,unsigned conf) +{ +u32 l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG1 ); +unsigned idx = ~0x0 ; +int polarity =0 ; - l =gpmc_read_reg (GPMC_REVISION ); -printk (KERN_INFO "GPMC revision %d.%d\n" , (l >>4 ) &0x0f , l &0x0f ); -/* Set smart idle mode and automatic L3 clock gating */ - l =gpmc_read_reg (GPMC_SYSCONFIG ); - l &=0x03 <<3 ; - l |= (0x02 <<3 ) | (1 <<0 ); -gpmc_write_reg (GPMC_SYSCONFIG , l); -gpmc_mem_init (); +switch (conf &GPMC_WAITPIN_MASK ) { +case GPMC_WAITPIN_0 : + idx =GPMC_WAITPIN_IDX0 ; +break ; +case GPMC_WAITPIN_1 : + idx =GPMC_WAITPIN_IDX1 ; +break ; +case GPMC_WAITPIN_2 : + idx =GPMC_WAITPIN_IDX2 ; +break ; +case GPMC_WAITPIN_3 : + idx =GPMC_WAITPIN_IDX3 ; +break ; +/* no waitpin */ +case 0 : +break ; +default : +dev_err (gpmc->dev,"multiple waitpins selected on CS:%u\n" , cs); +return -EINVAL ; +break ; + } -/* initalize the irq_chained */ - irq =OMAP_GPMC_IRQ_BASE ; -for (cs =0 ; cs <GPMC_CS_NUM ; cs++) { -irq_set_chip_and_handler (irq, &dummy_irq_chip, - handle_simple_irq); -set_irq_flags (irq,IRQF_VALID ); - irq++; +switch (conf &GPMC_WAITPIN_POLARITY_MASK ) { +case GPMC_WAITPIN_ACTIVE_LOW : + polarity =LOW ; +break ; +case GPMC_WAITPIN_ACTIVE_HIGH : + polarity =HIGH ; +break ; +/* no waitpin */ +case 0 : +break ; +default : +dev_err (gpmc->dev,"waitpin polarity set to low & high\n" ); +return -EINVAL ; +break ; } - ret =request_irq (gpmc_irq, gpmc_handle_irq,IRQF_SHARED ,"gpmc" ,NULL ); -if (ret) -pr_err ("gpmc: irq-%d could not claim: err %d\n" , - gpmc_irq, ret); -return ret; +if (idx != ~0x0 ) { +if (gd->have_waitpin) { +if (gd->waitpin != idx || + gd->waitpin_polarity != polarity) { +dev_err (gpmc->dev,"error: conflict: waitpin %u with polarity %d on device %s.%d\n" , + gd->waitpin, gd->waitpin_polarity, + gd->name, gd->id); +return -EBUSY ; + } + }else { + gd->have_waitpin = true; + gd->waitpin = idx; + gd->waitpin_polarity = polarity; + } + + l &= ~GPMC_CONFIG1_WAIT_PIN_SEL_MASK ; + l |=GPMC_CONFIG1_WAIT_PIN_SEL (idx); +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , l); + }else if (polarity) { +dev_err (gpmc->dev,"error: waitpin polarity specified with out wait pin number on device %s.%d\n" , + gd->name, gd->id); +return -EINVAL ; + } + +return 0 ; +} + +static void gpmc_setup_cs_config (struct gpmc *gpmc,unsigned cs,unsigned conf) +{ +u32 l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG1 ); + + l &= ~(GPMC_CONFIG1_TIMEPARAGRANULARITY | +GPMC_CONFIG1_MUXADDDATA | +GPMC_CONFIG1_DEVICETYPE (~0 ) | +GPMC_CONFIG1_DEVICESIZE (~0 ) | +GPMC_CONFIG1_WAIT_WRITE_MON | +GPMC_CONFIG1_WAIT_READ_MON | +GPMC_CONFIG1_PAGE_LEN (~0 ) | +GPMC_CONFIG1_WRITETYPE_SYNC | +GPMC_CONFIG1_WRITEMULTIPLE | +GPMC_CONFIG1_READTYPE_SYNC | +GPMC_CONFIG1_READMULTIPLE | +GPMC_CONFIG1_WRAPBURST | +GPMC_CONFIG1_WAITPIN_MONITOR_TIME (~0 ) | +GPMC_CONFIG1_CLOCKACTIVATION_TIME (~0 )); + +if (conf &GPMC_TIMEPARAGRANULARITY ) + l |=GPMC_CONFIG1_TIMEPARAGRANULARITY ; +if (conf &GPMC_MUXADDDATA ) + l |=GPMC_CONFIG1_MUXADDDATA ; +if (conf &GPMC_DEVICETYPE_NAND ) + l |=GPMC_CONFIG1_DEVICETYPE_NAND ; +if (conf &GPMC_DEVICESIZE_16 ) + l |=GPMC_CONFIG1_DEVICESIZE_16 ; +if (conf &GPMC_WAIT_WRITE_MON ) + l |=GPMC_CONFIG1_WAIT_WRITE_MON ; +if (conf &GPMC_WAIT_READ_MON ) + l |=GPMC_CONFIG1_WAIT_READ_MON ; +if (conf &GPMC_PAGE_LEN_16 ) + l |=GPMC_CONFIG1_PAGE_LEN_16 ; +else if (conf &GPMC_PAGE_LEN_8 ) + l |=GPMC_CONFIG1_PAGE_LEN_8 ; +if (conf &GPMC_WRITETYPE_SYNC ) + l |=GPMC_CONFIG1_WRITETYPE_SYNC ; +if (conf &GPMC_WRITEMULTIPLE ) + l |=GPMC_CONFIG1_WRITEMULTIPLE ; +if (conf &GPMC_READTYPE_SYNC ) + l |=GPMC_CONFIG1_READTYPE_SYNC ; +if (conf &GPMC_READMULTIPLE ) + l |=GPMC_CONFIG1_READMULTIPLE ; +if (conf &GPMC_WRAPBURST ) + l |=GPMC_CONFIG1_WRAPBURST ; +if (conf &GPMC_WAITPIN_MONITOR_TIME_1 ) + l |=GPMC_CONFIG1_WAITPIN_MONITOR_TIME_1 ; +else if (conf &GPMC_WAITPIN_MONITOR_TIME_2 ) + l |=GPMC_CONFIG1_WAITPIN_MONITOR_TIME_2 ; +if (conf &GPMC_CLOCKACTIVATION_TIME_1 ) + l |=GPMC_CONFIG1_CLOCKACTIVATION_TIME_1 ; +else if (conf &GPMC_CLOCKACTIVATION_TIME_2 ) + l |=GPMC_CONFIG1_CLOCKACTIVATION_TIME_2 ; + +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , l); + +if (conf &GPMC_WRITEPROTECT ) + gpmc->wp = true; +} + +static int gpmc_setup_cs_nonres (struct gpmc *gpmc, +struct gpmc_device *gd,struct gpmc_cs_data *cs) +{ +int ret; + +/* some boards rely on bootloader for configuration */ +if (cs->have_config) { +gpmc_setup_cs_config (gpmc, cs->cs, cs->config); + ret =gpmc_setup_cs_waitpin (gpmc, gd, cs->cs, cs->config); +if (IS_ERR_VALUE (ret)) { +dev_err (gpmc->dev,"error: waitpin on CS %d\n" , cs->cs); +return ret; + } + }else +dev_warn (gpmc->dev,"config not present for CS: %d\n" , cs->cs); + +if (cs->timing) { + ret =gpmc_cs_set_timings (cs->cs, cs->timing); +if (IS_ERR_VALUE (ret)) { +dev_err (gpmc->dev,"error: timing on CS: %d\n" , cs->cs); +return ret; + } + }else +dev_warn (gpmc->dev,"timing not present for CS: %u\n" , cs->cs); + +return 0 ; +} + +static int gpmc_match_device (struct gpmc *gpmc,char *name,int id) +{ +int i; +struct gpmc_device *gd; + +for (i =0 , gd = gpmc->device; i < gpmc->num_device; i++, gd++) +if (!strcmp (gd->name, name) && gd->id == id) +return i; + +return -ENOENT ; +} + +int gpmc_cs_reconfigure (char *name,int id,struct gpmc_cs_data *cs) +{ +int i; + + i =gpmc_match_device (gpmc, name, id); +if (IS_ERR_VALUE (i)) { +dev_err (gpmc->dev,"no device %s.%d to configure\n" , name, id); +return i; + } + + i =gpmc_setup_cs_nonres (gpmc, gpmc->device + i, cs); +if (IS_ERR_VALUE (i)) { +dev_err (gpmc->dev,"error: configure device %s.%d\n" , name, id); +return i; + } + +return gpmc_setup_waitpin (gpmc, gpmc->device + i); + +} +EXPORT_SYMBOL_GPL (gpmc_cs_reconfigure); + +static inline unsigned int gpmc_bit_to_irq (unsigned bitmask) +{ +if (bitmask &GPMC_IRQ_BIT_FIFOEVENT ) +return GPMC_IRQ_FIFOEVENTENABLE ; +else if (bitmask &GPMC_IRQ_BIT_TERMINALCOUNT ) +return GPMC_IRQ_COUNT_EVENT ; +else +return 0 ; +} + +static __devinit int gpmc_setup_cs_irq (struct gpmc *gpmc, +struct gpmc_cs_data *cs,struct resource *res) +{ +int i, n; + +for (i =0 , n =0 ; i <GPMC_NR_IRQ ; i++) +if (gpmc_bit_to_irq (gpmc->irq[i].bitmask) & cs->irq_config) { + res[n].start = res[n].end = gpmc->irq[i].irq; + res[n].flags =IORESOURCE_IRQ ; +dev_info (gpmc->dev,"irq %u on CS %d\n" , + res[n].start, cs->cs); + n++; + } + +return n; +} + +static __devinit int gpmc_setup_cs_mem (struct gpmc *gpmc, +struct gpmc_cs_data *cs,struct resource *res) +{ +unsigned long start; +int ret; + + ret =gpmc_cs_request (cs->cs, cs->mem_size, &start); +if (IS_ERR_VALUE (ret)) { +dev_err (gpmc->dev,"error: gpmc request on CS: %d\n" , cs->cs); +return ret; + } + + res->start = start + cs->mem_offset; + res->end = res->start + cs->mem_size -1 ; + res->flags =IORESOURCE_MEM ; + +dev_info (gpmc->dev,"memory 0x%x-0x%x on CS %d\n" , res->start, + res->end, cs->cs); + +return 1 ; +} + +static __devinit int gpmc_setup_cs (struct gpmc *gpmc,struct gpmc_device *gd, +struct gpmc_cs_data *cs,struct resource *res) +{ +int num, ret; + + num =gpmc_setup_cs_mem (gpmc, cs, res); +if (IS_ERR_VALUE (num)) +return num; + + ret =gpmc_setup_cs_nonres (gpmc, gd, cs); +if (IS_ERR_VALUE (ret)) +return ret; + + num +=gpmc_setup_cs_irq (gpmc, cs, res + num); + +return num; +} + +static __devinit int gpmc_setup_device (struct gpmc *gpmc, +struct gpmc_device *gd,struct gpmc_device_pdata *gdp) +{ +int i, n, ret; +struct gpmc_cs_data *cs; + +for (i =0 , n = gdp->num_cs, cs = gdp->cs_data; + i < gdp->num_cs; i++, cs++) + n +=hweight32 (cs->irq_config); + + gd->gpmc_res =devm_kzalloc (gpmc->dev,sizeof (*gd->gpmc_res) * n, +GFP_KERNEL ); +if (gd->gpmc_res ==NULL ) { +dev_err (gpmc->dev,"error: memory allocation\n" ); +return -ENOMEM ; + } + +for (i =0 , cs = gdp->cs_data, gd->gpmc_res_cnt =0 ; + i < gdp->num_cs; cs++, i++) { + ret =gpmc_setup_cs (gpmc, gd, cs, + gd->gpmc_res + gd->gpmc_res_cnt); +if (IS_ERR_VALUE (ret) || +IS_ERR_VALUE (gpmc_setup_waitpin (gpmc, gd))) { +dev_err (gpmc->dev,"error: setup for %s\n" , gdp->name); +devm_kfree (gpmc->dev, gd->gpmc_res); + gd->gpmc_res =NULL ; + gd->gpmc_res_cnt =0 ; +return -EINVAL ; + }else + gd->gpmc_res_cnt += ret; + } + + gd->name = gdp->name; + gd->id = gdp->id; + gd->pdata = gdp->pdata; + gd->pdata_size = gdp->pdata_size; + gd->per_res = gdp->per_res; + gd->per_res_cnt = gdp->per_res_cnt; + +return 0 ; +} + +static __devinit +struct platform_device *gpmc_create_device (struct gpmc *gpmc, +struct gpmc_device *p) +{ +int num = p->per_res_cnt + p->gpmc_res_cnt; +struct resource *res; +struct platform_device *pdev; + + res =devm_kzalloc (gpmc->dev,sizeof (struct resource ) * num, +GFP_KERNEL ); +if (!res) { +dev_err (gpmc->dev,"error: allocating memory\n" ); +return NULL ; + } + +memcpy ((char *)res, (const char *) p->gpmc_res, +sizeof (struct resource ) * p->gpmc_res_cnt); +memcpy ((char *)(res + p->gpmc_res_cnt), (const char *)p->per_res, +sizeof (struct resource ) * p->per_res_cnt); + + pdev =platform_device_register_resndata (gpmc->dev, p->name, p->id, + res, num, p->pdata, p->pdata_size); + +devm_kfree (gpmc->dev, res); + +return pdev; } -postcore_initcall (gpmc_init);static irqreturn_t gpmc_handle_irq (int irq,void *dev) { -u8 cs; +int i; +u32 regval; +struct gpmc *gpmc = dev; + + regval =gpmc_read_reg (GPMC_IRQSTATUS ); -/* check cs to invoke the irq */ - cs = ((gpmc_read_reg (GPMC_PREFETCH_CONFIG1 )) >>CS_NUM_SHIFT ) &0x7 ; -if (OMAP_GPMC_IRQ_BASE +cs <=OMAP_GPMC_IRQ_END ) -generic_handle_irq (OMAP_GPMC_IRQ_BASE +cs); +for (i =0 ; i <GPMC_NR_IRQ ; i++) +if (regval & gpmc->irq[i].bitmask) +generic_handle_irq (gpmc->irq[i].irq); + +gpmc_write_reg (GPMC_IRQSTATUS , regval);return IRQ_HANDLED ; } +static int gpmc_irq_endis (struct gpmc *gpmc,unsigned irq,bool endis) +{ +int i; +u32 regval; + +for (i =0 ; i <GPMC_NR_IRQ ; i++) +if (irq == gpmc->irq[i].irq) { + regval =gpmc_read_reg (GPMC_IRQENABLE ); +if (endis) + regval |= gpmc->irq[i].bitmask; +else + regval &= ~gpmc->irq[i].bitmask; +gpmc_write_reg (GPMC_IRQENABLE , regval); +break ; + } + +return 0 ; +} + +static void gpmc_irq_disable (struct irq_data *p) +{ +gpmc_irq_endis (irq_data_get_irq_chip_data (p), p->irq, false); +} + +static void gpmc_irq_enable (struct irq_data *p) +{ +gpmc_irq_endis (irq_data_get_irq_chip_data (p), p->irq, true); +} + +static void gpmc_irq_noop (struct irq_data *data) { } + +static unsigned int gpmc_irq_noop_ret (struct irq_data *data) {return 0 ; } + +static __devinit int gpmc_setup_irq (struct gpmc *gpmc) +{ +int i; +u32 regval; + +if (!gpmc->master_irq) +return -EINVAL ; + + gpmc->irq_start =irq_alloc_descs (-1 ,0 ,GPMC_NR_IRQ ,0 ); +if (IS_ERR_VALUE (gpmc->irq_start)) { +dev_err (gpmc->dev,"irq_alloc_descs failed\n" ); +return gpmc->irq_start; + } + + gpmc->irq_chip.name ="gpmc" ; + gpmc->irq_chip.irq_startup = gpmc_irq_noop_ret; + gpmc->irq_chip.irq_enable = gpmc_irq_enable; + gpmc->irq_chip.irq_disable = gpmc_irq_disable; + gpmc->irq_chip.irq_shutdown = gpmc_irq_noop; + gpmc->irq_chip.irq_ack = gpmc_irq_noop; + gpmc->irq_chip.irq_mask = gpmc_irq_noop; + gpmc->irq_chip.irq_unmask = gpmc_irq_noop; + + gpmc->irq[0 ].bitmask =GPMC_IRQ_BIT_FIFOEVENT ; + gpmc->irq[1 ].bitmask =GPMC_IRQ_BIT_TERMINALCOUNT ; + +for (i =0 ; i <GPMC_NR_IRQ ; i++) { + gpmc->irq[i].irq = gpmc->irq_start + i; +irq_set_chip_and_handler (gpmc->irq[i].irq, + &gpmc->irq_chip, handle_simple_irq); +irq_set_chip_data (gpmc->irq[i].irq, gpmc); +set_irq_flags (gpmc->irq[i].irq,IRQF_VALID |IRQF_NOAUTOEN ); + } + +/* Disable interrupts */ +gpmc_write_reg (GPMC_IRQENABLE ,0 ); + +/* clear interrupts */ + regval =gpmc_read_reg (GPMC_IRQSTATUS ); +gpmc_write_reg (GPMC_IRQSTATUS , regval); + +return request_irq (gpmc->master_irq, gpmc_handle_irq,IRQF_SHARED , +"gpmc" , gpmc); +} + +static __devinit void gpmc_setup_writeprotect (struct gpmc *gpmc) +{ +u32 l; + + l =gpmc_read_reg (GPMC_CONFIG ); +if (gpmc->wp == true) { + l &= ~GPMC_CONFIG_WRITEPROTECT ; +dev_info (gpmc->dev,"write protect enabled\n" ); + }else + l |=GPMC_CONFIG_WRITEPROTECT ; +gpmc_write_reg (GPMC_CONFIG , l); +} + +static __devinit int gpmc_probe (struct platform_device *pdev) +{ +u32 l; +int i; +int ret =0 ; +struct resource *res =NULL ; +struct gpmc_pdata *gp =dev_get_platdata (&pdev->dev); +struct gpmc_device_pdata **gdq =NULL ; +struct gpmc_device *gd =NULL ; + + gpmc =devm_kzalloc (&pdev->dev,sizeof (struct gpmc ),GFP_KERNEL ); +if (gpmc ==NULL ) +return -ENOMEM ; + + gpmc->dev = &pdev->dev; + gpmc->clk_prd = gp->clk_prd; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (res ==NULL ) +return -ENOENT ; + + gpmc->phys_base = res->start; + gpmc->memsize =resource_size (res); + + gpmc->io_base =devm_request_and_ioremap (gpmc->dev, res); +if (!gpmc->io_base) +return -EADDRNOTAVAIL ; + + res =platform_get_resource (pdev,IORESOURCE_IRQ ,0 ); +if (res ==NULL ) +dev_warn (gpmc->dev,"Failed to get resource: irq\n" ); +else + gpmc->master_irq = res->start; + +if (IS_ERR_VALUE (gpmc_setup_irq (gpmc))) +dev_warn (gpmc->dev,"gpmc_setup_irq failed\n" ); + + gpmc->ecc_used = -EINVAL ; +spin_lock_init (&gpmc->mem_lock); +platform_set_drvdata (pdev, gpmc); + + l =gpmc_read_reg (GPMC_REVISION ); + gpmc->revision = (l >>4 ) &0xf ; +dev_info (gpmc->dev,"GPMC revision %u.%u\n" , gpmc->revision, l &0x0f ); + +gpmc_mem_init (); + +for (i =0 , gdq = gp->device_pdata, gd = gpmc->device; + (i < gp->num_device) && (*gdq); i++, gdq++) { + ret =gpmc_setup_device (gpmc, gd, *gdq); +if (IS_ERR_VALUE (ret)) +dev_err (gpmc->dev,"gpmc setup on %s failed\n" , + (*gdq)->name); +else + gd++; + } + gpmc->num_device = gd - gpmc->device; + +gpmc_setup_writeprotect (gpmc); + +for (i =0 , gd = gpmc->device; i < gpmc->num_device; i++, gd++) +if (IS_ERR (gpmc_create_device (gpmc, gd))) +dev_err (gpmc->dev,"device creation on %s failed\n" , + gd->name); + +return 0 ; +} + +static __devexit int gpmc_free_irq(struct gpmc *gpmc) +{ +int i; + +if (gpmc->master_irq) +free_irq (gpmc->master_irq, gpmc); + +for (i =0 ; i <GPMC_NR_IRQ ; i++) { +irq_set_handler (gpmc->irq[i].irq,NULL ); +irq_set_chip (gpmc->irq[i].irq, &no_irq_chip); +irq_set_chip_data (gpmc->irq[i].irq,NULL ); +irq_modify_status (gpmc->irq[i].irq,0 ,0 ); + } + +irq_free_descs (gpmc->irq_start,GPMC_NR_IRQ ); + +return 0 ; +} + +static __devexit int gpmc_remove(struct platform_device *pdev) +{ +struct gpmc *gpmc =platform_get_drvdata (pdev); + +platform_set_drvdata (pdev,NULL ); +gpmc_free_irq (gpmc); + +return 0 ; +} + +static struct platform_driver gpmc_driver = { + .probe = gpmc_probe, + .remove =__devexit_p (gpmc_remove), + .driver = { + .name =DRIVER_NAME , + .owner =THIS_MODULE , + }, +}; + +module_platform_driver (gpmc_driver); +#ifdef CONFIG_ARCH_OMAP3 static struct omap3_gpmc_regs gpmc_context;
@@ -854,10 +1543,10 @@ int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size)unsigned int val;/* check if ecc module is in used */ -if (gpmc_ecc_used != -EINVAL ) +if (gpmc->ecc_used != -EINVAL )return -EINVAL ; - gpmc_ecc_used = cs; + gpmc->ecc_used = cs;/* clear ecc and enable bits */ val = ((0x00000001 <<8 ) |0x00000001 );
@@ -905,7 +1594,7 @@ int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code) {unsigned int val =0x0 ; -if (gpmc_ecc_used != cs) +if (gpmc->ecc_used != cs)return -EINVAL ;/* read ecc result */
@@ -915,7 +1604,7 @@ int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */ *ecc_code++ = ((val >>8 ) &0x0f ) | ((val >>20 ) &0xf0 ); - gpmc_ecc_used = -EINVAL ; + gpmc->ecc_used = -EINVAL ;return 0 ; }EXPORT_SYMBOL_GPL (gpmc_calculate_ecc);
arch/arm/plat-omap/include/plat/gpmc.h +89 -4
135 lines not on this page · raw message
Signature · 1 line
1.7.10
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Afzal,
Looks good! Some minor comments ...
Quoted 106 lines · Afzal Mohammed
Convert GPMC code to driver. Boards using GPMC should provide driver with type of configuration, timing, CS. Platform devices would then be created for each connected peripheral (details also to be passed by board so that it reaches respective driver). And GPMC driver would populate memory resource details for the connected peripheral driver. Boards should inform gpmc driver with platform data destined for peripheral driver. gpmc driver will provide the same information to peripheral driver.
A peripheral connected to GPMC can have multiple address spaces using different chip select. Hence GPMC driver has been provided capability to create platform device for peripheral using mutiple CS. The peripheral that made it necessary was tusb6010.
Interrupts of GPMC are presented to drivers of connected peripherals as resource. A fictitious interrupt controller chip handles these interrupts at GPMC hardware level. Clients can use normal interrupt APIs. Platform information of peripheral passed to GPMC driver should indicate interrupts to be used via flags.
Driver is capable of configuring waitpin, waitpin details has to be provided per CS. Wait pin has been considered as exclusive resource as multiple peripherals should not using the same pin, at the same it is valid for mutiple CS to use same waitpin provided they are a part of single peripheral (eg. tusb6010)
An exported symbol for reconfiguring GPMC settings has been provided. OneNAND is the one that neccessitated this.
Acquiring CS# for NAND is done on a few boards. It means, depending on bootloader to embed this information. Probably CS# being used can be set in the Kernel, and acquiring it can be removed. If ever this capbility is needed, GPMC driver has to be made aware of handling it.
Modifications has been made keeping in mind that the driver would have to move to driver folder. This explains requirement of
clk_prdfield; even thoughclk_prdvariable is not necessary asgpmc_get_fclk_periodis present in the same file as of now, this will help in moving the driver easily to drivers folder.Code related to GPMC clock may have to continue live in platform folders as input clock is beyond the control of GPMC and calculating timing for the peripheral may need other helpers. This explains presence of '
gpmc_cs_calc_divider' along with 'gpmc_calc_divider', both doing same work, latter meant to go with driver, former for calculation in platform code.Thanks to Vaibhav Hiremath & Jonathan Hunter on their various good suggestions which resulted in improving the code.
Cc Vaibhav Hiremath <[email protected]>Cc Jon Hunter <[email protected]>Signed-off-by Afzal Mohammed <[email protected]>--- arch/arm/mach-omap2/gpmc.c | 877 ++++++++++++++++++++++++++++---- arch/arm/plat-omap/include/plat/gpmc.h | 93 +++- 2 files changed, 872 insertions(+), 98 deletions(-)arch/arm/mach-omap2/gpmc.c +31
-0@@ -14,8 +14,11 @@*/ #undef DEBUG +#include <linux/platform_device.h> +#include <linux/irq.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> #include <linux/clk.h> @@ -53,6 +56,45 @@#define GPMC_CS0_OFFSET 0x60#define GPMC_CS_SIZE 0x30 +/* GPMC register bits */ +#define GPMC_CONFIG1_TIMEPARAGRANULARITY BIT(4) +#define GPMC_CONFIG1_DEVICETYPE_NAND GPMC_CONFIG1_DEVICETYPE(0x2) +#define GPMC_CONFIG1_WAIT_PIN_SEL_MASK GPMC_CONFIG1_WAIT_PIN_SEL(0x3) +#define GPMC_CONFIG1_WAIT_MON_TIME (val) ((val & 0x3) << 18) +#define GPMC_CONFIG1_WRITEMULTIPLE BIT(28) +#define GPMC_CONFIG1_READMULTIPLE BIT(30) +#define GPMC_CONFIG1_WRAPBURST BIT(31) +#define GPMC_CONFIG_WAITPIN_POLARITY_SHIFT 0x8 +#define GPMC_CONFIG1_WAITPIN_MONITOR_TIME (val) ((val & 0x3) << 18) +#define GPMC_CONFIG1_WAITPIN_MONITOR_TIME_1 \ + GPMC_CONFIG1_WAITPIN_MONITOR_TIME(0x1) +#define GPMC_CONFIG1_WAITPIN_MONITOR_TIME_2 \ + GPMC_CONFIG1_WAITPIN_MONITOR_TIME(0x2) +#define GPMC_CONFIG1_CLOCKACTIVATION_TIME (val) ((val & 0x3) << 25) +#define GPMC_CONFIG1_CLOCKACTIVATION_TIME_1 \ + GPMC_CONFIG1_CLOCKACTIVATION_TIME(0x1) +#define GPMC_CONFIG1_CLOCKACTIVATION_TIME_2 \ + GPMC_CONFIG1_CLOCKACTIVATION_TIME(0x2) + +#define GPMC_CONFIG2_CSEXTRADELAY BIT(7) + +#define GPMC_CONFIG3_ADVEXTRADELAY BIT(7) + +#define GPMC_CONFIG4_OEEXTRADELAY BIT(7) +#define GPMC_CONFIG4_WEEXTRADELAY BIT(23) + +#define GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN BIT(6)
arch/arm/mach-omap2/gpmc.c line 96
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10
-0+#define GPMC_CONFIG6_CYCLE2CYCLESAMECSEN BIT(7) + +#define GPMC_IRQ_BIT_FIFOEVENT BIT(0) +#define GPMC_IRQ_BIT_TERMINALCOUNT BIT(1) + +#define GPMC_WAITPIN_IDX0 0x0 +#define GPMC_WAITPIN_IDX1 0x1 +#define GPMC_WAITPIN_IDX2 0x2 +#define GPMC_WAITPIN_IDX3 0x3 +#define GPMC_NR_WAITPIN 0x4
How about an enum here? Also OMAP4 only have 3 wait pins and so the number is device dependent.
arch/arm/mach-omap2/gpmc.c line 111
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +3
-0#define GPMC_MEM_START 0x00000000#define GPMC_MEM_END 0x3FFFFFFF#define BOOT_ROM_SPACE 0x100000/* 1MB */ @@ -64,6 +106,55 @@#define ENABLE_PREFETCH (0x1 << 7)#define DMA_MPU_MODE 2 +#define DRIVER_NAME "omap-gpmc" + +#define GPMC_NR_IRQ 2
Why has this been changed to 2? It was 6 in the previous version. As we discussed before the number of IRQs should be detected based upon GPMC IP version.
Quoted 6 lines
arch/arm/mach-omap2/gpmc.c +6
-0+ +#define HIGH 1 +#define LOW -1 + +struct gpmc_device { +char *name;
arch/arm/mach-omap2/gpmc.c line 127
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10
-0+int id; +void *pdata; +unsigned pdata_size; +struct resource *per_res; +unsigned per_res_cnt; +struct resource *gpmc_res; +unsigned gpmc_res_cnt; +bool have_waitpin; +unsigned waitpin; +int waitpin_polarity;
I think that it make more sense to have the wait-pin information part of the gpmc_cs_data structure for the following reasons ...
1. If a device can use multiple CS, then it could use multiple wait signals.
2. Eventually, all board information needs to move to device tree. By having it in the pdata it will be easier to migrate to device tree.
It may be nice to have "have_waitpin" be an integer too, that indicates if wait is used for both read and write or just one or the other.
Also, any reason why waitpin_polarity is an int? I see you define LOW as -1, but I not sure why LOW cannot be 0 as 0 is programmed into the register for an active low wait signal.
Quoted 528 lines
arch/arm/mach-omap2/gpmc.c +230
-84+}; + +struct gpmc_irq { +unsigned irq; +u32 bitmask; +}; + +struct gpmc { +struct device *dev; +unsigned long clk_prd; +void __iomem *io_base; +unsigned long phys_base; +u32 memsize; +unsigned cs_map; +int ecc_used; +spinlock_t mem_lock; +struct resource mem_root; +struct resource cs_mem[GPMC_CS_NUM ]; +/* XXX: Or allocate dynamically ? */ +struct gpmc_device device[GPMC_CS_NUM ]; +unsigned num_device; +unsigned master_irq; +unsigned irq_start; +struct gpmc_irq irq[GPMC_NR_IRQ ]; +struct irq_chip irq_chip; +bool wp; +unsigned waitpin_map; +unsigned revision; +}; +/* Structure to save gpmc cs context */ struct gpmc_cs_config {u32 config1;@@ -91,58 +182,50 @@ struct omap3_gpmc_regs {struct gpmc_cs_config cs_context[GPMC_CS_NUM ]; }; -static struct resource gpmc_mem_root; -static struct resource gpmc_cs_mem[GPMC_CS_NUM ]; -static DEFINE_SPINLOCK (gpmc_mem_lock); -static unsigned int gpmc_cs_map;/* flag for cs which are initialized */ -static int gpmc_ecc_used = -EINVAL ;/* cs using ecc engine */ - -static void __iomem *gpmc_base; -static struct clk *gpmc_l3_clk; -static irqreturn_t gpmc_handle_irq (int irq,void *dev); +static struct gpmc *gpmc;static void gpmc_write_reg (int idx,u32 val) { -__raw_writel (val, gpmc_base + idx); +writel (val, gpmc->io_base + idx); }static u32 gpmc_read_reg (int idx) { -return __raw_readl (gpmc_base + idx); +return readl (gpmc->io_base + idx); }static void gpmc_cs_write_byte (int cs,int idx,u8 val) {void __iomem *reg_addr; - reg_addr = gpmc_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; -__raw_writeb (val, reg_addr); + reg_addr = gpmc->io_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; +writeb (val, reg_addr); }static u8 gpmc_cs_read_byte (int cs,int idx) {void __iomem *reg_addr; - reg_addr = gpmc_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; -return __raw_readb (reg_addr); + reg_addr = gpmc->io_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; +return readb (reg_addr); }void gpmc_cs_write_reg (int cs,int idx,u32 val) {void __iomem *reg_addr; - reg_addr = gpmc_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; -__raw_writel (val, reg_addr); + reg_addr = gpmc->io_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; +writel (val, reg_addr); }u32 gpmc_cs_read_reg (int cs,int idx) {void __iomem *reg_addr; - reg_addr = gpmc_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; -return __raw_readl (reg_addr); + reg_addr = gpmc->io_base +GPMC_CS0_OFFSET + (cs *GPMC_CS_SIZE ) + idx; +return readl (reg_addr); }/* TODO: Add support for gpmc_fck to clock framework and use it */ @@ -207,7 +290,8 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,if (time ==0 ) ticks =0 ;else - ticks =gpmc_ns_to_ticks (time); + ticks = (time *1000 + gpmc->clk_prd -1 ) / gpmc->clk_prd; + nr_bits = end_bit - st_bit +1 ;if (ticks >=1 << nr_bits) {#ifdef DEBUG @@ -222,7 +306,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,#ifdef DEBUG printk (KERN_INFO "GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n" , - cs, name, ticks,gpmc_get_fclk_period () * ticks /1000 , + cs, name, ticks, gpmc->clk_prd * ticks /1000 , (l >> st_bit) & mask, time);#endif l &= ~(mask << st_bit);@@ -243,6 +327,21 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, return -1#endif +int gpmc_calc_divider (unsigned int sync_clk) +{ +int div; +u32 l; + + l = sync_clk + (gpmc->clk_prd -1 ); + div = l / gpmc->clk_prd; +if (div >4 ) +return -1 ; +if (div <=0 ) + div =1 ; + +return div; +} +int gpmc_cs_calc_divider (int cs,unsigned int sync_clk) {int div;@@ -258,12 +357,53 @@ int gpmc_cs_calc_divider(int cs, unsigned int sync_clk)return div; } +static void gpmc_cs_onoff_timings (int cs,const struct gpmc_onoff_timings *p) +{ +u32 l; + + l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG2 ); +if (p->cs_extra_delay) + l |=GPMC_CONFIG2_CSEXTRADELAY ; +else + l &= ~GPMC_CONFIG2_CSEXTRADELAY ; +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG2 , l); + + l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG3 ); +if (p->adv_extra_delay) + l |=GPMC_CONFIG3_ADVEXTRADELAY ; +else + l &= ~GPMC_CONFIG3_ADVEXTRADELAY ; +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG3 , l); + + l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG4 ); +if (p->oe_extra_delay) + l |=GPMC_CONFIG4_OEEXTRADELAY ; +else + l &= ~GPMC_CONFIG4_OEEXTRADELAY ; +if (p->we_extra_delay) + l |=GPMC_CONFIG4_WEEXTRADELAY ; +else + l &= ~GPMC_CONFIG4_WEEXTRADELAY ; +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG4 , l); + + l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG6 ); +if (p->cycle2cyclesamecsen) + l |=GPMC_CONFIG6_CYCLE2CYCLESAMECSEN ; +else + l &= ~GPMC_CONFIG6_CYCLE2CYCLESAMECSEN ; +if (p->cycle2cyclediffcsen) + l |=GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN ; +else + l &= ~GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN ; +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG6 , l); +} +int gpmc_cs_set_timings (int cs,const struct gpmc_timings *t) {int div;u32 l; - div =gpmc_cs_calc_divider (cs, t->sync_clk); + div =gpmc_calc_divider (t->sync_clk);if (div <0 )return -1 ;@@ -286,7 +426,10 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)GPMC_SET_ONE (GPMC_CS_CONFIG5 ,24 ,27 , page_burst_access); -if (cpu_is_omap34xx ()) { +GPMC_SET_ONE (GPMC_CS_CONFIG6 ,8 ,11 , cycle2cycle_delay); +GPMC_SET_ONE (GPMC_CS_CONFIG6 ,0 ,3 , busturnaround); + +if (gpmc->revision >=5 ) {GPMC_SET_ONE (GPMC_CS_CONFIG6 ,16 ,19 , wr_data_mux_bus);GPMC_SET_ONE (GPMC_CS_CONFIG6 ,24 ,28 , wr_access); }@@ -298,13 +441,15 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)if (l & (GPMC_CONFIG1_READTYPE_SYNC |GPMC_CONFIG1_WRITETYPE_SYNC )) {#ifdef DEBUG printk (KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n" , - cs, (div *gpmc_get_fclk_period ()) /1000 , div); + cs, (div * gpmc->clk_prd) /1000 , div);#endif l &= ~0x03 ; l |= (div -1 );gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , l); } +gpmc_cs_onoff_timings (cs, &t->control); +return 0 ; }@@ -332,7 +477,7 @@ static void gpmc_cs_disable_mem(int cs)gpmc_cs_write_reg (cs,GPMC_CS_CONFIG7 , l); } -static void gpmc_cs_get_memconf (int cs,u32 *base,u32 *size) +static __devinit void gpmc_cs_get_memconf (int cs,u32 *base,u32 *size) {u32 l;u32 mask;@@ -351,23 +496,23 @@ static int gpmc_cs_mem_enabled(int cs)return l &GPMC_CONFIG7_CSVALID ; } -int gpmc_cs_set_reserved (int cs,int reserved) +static int gpmc_cs_set_reserved (int cs,int reserved) {if (cs >GPMC_CS_NUM )return -ENODEV ; - gpmc_cs_map &= ~(1 << cs); - gpmc_cs_map |= (reserved ?1 :0 ) << cs; + gpmc->cs_map &= ~(1 << cs); + gpmc->cs_map |= (reserved ?1 :0 ) << cs;return 0 ; } -int gpmc_cs_reserved (int cs) +static int gpmc_cs_reserved (int cs) {if (cs >GPMC_CS_NUM )return -ENODEV ; -return gpmc_cs_map & (1 << cs); +return gpmc->cs_map & (1 << cs); }static unsigned long gpmc_mem_align (unsigned long size)@@ -384,24 +529,25 @@ static unsigned long gpmc_mem_align(unsigned long size)return size; } -static int gpmc_cs_insert_mem (int cs,unsigned long base,unsigned long size) +static __devinit +int gpmc_cs_insert_mem (int cs,unsigned long base,unsigned long size) { -struct resource *res = &gpmc_cs_mem[cs]; +struct resource *res = &gpmc->cs_mem[cs];int r; size =gpmc_mem_align (size); -spin_lock (&gpmc_mem_lock); +spin_lock (&gpmc->mem_lock); res->start = base; res->end = base + size -1 ; - r =request_resource (&gpmc_mem_root, res); -spin_unlock (&gpmc_mem_lock); + r =request_resource (&gpmc->mem_root, res); +spin_unlock (&gpmc->mem_lock);return r; }int gpmc_cs_request (int cs,unsigned long size,unsigned long *base) { -struct resource *res = &gpmc_cs_mem[cs]; +struct resource *res = &gpmc->cs_mem[cs];int r =-1 ;if (cs >GPMC_CS_NUM )@@ -411,7 +557,7 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)if (size > (1 <<GPMC_SECTION_SHIFT ))return -ENOMEM ; -spin_lock (&gpmc_mem_lock); +spin_lock (&gpmc->mem_lock);if (gpmc_cs_reserved (cs)) { r = -EBUSY ; goto out;@@ -419,7 +565,7 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)if (gpmc_cs_mem_enabled (cs)) r =adjust_resource (res, res->start & ~(size -1 ), size);if (r <0 ) - r =allocate_resource (&gpmc_mem_root, res, size,0 , ~0 , + r =allocate_resource (&gpmc->mem_root, res, size,0 , ~0 , size,NULL ,NULL );if (r <0 ) goto out;@@ -428,24 +574,24 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) *base = res->start;gpmc_cs_set_reserved (cs,1 ); out: -spin_unlock (&gpmc_mem_lock); +spin_unlock (&gpmc->mem_lock);return r; }EXPORT_SYMBOL (gpmc_cs_request);void gpmc_cs_free (int cs) { -spin_lock (&gpmc_mem_lock); +spin_lock (&gpmc->mem_lock);if (cs >=GPMC_CS_NUM || cs <0 || !gpmc_cs_reserved (cs)) {printk (KERN_ERR "Trying to free non-reserved GPMC CS%d\n" , cs);BUG (); -spin_unlock (&gpmc_mem_lock); +spin_unlock (&gpmc->mem_lock);return ; }gpmc_cs_disable_mem (cs); -release_resource (&gpmc_cs_mem[cs]); +release_resource (&gpmc->cs_mem[cs]);gpmc_cs_set_reserved (cs,0 ); -spin_unlock (&gpmc_mem_lock); +spin_unlock (&gpmc->mem_lock); }EXPORT_SYMBOL (gpmc_cs_free);@@ -668,7 +814,7 @@ int gpmc_prefetch_reset(int cs) }EXPORT_SYMBOL (gpmc_prefetch_reset); -static void __init gpmc_mem_init (void ) +static __devinit void gpmc_mem_init (void ) {int cs;unsigned long boot_rom_space =0 ;@@ -680,8 +826,8 @@ static void __init gpmc_mem_init(void)/* In apollon the CS0 is mapped as 0x0000 0000 */ if (machine_is_omap_apollon ()) boot_rom_space =0 ; - gpmc_mem_root.start =GPMC_MEM_START + boot_rom_space; - gpmc_mem_root.end =GPMC_MEM_END ; + gpmc->mem_root.start =GPMC_MEM_START + boot_rom_space; + gpmc->mem_root.end =GPMC_MEM_END ;/* Reserve all regions that has been set up by bootloader */ for (cs =0 ; cs <GPMC_CS_NUM ; cs++) {@@ -697,26 +843,15 @@ static void __init gpmc_mem_init(void)static int __init gpmc_init (void ) { -u32 l, irq; -int cs, ret = -EINVAL ; -int gpmc_irq; +int ret = -EINVAL ;char *ck =NULL ;if (cpu_is_omap24xx ()) { ck ="core_l3_ck" ; -if (cpu_is_omap2420 ()) - l =OMAP2420_GPMC_BASE ; -else - l =OMAP34XX_GPMC_BASE ; - gpmc_irq =INT_34XX_GPMC_IRQ ; }else if (cpu_is_omap34xx ()) { ck ="gpmc_fck" ; - l =OMAP34XX_GPMC_BASE ; - gpmc_irq =INT_34XX_GPMC_IRQ ; }else if (cpu_is_omap44xx ()) { ck ="gpmc_ck" ; - l =OMAP44XX_GPMC_BASE ; - gpmc_irq =OMAP44XX_IRQ_GPMC ; }if (WARN_ON (!ck))@@ -728,53 +863,607 @@ static int __init gpmc_init(void)BUG (); } - gpmc_base =ioremap (l,SZ_4K ); -if (!gpmc_base) { -clk_put (gpmc_l3_clk); -printk (KERN_ERR "Could not get GPMC register memory\n" ); -BUG (); +clk_enable (gpmc_l3_clk); + +return 0 ; +} +postcore_initcall (gpmc_init); + +static inline int gpmc_waitpin_is_reserved (struct gpmc *gpmc,unsigned waitpin) +{ +return gpmc->waitpin_map & (0x1 << waitpin); +} + +static inline void gpmc_reserve_waitpin (struct gpmc *gpmc,unsigned waitpin) +{ + gpmc->waitpin_map &= ~(0x1 << waitpin); + gpmc->waitpin_map |= (0x1 << waitpin); +} + +static int gpmc_waitpin_request (struct gpmc *gpmc,unsigned waitpin) +{ +if (!(waitpin <GPMC_NR_WAITPIN )) +return -ENODEV ; + +if (gpmc_waitpin_is_reserved (gpmc, waitpin)) +return -EBUSY ; +else +gpmc_reserve_waitpin (gpmc, waitpin); + +return 0 ; +} + +static int gpmc_setup_waitpin (struct gpmc *gpmc,struct gpmc_device *gd) +{ +int ret; + +if (!gd->have_waitpin) +return 0 ; + + ret =gpmc_waitpin_request (gpmc, gd->waitpin); +if (IS_ERR_VALUE (ret)) { +dev_err (gpmc->dev,"waitpin %u reserved\n" , gd->waitpin); +return ret; + }else if (gd->waitpin_polarity) { +u32 l =gpmc_read_reg (GPMC_CONFIG ); +u32 shift = gd->waitpin +GPMC_CONFIG_WAITPIN_POLARITY_SHIFT ; + +if (gd->waitpin_polarity ==HIGH ) + l |=1 << shift; +else + l &= ~(1 << shift); + +gpmc_write_reg (GPMC_CONFIG , l); } +return 0 ; +} -clk_enable (gpmc_l3_clk); +static int gpmc_setup_cs_waitpin (struct gpmc *gpmc,struct gpmc_device *gd, +unsigned cs,unsigned conf) +{ +u32 l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG1 ); +unsigned idx = ~0x0 ; +int polarity =0 ; - l =gpmc_read_reg (GPMC_REVISION ); -printk (KERN_INFO "GPMC revision %d.%d\n" , (l >>4 ) &0x0f , l &0x0f ); -/* Set smart idle mode and automatic L3 clock gating */ - l =gpmc_read_reg (GPMC_SYSCONFIG ); - l &=0x03 <<3 ; - l |= (0x02 <<3 ) | (1 <<0 ); -gpmc_write_reg (GPMC_SYSCONFIG , l); -gpmc_mem_init (); +switch (conf &GPMC_WAITPIN_MASK ) { +case GPMC_WAITPIN_0 : + idx =GPMC_WAITPIN_IDX0 ; +break ; +case GPMC_WAITPIN_1 : + idx =GPMC_WAITPIN_IDX1 ; +break ; +case GPMC_WAITPIN_2 : + idx =GPMC_WAITPIN_IDX2 ; +break ; +case GPMC_WAITPIN_3 : + idx =GPMC_WAITPIN_IDX3 ; +break ; +/* no waitpin */ +case 0 : +break ; +default : +dev_err (gpmc->dev,"multiple waitpins selected on CS:%u\n" , cs); +return -EINVAL ; +break ; + } -/* initalize the irq_chained */ - irq =OMAP_GPMC_IRQ_BASE ; -for (cs =0 ; cs <GPMC_CS_NUM ; cs++) { -irq_set_chip_and_handler (irq, &dummy_irq_chip, - handle_simple_irq); -set_irq_flags (irq,IRQF_VALID ); - irq++; +switch (conf &GPMC_WAITPIN_POLARITY_MASK ) { +case GPMC_WAITPIN_ACTIVE_LOW : + polarity =LOW ; +break ; +case GPMC_WAITPIN_ACTIVE_HIGH : + polarity =HIGH ; +break ; +/* no waitpin */ +case 0 : +break ; +default : +dev_err (gpmc->dev,"waitpin polarity set to low & high\n" ); +return -EINVAL ; +break ; } - ret =request_irq (gpmc_irq, gpmc_handle_irq,IRQF_SHARED ,"gpmc" ,NULL ); -if (ret) -pr_err ("gpmc: irq-%d could not claim: err %d\n" , - gpmc_irq, ret); -return ret; +if (idx != ~0x0 ) { +if (gd->have_waitpin) { +if (gd->waitpin != idx || + gd->waitpin_polarity != polarity) {
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 979
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10
-0+dev_err (gpmc->dev,"error: conflict: waitpin %u with polarity %d on device %s.%d\n" , + gd->waitpin, gd->waitpin_polarity, + gd->name, gd->id); +return -EBUSY ; + } + }else { + gd->have_waitpin = true; + gd->waitpin = idx; + gd->waitpin_polarity = polarity; + }
I am not sure about the above code. What happens if a device has multiple CS signals and uses multiple wait signals?
I am also not sure why gpmc_setup_cs_waitpin and gpmc_setup_waitpin cannot be combined. I think that it would be a fair assumption to make that anyone using the waitpin does so inconjunction with the CS (I think that they would have too).
However, if there is a reason for splitting it up this way please explain why.
Quoted 65 lines
arch/arm/mach-omap2/gpmc.c +65
-0+ + l &= ~GPMC_CONFIG1_WAIT_PIN_SEL_MASK ; + l |=GPMC_CONFIG1_WAIT_PIN_SEL (idx); +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , l); + }else if (polarity) { +dev_err (gpmc->dev,"error: waitpin polarity specified with out wait pin number on device %s.%d\n" , + gd->name, gd->id); +return -EINVAL ; + } + +return 0 ; +} + +static void gpmc_setup_cs_config (struct gpmc *gpmc,unsigned cs,unsigned conf) +{ +u32 l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG1 ); + + l &= ~(GPMC_CONFIG1_TIMEPARAGRANULARITY | +GPMC_CONFIG1_MUXADDDATA | +GPMC_CONFIG1_DEVICETYPE (~0 ) | +GPMC_CONFIG1_DEVICESIZE (~0 ) | +GPMC_CONFIG1_WAIT_WRITE_MON | +GPMC_CONFIG1_WAIT_READ_MON | +GPMC_CONFIG1_PAGE_LEN (~0 ) | +GPMC_CONFIG1_WRITETYPE_SYNC | +GPMC_CONFIG1_WRITEMULTIPLE | +GPMC_CONFIG1_READTYPE_SYNC | +GPMC_CONFIG1_READMULTIPLE | +GPMC_CONFIG1_WRAPBURST | +GPMC_CONFIG1_WAITPIN_MONITOR_TIME (~0 ) | +GPMC_CONFIG1_CLOCKACTIVATION_TIME (~0 )); + +if (conf &GPMC_TIMEPARAGRANULARITY ) + l |=GPMC_CONFIG1_TIMEPARAGRANULARITY ; +if (conf &GPMC_MUXADDDATA ) + l |=GPMC_CONFIG1_MUXADDDATA ; +if (conf &GPMC_DEVICETYPE_NAND ) + l |=GPMC_CONFIG1_DEVICETYPE_NAND ; +if (conf &GPMC_DEVICESIZE_16 ) + l |=GPMC_CONFIG1_DEVICESIZE_16 ; +if (conf &GPMC_WAIT_WRITE_MON ) + l |=GPMC_CONFIG1_WAIT_WRITE_MON ; +if (conf &GPMC_WAIT_READ_MON ) + l |=GPMC_CONFIG1_WAIT_READ_MON ; +if (conf &GPMC_PAGE_LEN_16 ) + l |=GPMC_CONFIG1_PAGE_LEN_16 ; +else if (conf &GPMC_PAGE_LEN_8 ) + l |=GPMC_CONFIG1_PAGE_LEN_8 ; +if (conf &GPMC_WRITETYPE_SYNC ) + l |=GPMC_CONFIG1_WRITETYPE_SYNC ; +if (conf &GPMC_WRITEMULTIPLE ) + l |=GPMC_CONFIG1_WRITEMULTIPLE ; +if (conf &GPMC_READTYPE_SYNC ) + l |=GPMC_CONFIG1_READTYPE_SYNC ; +if (conf &GPMC_READMULTIPLE ) + l |=GPMC_CONFIG1_READMULTIPLE ; +if (conf &GPMC_WRAPBURST ) + l |=GPMC_CONFIG1_WRAPBURST ; +if (conf &GPMC_WAITPIN_MONITOR_TIME_1 ) + l |=GPMC_CONFIG1_WAITPIN_MONITOR_TIME_1 ; +else if (conf &GPMC_WAITPIN_MONITOR_TIME_2 ) + l |=GPMC_CONFIG1_WAITPIN_MONITOR_TIME_2 ; +if (conf &GPMC_CLOCKACTIVATION_TIME_1 ) + l |=GPMC_CONFIG1_CLOCKACTIVATION_TIME_1 ; +else if (conf &GPMC_CLOCKACTIVATION_TIME_2 )
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1054
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10
-0+ l |=GPMC_CONFIG1_CLOCKACTIVATION_TIME_2 ; + +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , l); + +if (conf &GPMC_WRITEPROTECT ) + gpmc->wp = true; +} + +static int gpmc_setup_cs_nonres (struct gpmc *gpmc, +struct gpmc_device *gd,struct gpmc_cs_data *cs)
The name of this function is not 100% clear to me. What do you mean by "nonres"?
Quoted 29 lines
arch/arm/mach-omap2/gpmc.c +29
-0+{ +int ret; + +/* some boards rely on bootloader for configuration */ +if (cs->have_config) { +gpmc_setup_cs_config (gpmc, cs->cs, cs->config); + ret =gpmc_setup_cs_waitpin (gpmc, gd, cs->cs, cs->config); +if (IS_ERR_VALUE (ret)) { +dev_err (gpmc->dev,"error: waitpin on CS %d\n" , cs->cs); +return ret; + } + }else +dev_warn (gpmc->dev,"config not present for CS: %d\n" , cs->cs); + +if (cs->timing) { + ret =gpmc_cs_set_timings (cs->cs, cs->timing); +if (IS_ERR_VALUE (ret)) { +dev_err (gpmc->dev,"error: timing on CS: %d\n" , cs->cs); +return ret; + } + }else +dev_warn (gpmc->dev,"timing not present for CS: %u\n" , cs->cs); + +return 0 ; +} + +static int gpmc_match_device (struct gpmc *gpmc,char *name,int id) +{ +int i;
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1093
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10
-0+struct gpmc_device *gd; + +for (i =0 , gd = gpmc->device; i < gpmc->num_device; i++, gd++) +if (!strcmp (gd->name, name) && gd->id == id) +return i; + +return -ENOENT ; +} + +int gpmc_cs_reconfigure (char *name,int id,struct gpmc_cs_data *cs)
What scenario is this function used in? May be worth adding a comment about the function.
Quoted 86 lines
arch/arm/mach-omap2/gpmc.c +86
-0+{ +int i; + + i =gpmc_match_device (gpmc, name, id); +if (IS_ERR_VALUE (i)) { +dev_err (gpmc->dev,"no device %s.%d to configure\n" , name, id); +return i; + } + + i =gpmc_setup_cs_nonres (gpmc, gpmc->device + i, cs); +if (IS_ERR_VALUE (i)) { +dev_err (gpmc->dev,"error: configure device %s.%d\n" , name, id); +return i; + } + +return gpmc_setup_waitpin (gpmc, gpmc->device + i); + +} +EXPORT_SYMBOL_GPL (gpmc_cs_reconfigure); + +static inline unsigned int gpmc_bit_to_irq (unsigned bitmask) +{ +if (bitmask &GPMC_IRQ_BIT_FIFOEVENT ) +return GPMC_IRQ_FIFOEVENTENABLE ; +else if (bitmask &GPMC_IRQ_BIT_TERMINALCOUNT ) +return GPMC_IRQ_COUNT_EVENT ; +else +return 0 ; +} + +static __devinit int gpmc_setup_cs_irq (struct gpmc *gpmc, +struct gpmc_cs_data *cs,struct resource *res) +{ +int i, n; + +for (i =0 , n =0 ; i <GPMC_NR_IRQ ; i++) +if (gpmc_bit_to_irq (gpmc->irq[i].bitmask) & cs->irq_config) { + res[n].start = res[n].end = gpmc->irq[i].irq; + res[n].flags =IORESOURCE_IRQ ; +dev_info (gpmc->dev,"irq %u on CS %d\n" , + res[n].start, cs->cs); + n++; + } + +return n; +} + +static __devinit int gpmc_setup_cs_mem (struct gpmc *gpmc, +struct gpmc_cs_data *cs,struct resource *res) +{ +unsigned long start; +int ret; + + ret =gpmc_cs_request (cs->cs, cs->mem_size, &start); +if (IS_ERR_VALUE (ret)) { +dev_err (gpmc->dev,"error: gpmc request on CS: %d\n" , cs->cs); +return ret; + } + + res->start = start + cs->mem_offset; + res->end = res->start + cs->mem_size -1 ; + res->flags =IORESOURCE_MEM ; + +dev_info (gpmc->dev,"memory 0x%x-0x%x on CS %d\n" , res->start, + res->end, cs->cs); + +return 1 ; +} + +static __devinit int gpmc_setup_cs (struct gpmc *gpmc,struct gpmc_device *gd, +struct gpmc_cs_data *cs,struct resource *res) +{ +int num, ret; + + num =gpmc_setup_cs_mem (gpmc, cs, res); +if (IS_ERR_VALUE (num)) +return num; + + ret =gpmc_setup_cs_nonres (gpmc, gd, cs); +if (IS_ERR_VALUE (ret)) +return ret; + + num +=gpmc_setup_cs_irq (gpmc, cs, res + num); + +return num; +}
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1189
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10
-0+ +static __devinit int gpmc_setup_device (struct gpmc *gpmc, +struct gpmc_device *gd,struct gpmc_device_pdata *gdp) +{ +int i, n, ret; +struct gpmc_cs_data *cs; + +for (i =0 , n = gdp->num_cs, cs = gdp->cs_data; + i < gdp->num_cs; i++, cs++) + n +=hweight32 (cs->irq_config);
As you know I am not a fan of these overloaded for-loops as I find them hard to read ;-)
Why not ...
n = gdp->num_cs;
cs = gdp->cs_data;
/* Calculate total number of irqs used by device */ for (i = 0, i < gdp->num_cs; i++)
n += hweight32(cs[i].irq_flags & GPMC_IRQ_MASK);
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1199
Quoted 9 lines
arch/arm/mach-omap2/gpmc.c +9
-0+ gd->gpmc_res =devm_kzalloc (gpmc->dev,sizeof (*gd->gpmc_res) * n, +GFP_KERNEL ); +if (gd->gpmc_res ==NULL ) { +dev_err (gpmc->dev,"error: memory allocation\n" ); +return -ENOMEM ; + } + +for (i =0 , cs = gdp->cs_data, gd->gpmc_res_cnt =0 ; + i < gdp->num_cs; cs++, i++) {
By the way, if you make the above change, you can also remove "cs = gdp->cs_data" from this for-loop as it is already initialised.
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1203
Quoted 4 lines
arch/arm/mach-omap2/gpmc.c +4
-0+ ret =gpmc_setup_cs (gpmc, gd, cs, + gd->gpmc_res + gd->gpmc_res_cnt); +if (IS_ERR_VALUE (ret) || +IS_ERR_VALUE (gpmc_setup_waitpin (gpmc, gd))) {
May be consider moving gpmc_setup_waitpin into gpmc_setup_cs as it makes sense that it is part of the cs setup.
Quoted 200 lines
arch/arm/mach-omap2/gpmc.c +185
-6+dev_err (gpmc->dev,"error: setup for %s\n" , gdp->name); +devm_kfree (gpmc->dev, gd->gpmc_res); + gd->gpmc_res =NULL ; + gd->gpmc_res_cnt =0 ; +return -EINVAL ; + }else + gd->gpmc_res_cnt += ret; + } + + gd->name = gdp->name; + gd->id = gdp->id; + gd->pdata = gdp->pdata; + gd->pdata_size = gdp->pdata_size; + gd->per_res = gdp->per_res; + gd->per_res_cnt = gdp->per_res_cnt; + +return 0 ; +} + +static __devinit +struct platform_device *gpmc_create_device (struct gpmc *gpmc, +struct gpmc_device *p) +{ +int num = p->per_res_cnt + p->gpmc_res_cnt; +struct resource *res; +struct platform_device *pdev; + + res =devm_kzalloc (gpmc->dev,sizeof (struct resource ) * num, +GFP_KERNEL ); +if (!res) { +dev_err (gpmc->dev,"error: allocating memory\n" ); +return NULL ; + } + +memcpy ((char *)res, (const char *) p->gpmc_res, +sizeof (struct resource ) * p->gpmc_res_cnt); +memcpy ((char *)(res + p->gpmc_res_cnt), (const char *)p->per_res, +sizeof (struct resource ) * p->per_res_cnt); + + pdev =platform_device_register_resndata (gpmc->dev, p->name, p->id, + res, num, p->pdata, p->pdata_size); + +devm_kfree (gpmc->dev, res); + +return pdev; } -postcore_initcall (gpmc_init);static irqreturn_t gpmc_handle_irq (int irq,void *dev) { -u8 cs; +int i; +u32 regval; +struct gpmc *gpmc = dev; + + regval =gpmc_read_reg (GPMC_IRQSTATUS ); -/* check cs to invoke the irq */ - cs = ((gpmc_read_reg (GPMC_PREFETCH_CONFIG1 )) >>CS_NUM_SHIFT ) &0x7 ; -if (OMAP_GPMC_IRQ_BASE +cs <=OMAP_GPMC_IRQ_END ) -generic_handle_irq (OMAP_GPMC_IRQ_BASE +cs); +for (i =0 ; i <GPMC_NR_IRQ ; i++) +if (regval & gpmc->irq[i].bitmask) +generic_handle_irq (gpmc->irq[i].irq); + +gpmc_write_reg (GPMC_IRQSTATUS , regval);return IRQ_HANDLED ; } +static int gpmc_irq_endis (struct gpmc *gpmc,unsigned irq,bool endis) +{ +int i; +u32 regval; + +for (i =0 ; i <GPMC_NR_IRQ ; i++) +if (irq == gpmc->irq[i].irq) { + regval =gpmc_read_reg (GPMC_IRQENABLE ); +if (endis) + regval |= gpmc->irq[i].bitmask; +else + regval &= ~gpmc->irq[i].bitmask; +gpmc_write_reg (GPMC_IRQENABLE , regval); +break ; + } + +return 0 ; +} + +static void gpmc_irq_disable (struct irq_data *p) +{ +gpmc_irq_endis (irq_data_get_irq_chip_data (p), p->irq, false); +} + +static void gpmc_irq_enable (struct irq_data *p) +{ +gpmc_irq_endis (irq_data_get_irq_chip_data (p), p->irq, true); +} + +static void gpmc_irq_noop (struct irq_data *data) { } + +static unsigned int gpmc_irq_noop_ret (struct irq_data *data) {return 0 ; } + +static __devinit int gpmc_setup_irq (struct gpmc *gpmc) +{ +int i; +u32 regval; + +if (!gpmc->master_irq) +return -EINVAL ; + + gpmc->irq_start =irq_alloc_descs (-1 ,0 ,GPMC_NR_IRQ ,0 ); +if (IS_ERR_VALUE (gpmc->irq_start)) { +dev_err (gpmc->dev,"irq_alloc_descs failed\n" ); +return gpmc->irq_start; + } + + gpmc->irq_chip.name ="gpmc" ; + gpmc->irq_chip.irq_startup = gpmc_irq_noop_ret; + gpmc->irq_chip.irq_enable = gpmc_irq_enable; + gpmc->irq_chip.irq_disable = gpmc_irq_disable; + gpmc->irq_chip.irq_shutdown = gpmc_irq_noop; + gpmc->irq_chip.irq_ack = gpmc_irq_noop; + gpmc->irq_chip.irq_mask = gpmc_irq_noop; + gpmc->irq_chip.irq_unmask = gpmc_irq_noop; + + gpmc->irq[0 ].bitmask =GPMC_IRQ_BIT_FIFOEVENT ; + gpmc->irq[1 ].bitmask =GPMC_IRQ_BIT_TERMINALCOUNT ; + +for (i =0 ; i <GPMC_NR_IRQ ; i++) { + gpmc->irq[i].irq = gpmc->irq_start + i; +irq_set_chip_and_handler (gpmc->irq[i].irq, + &gpmc->irq_chip, handle_simple_irq); +irq_set_chip_data (gpmc->irq[i].irq, gpmc); +set_irq_flags (gpmc->irq[i].irq,IRQF_VALID |IRQF_NOAUTOEN ); + } + +/* Disable interrupts */ +gpmc_write_reg (GPMC_IRQENABLE ,0 ); + +/* clear interrupts */ + regval =gpmc_read_reg (GPMC_IRQSTATUS ); +gpmc_write_reg (GPMC_IRQSTATUS , regval); + +return request_irq (gpmc->master_irq, gpmc_handle_irq,IRQF_SHARED , +"gpmc" , gpmc); +} + +static __devinit void gpmc_setup_writeprotect (struct gpmc *gpmc) +{ +u32 l; + + l =gpmc_read_reg (GPMC_CONFIG ); +if (gpmc->wp == true) { + l &= ~GPMC_CONFIG_WRITEPROTECT ; +dev_info (gpmc->dev,"write protect enabled\n" ); + }else + l |=GPMC_CONFIG_WRITEPROTECT ; +gpmc_write_reg (GPMC_CONFIG , l); +} + +static __devinit int gpmc_probe (struct platform_device *pdev) +{ +u32 l; +int i; +int ret =0 ; +struct resource *res =NULL ; +struct gpmc_pdata *gp =dev_get_platdata (&pdev->dev); +struct gpmc_device_pdata **gdq =NULL ; +struct gpmc_device *gd =NULL ; + + gpmc =devm_kzalloc (&pdev->dev,sizeof (struct gpmc ),GFP_KERNEL ); +if (gpmc ==NULL ) +return -ENOMEM ; + + gpmc->dev = &pdev->dev; + gpmc->clk_prd = gp->clk_prd; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (res ==NULL ) +return -ENOENT ; + + gpmc->phys_base = res->start; + gpmc->memsize =resource_size (res); + + gpmc->io_base =devm_request_and_ioremap (gpmc->dev, res); +if (!gpmc->io_base) +return -EADDRNOTAVAIL ; + + res =platform_get_resource (pdev,IORESOURCE_IRQ ,0 ); +if (res ==NULL ) +dev_warn (gpmc->dev,"Failed to get resource: irq\n" ); +else + gpmc->master_irq = res->start; + +if (IS_ERR_VALUE (gpmc_setup_irq (gpmc))) +dev_warn (gpmc->dev,"gpmc_setup_irq failed\n" ); + + gpmc->ecc_used = -EINVAL ; +spin_lock_init (&gpmc->mem_lock);
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1407
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10
-0+platform_set_drvdata (pdev, gpmc); + + l =gpmc_read_reg (GPMC_REVISION ); + gpmc->revision = (l >>4 ) &0xf ; +dev_info (gpmc->dev,"GPMC revision %u.%u\n" , gpmc->revision, l &0x0f ); + +gpmc_mem_init (); + +for (i =0 , gdq = gp->device_pdata, gd = gpmc->device; + (i < gp->num_device) && (*gdq); i++, gdq++) {
You have num_devices now and so do you really need the "&& (*gdq)"? Seems redundant.
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1408
Quoted 1 line
arch/arm/mach-omap2/gpmc.c +1
-0+ ret =gpmc_setup_device (gpmc, gd, *gdq);
gdp[i]
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1417
Quoted 9 lines
arch/arm/mach-omap2/gpmc.c +9
-0+if (IS_ERR_VALUE (ret)) +dev_err (gpmc->dev,"gpmc setup on %s failed\n" , + (*gdq)->name); +else + gd++; + } + gpmc->num_device = gd - gpmc->device; + +gpmc_setup_writeprotect (gpmc);
Write protect is a pin and there is only one. Like the waitpins and CS signals this needs to be associated with a device. It would make sense that this is associated with the cs data.
Quoted 119 lines
arch/arm/mach-omap2/gpmc.c +53
-4+ +for (i =0 , gd = gpmc->device; i < gpmc->num_device; i++, gd++) +if (IS_ERR (gpmc_create_device (gpmc, gd))) +dev_err (gpmc->dev,"device creation on %s failed\n" , + gd->name); + +return 0 ; +} + +static __devexit int gpmc_free_irq(struct gpmc *gpmc) +{ +int i; + +if (gpmc->master_irq) +free_irq (gpmc->master_irq, gpmc); + +for (i =0 ; i <GPMC_NR_IRQ ; i++) { +irq_set_handler (gpmc->irq[i].irq,NULL ); +irq_set_chip (gpmc->irq[i].irq, &no_irq_chip); +irq_set_chip_data (gpmc->irq[i].irq,NULL ); +irq_modify_status (gpmc->irq[i].irq,0 ,0 ); + } + +irq_free_descs (gpmc->irq_start,GPMC_NR_IRQ ); + +return 0 ; +} + +static __devexit int gpmc_remove(struct platform_device *pdev) +{ +struct gpmc *gpmc =platform_get_drvdata (pdev); + +platform_set_drvdata (pdev,NULL ); +gpmc_free_irq (gpmc); + +return 0 ; +} + +static struct platform_driver gpmc_driver = { + .probe = gpmc_probe, + .remove =__devexit_p (gpmc_remove), + .driver = { + .name =DRIVER_NAME , + .owner =THIS_MODULE , + }, +}; + +module_platform_driver (gpmc_driver); +#ifdef CONFIG_ARCH_OMAP3 static struct omap3_gpmc_regs gpmc_context;@@ -854,10 +1543,10 @@ int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size)unsigned int val;/* check if ecc module is in used */ -if (gpmc_ecc_used != -EINVAL ) +if (gpmc->ecc_used != -EINVAL )return -EINVAL ; - gpmc_ecc_used = cs; + gpmc->ecc_used = cs;/* clear ecc and enable bits */ val = ((0x00000001 <<8 ) |0x00000001 );@@ -905,7 +1594,7 @@ int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code) {unsigned int val =0x0 ; -if (gpmc_ecc_used != cs) +if (gpmc->ecc_used != cs)return -EINVAL ;/* read ecc result */ @@ -915,7 +1604,7 @@ int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */ *ecc_code++ = ((val >>8 ) &0x0f ) | ((val >>20 ) &0xf0 ); - gpmc_ecc_used = -EINVAL ; + gpmc->ecc_used = -EINVAL ;return 0 ; }EXPORT_SYMBOL_GPL (gpmc_calculate_ecc);arch/arm/plat-omap/include/plat/gpmc.h +28
-0@@ -11,6 +11,44 @@#ifndef __OMAP2_GPMC_H#define __OMAP2_GPMC_H +/* configuration flags */ +#define GPMC_WRITEPROTECT BIT(0) +#define GPMC_TIMEPARAGRANULARITY BIT(1) +#define GPMC_MUXADDDATA BIT(2) +#define GPMC_DEVICETYPE_NOR BIT(3) +#define GPMC_DEVICETYPE_NAND BIT(4) +#define GPMC_DEVICESIZE_8 BIT(5) +#define GPMC_DEVICESIZE_16 BIT(6) +#define GPMC_WAIT_WRITE_MON BIT(7) +#define GPMC_WAIT_READ_MON BIT(8) +#define GPMC_PAGE_LEN_4 BIT(9) +#define GPMC_PAGE_LEN_8 BIT(10) +#define GPMC_PAGE_LEN_16 BIT(11) +#define GPMC_CLOCKACTIVATIONTIME_0 BIT(12) +#define GPMC_CLOCKACTIVATIONTIME_1 BIT(13) +#define GPMC_CLOCKACTIVATIONTIME_2 BIT(14) +#define GPMC_WRITETYPE_SYNC BIT(15) +#define GPMC_WRITEMULTIPLE BIT(16) +#define GPMC_READTYPE_SYNC BIT(17) +#define GPMC_READMULTIPLE BIT(18) +#define GPMC_WRAPBURST BIT(19) +#define GPMC_WAITPIN_0 BIT(20) +#define GPMC_WAITPIN_1 BIT(21) +#define GPMC_WAITPIN_2 BIT(22) +#define GPMC_WAITPIN_3 BIT(23) +#define GPMC_WAITPIN_MASK (GPMC_WAITPIN_0 | GPMC_WAITPIN_1 | \ + GPMC_WAITPIN_2 | GPMC_WAITPIN_3) +#define GPMC_WAITPIN_ACTIVE_LOW BIT(24)
arch/arm/plat-omap/include/plat/gpmc.h line 51
Quoted 10 lines
arch/arm/plat-omap/include/plat/gpmc.h +10
-0+#define GPMC_WAITPIN_ACTIVE_HIGH BIT(25) +#define GPMC_WAITPIN_POLARITY_MASK (GPMC_WAITPIN_ACTIVE_LOW | \ + GPMC_WAITPIN_ACTIVE_HIGH) +#define GPMC_WAITPIN_MONITOR_TIME_1 BIT(26) +#define GPMC_WAITPIN_MONITOR_TIME_2 BIT(27) +#define GPMC_CLOCKACTIVATION_TIME_1 BIT(28) +#define GPMC_CLOCKACTIVATION_TIME_2 BIT(29) +#define GPMC_READTYPE_ASYNC BIT(30) +#define GPMC_WRITETYPE_ASYNC BIT(31) +
Please keep in mind that eventually this has to all be moved into device tree and so at that point these configuration flags will have to be re-worked. However, just a FYI.
Cheers
Jon
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Jon,
Quoted 3 lines · Jon
Hi Afzal,
Looks good! Some minor comments ...
Thanks
Quoted 8 lines
arch/arm/mach-omap2/gpmc.c line 96
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c +5
-0+#define GPMC_WAITPIN_IDX0 0x0 +#define GPMC_WAITPIN_IDX1 0x1 +#define GPMC_WAITPIN_IDX2 0x2 +#define GPMC_WAITPIN_IDX3 0x3 +#define GPMC_NR_WAITPIN 0x4How about an enum here? Also OMAP4 only have 3 wait pins and so the number is device dependent.
Ok
Quoted 8 lines
Quoted 8 lines
#define
GPMC_MEM_START0x00000000
#defineGPMC_MEM_END0x3FFFFFFF
#defineBOOT_ROM_SPACE0x100000/* 1MB */arch/arm/mach-omap2/gpmc.c +0
-0@@ -64,6 +106,55 @@#define ENABLE_PREFETCH (0x1 << 7)#define DMA_MPU_MODE 2
Quoted 7 lines
arch/arm/mach-omap2/gpmc.c line 111
Quoted 3 lines
arch/arm/mach-omap2/gpmc.c +3
-0+#define DRIVER_NAME "omap-gpmc" + +#define GPMC_NR_IRQ 2Why has this been changed to 2? It was 6 in the previous version. As we discussed before the number of IRQs should be detected based upon GPMC IP version.
As mentioned in the cover letter,
"Additional features that currently boards in mainline does not make use of like, waitpin interrupt handling, changes to leverage revision 6 IP differences has not been incorporated."
Priority in this series is to convert into a driver, get all boards working on mainline. Once all boards are working with gpmc driver, these features which are not required for currently supported boards can be added later.
Quoted 7 lines
Quoted 7 lines
arch/arm/mach-omap2/gpmc.c +7
-0+struct gpmc_device { +char *name; +int id; +void *pdata; +unsigned pdata_size; +struct resource *per_res; +unsigned per_res_cnt;
Quoted 8 lines
arch/arm/mach-omap2/gpmc.c line 127
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c +5
-0+struct resource *gpmc_res; +unsigned gpmc_res_cnt; +bool have_waitpin; +unsigned waitpin; +int waitpin_polarity;I think that it make more sense to have the wait-pin information part of the
gpmc_cs_datastructure for the following reasons ...
Waitpin information is indeed a part of cs as far as boards are concerned, it is only that it gets propogated to device
Quoted 11 lines
1. If a device can use multiple CS, then it could use multiple wait signals.
2. Eventually, all board information needs to move to device tree. By having it in the pdata it will be easier to migrate to device tree.It may be nice to have "
have_waitpin" be an integer too, that indicates if wait is used for both read and write or just one or the other.Also, any reason why
waitpin_polarityis an int? I see you define LOW as -1, but I not sure why LOW cannot be 0 as 0 is programmed into the register for an active low wait signal.
Only intention is not to alter default waitpin polarity value, i.e. if any board does make use of it w/o knowledge of Kernel, I don't want to break it, there may be an argument saying that the board code is buggy, while if some board does so, it is, but don't want to break working one.
Here unless user explicitly set the flag, it does nothing on polarity
Quoted 18 lines
Quoted 4 lines
arch/arm/mach-omap2/gpmc.c +4
-0+if (idx != ~0x0 ) { +if (gd->have_waitpin) { +if (gd->waitpin != idx || + gd->waitpin_polarity != polarity) {arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 979
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10
-0+dev_err (gpmc->dev,"error: conflict: waitpin %u with polarity %d on device %s.%d\n" , + gd->waitpin, gd->waitpin_polarity, + gd->name, gd->id); +return -EBUSY ; + } + }else { + gd->have_waitpin = true; + gd->waitpin = idx; + gd->waitpin_polarity = polarity; + }I am not sure about the above code. What happens if a device has multiple CS signals and uses multiple wait signals?
Quoted 7 lines
I am also not sure why
gpmc_setup_cs_waitpinandgpmc_setup_waitpincannot be combined. I think that it would be a fair assumption to make that anyone using the waitpin does so inconjunction with the CS (I think that they would have too).However, if there is a reason for splitting it up this way please explain why.
Initially it was done per CS, the problem happened while trying to convert tusb6010. It had multiple CS, but using same waitpin. Problem with incorporating this onto CS is we have to sacrifice on wait pin conflict prevention capability. The code now handles case of wait pin conflict per device, the code can be extended to have multiple wait pin per device also. But I prefer to defer it to later, not as part of this series, as this feature what you asking for is not required for any of the existing boards. I can add it in this series if there is a strong opinion in the community for the same in this series.
Policy that is being followed here is first sit, then straighten legs, ;)
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1054
Quoted 2 lines
arch/arm/mach-omap2/gpmc.c +2
-0+static int gpmc_setup_cs_nonres (struct gpmc *gpmc, +struct gpmc_device *gd,struct gpmc_cs_data *cs)The name of this function is not 100% clear to me. What do you mean by "nonres"?
It means anything other than resources like memory & irq, happened for want of better name, if you have one, name it, will put it.
Quoted 4 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1093
Quoted 1 line
arch/arm/mach-omap2/gpmc.c +1
-0+int gpmc_cs_reconfigure (char *name,int id,struct gpmc_cs_data *cs)What scenario is this function used in? May be worth adding a comment about the function.
Ok, it was required for OneNAND, as it needs to reconfigure
Quoted 11 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1189
Quoted 3 lines
arch/arm/mach-omap2/gpmc.c +3
-0+for (i =0 , n = gdp->num_cs, cs = gdp->cs_data; + i < gdp->num_cs; i++, cs++) + n +=hweight32 (cs->irq_config);As you know I am not a fan of these overloaded for-loops as I find them hard to read ;-)
Why not ...
n =
gdp->num_cs;
cs =gdp->cs_data;
Well, you also know that I am big fan of it; difference of opinion, my preference is to keep loop control statements together with "for", unless there is a cry from community that it should not be this way. I believe that it is not that much unreadable.
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1407
Quoted 2 lines
arch/arm/mach-omap2/gpmc.c +2
-0+for (i =0 , gdq = gp->device_pdata, gd = gpmc->device; + (i < gp->num_device) && (*gdq); i++, gdq++) {You have
num_devicesnow and so do you really need the "&& (*gdq)"? Seems redundant.
num_device is something that I never wanted to add, was happy with, NULL entry termination, only because of your repeated comments, I added this. And this additional check now prevents NULL dereference.
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1417
Quoted 1 line
arch/arm/mach-omap2/gpmc.c +1
-0+gpmc_setup_writeprotect (gpmc);Write protect is a pin and there is only one. Like the waitpins and CS signals this needs to be associated with a device. It would make sense that this is associated with the cs data.
As far as platform are concerned, it is associated with cs, it is only that while configuring CS, it is propagated such that it is done once.
Quoted 7 lines
arch/arm/plat-omap/include/plat/gpmc.h line 51
Quoted 3 lines
arch/arm/plat-omap/include/plat/gpmc.h +3
-0+#define GPMC_READTYPE_ASYNC BIT(30) +#define GPMC_WRITETYPE_ASYNC BIT(31) +Please keep in mind that eventually this has to all be moved into device tree and so at that point these configuration flags will have to be re-worked. However, just a FYI.
On device tree matters, my mind is next to blank, thanks for mentioning it.
Regards
Afzal
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Afzal,
Quoted 38 lines · Afzal
Hi Jon,
Quoted 3 lines · Jon
Hi Afzal,
Looks good! Some minor comments ...
Thanks
Quoted 8 lines
arch/arm/mach-omap2/gpmc.c line 96
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c +5
-0+#define GPMC_WAITPIN_IDX0 0x0 +#define GPMC_WAITPIN_IDX1 0x1 +#define GPMC_WAITPIN_IDX2 0x2 +#define GPMC_WAITPIN_IDX3 0x3 +#define GPMC_NR_WAITPIN 0x4How about an enum here? Also OMAP4 only have 3 wait pins and so the number is device dependent.
Ok
Quoted 8 lines
Quoted 8 lines
#define
GPMC_MEM_START0x00000000
#defineGPMC_MEM_END0x3FFFFFFF
#defineBOOT_ROM_SPACE0x100000/* 1MB */arch/arm/mach-omap2/gpmc.c +0
-0@@ -64,6 +106,55 @@#define ENABLE_PREFETCH (0x1 << 7)#define DMA_MPU_MODE 2Quoted 7 lines
arch/arm/mach-omap2/gpmc.c line 111
Quoted 3 lines
arch/arm/mach-omap2/gpmc.c +3
-0+#define DRIVER_NAME "omap-gpmc" + +#define GPMC_NR_IRQ 2Why has this been changed to 2? It was 6 in the previous version. As we discussed before the number of IRQs should be detected based upon GPMC IP version.
As mentioned in the cover letter,
Quoted 7 lines
"Additional features that currently boards in mainline does not make use of like, waitpin interrupt handling, changes to leverage revision 6 IP differences has not been incorporated."
Priority in this series is to convert into a driver, get all boards working on mainline. Once all boards are working with gpmc driver, these features which are not required for currently supported boards can be added later.
Yes, but I meant why 2 and not say 5? Anyway, I think that this should be marked with a comment like a TODO so it is clear that this needs to be re-visited.
Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
arch/arm/mach-omap2/gpmc.c +7
-0+struct gpmc_device { +char *name; +int id; +void *pdata; +unsigned pdata_size; +struct resource *per_res; +unsigned per_res_cnt;Quoted 8 lines
arch/arm/mach-omap2/gpmc.c line 127
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c +5
-0+struct resource *gpmc_res; +unsigned gpmc_res_cnt; +bool have_waitpin; +unsigned waitpin; +int waitpin_polarity;I think that it make more sense to have the wait-pin information part of the
gpmc_cs_datastructure for the following reasons ...
Quoted 2 lines
Waitpin information is indeed a part of cs as far as boards are concerned, it is only that it gets propogated to device
Why does the device's driver care? From my point of view, the wait-pin is just part of the interface setup/configuration. The external device may require this and assumes that this has been setup along with the CS and interface timing, but the device's driver should not care. Remember this is just a ready signal used to stall the access. Once configured, software should be unaware of it.
Quoted 11 lines
Quoted 10 lines
1. If a device can use multiple CS, then it could use multiple wait signals.
2. Eventually, all board information needs to move to device tree. By having it in the pdata it will be easier to migrate to device tree.It may be nice to have "
have_waitpin" be an integer too, that indicates if wait is used for both read and write or just one or the other.Also, any reason why
waitpin_polarityis an int? I see you define LOW as -1, but I not sure why LOW cannot be 0 as 0 is programmed into the register for an active low wait signal.
Quoted 6 lines
Only intention is not to alter default waitpin polarity value, i.e. if any board does make use of it w/o knowledge of Kernel, I don't want to break it, there may be an argument saying that the board code is buggy, while if some board does so, it is, but don't want to break working one.
Here unless user explicitly set the flag, it does nothing on polarity
Ok. Do such scenario's exist today? Please note that board code will be removed in the future and device-tree will replace. So if there are no cases today, I would not be concerned. Unless this could be something that has already been configured by the bootloader. However, in that case would be even call this function?
Quoted 26 lines
Quoted 18 lines
Quoted 4 lines
arch/arm/mach-omap2/gpmc.c +4
-0+if (idx != ~0x0 ) { +if (gd->have_waitpin) { +if (gd->waitpin != idx || + gd->waitpin_polarity != polarity) {arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 979
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10
-0+dev_err (gpmc->dev,"error: conflict: waitpin %u with polarity %d on device %s.%d\n" , + gd->waitpin, gd->waitpin_polarity, + gd->name, gd->id); +return -EBUSY ; + } + }else { + gd->have_waitpin = true; + gd->waitpin = idx; + gd->waitpin_polarity = polarity; + }I am not sure about the above code. What happens if a device has multiple CS signals and uses multiple wait signals?
Quoted 7 lines
I am also not sure why
gpmc_setup_cs_waitpinandgpmc_setup_waitpincannot be combined. I think that it would be a fair assumption to make that anyone using the waitpin does so inconjunction with the CS (I think that they would have too).However, if there is a reason for splitting it up this way please explain why.
Quoted 9 lines
Initially it was done per CS, the problem happened while trying to convert tusb6010. It had multiple CS, but using same waitpin. Problem with incorporating this onto CS is we have to sacrifice on wait pin conflict prevention capability. The code now handles case of wait pin conflict per device, the code can be extended to have multiple wait pin per device also. But I prefer to defer it to later, not as part of this series, as this feature what you asking for is not required for any of the existing boards. I can add it in this series if there is a strong opinion in the community for the same in this series.
Ok, yes this does make sense. I wonder if we can clean up the all the nested if-statements in gpmc_setup_cs_waitpin(). Seems there could be some redundancy.
Quoted 1 line
Policy that is being followed here is first sit, then straighten legs, ;)
Ha! Crawl before walking ;-)
Quoted 8 lines
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1054
Quoted 2 lines
arch/arm/mach-omap2/gpmc.c +2
-0+static int gpmc_setup_cs_nonres (struct gpmc *gpmc, +struct gpmc_device *gd,struct gpmc_cs_data *cs)The name of this function is not 100% clear to me. What do you mean by "nonres"?
It means anything other than resources like memory & irq, happened for want of better name, if you have one, name it, will put it.
Not really, but may be worth adding a comment.
Quoted 6 lines
Quoted 4 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1093
Quoted 1 line
arch/arm/mach-omap2/gpmc.c +1
-0+int gpmc_cs_reconfigure (char *name,int id,struct gpmc_cs_data *cs)What scenario is this function used in? May be worth adding a comment about the function.
Ok, it was required for OneNAND, as it needs to reconfigure
Ok, but why is that? Unless this is something generic about one-nand I don't comprehend. I have a high-level understanding of one-nand, but I am not familiar with the specifics that require it to be reconfigured.
Quoted 9 lines
Quoted 9 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1189
Quoted 3 lines
arch/arm/mach-omap2/gpmc.c +3
-0+for (i =0 , n = gdp->num_cs, cs = gdp->cs_data; + i < gdp->num_cs; i++, cs++) + n +=hweight32 (cs->irq_config);As you know I am not a fan of these overloaded for-loops as I find them hard to read ;-)
Why not ...
Quoted 8 lines
Quoted 2 lines
n =
gdp->num_cs;
cs =gdp->cs_data;Well, you also know that I am big fan of it; difference of opinion, my preference is to keep loop control statements together with "for", unless there is a cry from community that it should not be this way. I believe that it is not that much unreadable.
Ok.
Quoted 9 lines
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1407
Quoted 2 lines
arch/arm/mach-omap2/gpmc.c +2
-0+for (i =0 , gdq = gp->device_pdata, gd = gpmc->device; + (i < gp->num_device) && (*gdq); i++, gdq++) {You have
num_devicesnow and so do you really need the "&& (*gdq)"? Seems redundant.
num_deviceis something that I never wanted to add, was happy with, NULL entry termination, only because of your repeated comments, I added this. And this additional check now prevents NULL dereference.
Ok, but I would go with one or the other. Make it NULL terminated but maybe add a comment?
Quoted 8 lines
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1417
Quoted 1 line
arch/arm/mach-omap2/gpmc.c +1
-0+gpmc_setup_writeprotect (gpmc);Write protect is a pin and there is only one. Like the waitpins and CS signals this needs to be associated with a device. It would make sense that this is associated with the cs data.
As far as platform are concerned, it is associated with cs, it is only that while configuring CS, it is propagated such that it is done once.
Hmmm ... but here it looks like if write-protect is used you are going to turn it on. A feature like this seems that it does need to be handled by the device's driver. Enabling and disabling write-protect are functions that I would expect are exported to the device's driver and not directly enabled in the gpmc driver during probe. However, maybe is could be valid for the write protect to be enabled by default which could make sense. However, I don't see anywhere else in the driver to control it.
Shouldn't we warn on multiple devices trying to use write-protect when parsing their configuration?
Quoted 9 lines
Quoted 7 lines
arch/arm/plat-omap/include/plat/gpmc.h line 51
Quoted 3 lines
arch/arm/plat-omap/include/plat/gpmc.h +3
-0+#define GPMC_READTYPE_ASYNC BIT(30) +#define GPMC_WRITETYPE_ASYNC BIT(31) +Please keep in mind that eventually this has to all be moved into device tree and so at that point these configuration flags will have to be re-worked. However, just a FYI.
On device tree matters, my mind is next to blank, thanks for mentioning it.
No problem. For now lets not worry too much.
Cheers
Jon
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Jon,
Quoted 6 lines · Jon
Quoted 6 lines
As mentioned in the cover letter,
"Additional features that currently boards in mainline does not make use of like, waitpin interrupt handling, changes to leverage revision 6 IP differences has not been incorporated."
Quoted 7 lines
Quoted 3 lines
Priority in this series is to convert into a driver, get all boards working on mainline. Once all boards are working with gpmc driver, these features which are not required for currently supported boards can be added later.
Yes, but I meant why 2 and not say 5? Anyway, I think that this should be marked with a comment like a TODO so it is clear that this needs to be re-visited.
Ok, it will be marked with TODO
Quoted 6 lines
Quoted 5 lines
Quoted 2 lines
I think that it make more sense to have the wait-pin information part of the
gpmc_cs_datastructure for the following reasons ...Waitpin information is indeed a part of cs as far as boards are concerned, it is only that it gets propogated to device
Quoted 6 lines
Why does the device's driver care? From my point of view, the wait-pin is just part of the interface setup/configuration. The external device may require this and assumes that this has been setup along with the CS and interface timing, but the device's driver should not care. Remember this is just a ready signal used to stall the access. Once configured, software should be unaware of it.
By device, it is referred to gpmc device which only gpmc driver is aware, the peripheral device's driver is not at all aware.
Quoted 9 lines
Quoted 9 lines
Quoted 3 lines
Also, any reason why
waitpin_polarityis an int? I see you define LOW as -1, but I not sure why LOW cannot be 0 as 0 is programmed into the register for an active low wait signal.Only intention is not to alter default waitpin polarity value, i.e. if any board does make use of it w/o knowledge of Kernel, I don't want to break it, there may be an argument saying that the board code is buggy, while if some board does so, it is, but don't want to break working one.
Quoted 7 lines
Quoted 1 line
Here unless user explicitly set the flag, it does nothing on polarity
Ok. Do such scenario's exist today? Please note that board code will be removed in the future and device-tree will replace. So if there are no cases today, I would not be concerned. Unless this could be something that has already been configured by the bootloader. However, in that case would be even call this function?
Let me check this, here only intent was to play safe, as I have only two boards to test.
Quoted 10 lines
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
+int
gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *cs)What scenario is this function used in? May be worth adding a comment about the function.
Ok, it was required for OneNAND, as it needs to reconfigure
Ok, but why is that? Unless this is something generic about one-nand I don't comprehend. I have a high-level understanding of one-nand, but I am not familiar with the specifics that require it to be reconfigured.
Not too familiar with OneNAND, from the code it has been understood that to set into sync mode, first it may have to set to async mode, read frequency from OneNAND, then setup sync mode for that frequency.
Quoted 18 lines
Quoted 8 lines
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1417
Quoted 1 line
arch/arm/mach-omap2/gpmc.c +1
-0+gpmc_setup_writeprotect (gpmc);Write protect is a pin and there is only one. Like the waitpins and CS signals this needs to be associated with a device. It would make sense that this is associated with the cs data.
As far as platform are concerned, it is associated with cs, it is only that while configuring CS, it is propagated such that it is done once.
Hmmm ... but here it looks like if write-protect is used you are going to turn it on. A feature like this seems that it does need to be handled by the device's driver. Enabling and disabling write-protect are functions that I would expect are exported to the device's driver and not directly enabled in the gpmc driver during probe. However, maybe is could be valid for the write protect to be enabled by default which could make sense. However, I don't see anywhere else in the driver to control it.
Quoted 2 lines
Shouldn't we warn on multiple devices trying to use write-protect when parsing their configuration?
Even if a single device sets write protect, kernel will log it.
Regards
Afzal
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Afzal,
Quoted 89 lines · Afzal
Hi Jon,
Quoted 6 lines · Jon
Quoted 6 lines
As mentioned in the cover letter,
"Additional features that currently boards in mainline does not make use of like, waitpin interrupt handling, changes to leverage revision 6 IP differences has not been incorporated."
Quoted 7 lines
Quoted 3 lines
Priority in this series is to convert into a driver, get all boards working on mainline. Once all boards are working with gpmc driver, these features which are not required for currently supported boards can be added later.
Yes, but I meant why 2 and not say 5? Anyway, I think that this should be marked with a comment like a TODO so it is clear that this needs to be re-visited.
Ok, it will be marked with TODO
Quoted 6 lines
Quoted 5 lines
Quoted 2 lines
I think that it make more sense to have the wait-pin information part of the
gpmc_cs_datastructure for the following reasons ...Waitpin information is indeed a part of cs as far as boards are concerned, it is only that it gets propogated to device
Quoted 6 lines
Why does the device's driver care? From my point of view, the wait-pin is just part of the interface setup/configuration. The external device may require this and assumes that this has been setup along with the CS and interface timing, but the device's driver should not care. Remember this is just a ready signal used to stall the access. Once configured, software should be unaware of it.
By device, it is referred to gpmc device which only gpmc driver is aware, the peripheral device's driver is not at all aware.
Quoted 9 lines
Quoted 9 lines
Quoted 3 lines
Also, any reason why
waitpin_polarityis an int? I see you define LOW as -1, but I not sure why LOW cannot be 0 as 0 is programmed into the register for an active low wait signal.Only intention is not to alter default waitpin polarity value, i.e. if any board does make use of it w/o knowledge of Kernel, I don't want to break it, there may be an argument saying that the board code is buggy, while if some board does so, it is, but don't want to break working one.
Quoted 7 lines
Quoted 1 line
Here unless user explicitly set the flag, it does nothing on polarity
Ok. Do such scenario's exist today? Please note that board code will be removed in the future and device-tree will replace. So if there are no cases today, I would not be concerned. Unless this could be something that has already been configured by the bootloader. However, in that case would be even call this function?
Let me check this, here only intent was to play safe, as I have only two boards to test.
Quoted 10 lines
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
+int
gpmc_cs_reconfigure(char *name, int id, struct gpmc_cs_data *cs)What scenario is this function used in? May be worth adding a comment about the function.
Ok, it was required for OneNAND, as it needs to reconfigure
Ok, but why is that? Unless this is something generic about one-nand I don't comprehend. I have a high-level understanding of one-nand, but I am not familiar with the specifics that require it to be reconfigured.
Not too familiar with OneNAND, from the code it has been understood that to set into sync mode, first it may have to set to async mode, read frequency from OneNAND, then setup sync mode for that frequency.
Quoted 18 lines
Quoted 8 lines
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 1417
Quoted 1 line
arch/arm/mach-omap2/gpmc.c +1
-0+gpmc_setup_writeprotect (gpmc);Write protect is a pin and there is only one. Like the waitpins and CS signals this needs to be associated with a device. It would make sense that this is associated with the cs data.
As far as platform are concerned, it is associated with cs, it is only that while configuring CS, it is propagated such that it is done once.
Hmmm ... but here it looks like if write-protect is used you are going to turn it on. A feature like this seems that it does need to be handled by the device's driver. Enabling and disabling write-protect are functions that I would expect are exported to the device's driver and not directly enabled in the gpmc driver during probe. However, maybe is could be valid for the write protect to be enabled by default which could make sense. However, I don't see anywhere else in the driver to control it.
Quoted 4 lines
Quoted 2 lines
Shouldn't we warn on multiple devices trying to use write-protect when parsing their configuration?
Even if a single device sets write protect, kernel will log it.
That does not seem sufficient. It should be flagged as an error.
Write protect is a resource like the CS and waitpins and so I would have thought that it should be reserved in the same way.
Jon
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Jon,
Quoted 19 lines · Jon
Quoted 19 lines
Quoted 18 lines
Quoted 6 lines
Quoted 3 lines
Write protect is a pin and there is only one. Like the waitpins and CS signals this needs to be associated with a device. It would make sense that this is associated with the cs data.
As far as platform are concerned, it is associated with cs, it is only that while configuring CS, it is propagated such that it is done once.
Hmmm ... but here it looks like if write-protect is used you are going to turn it on. A feature like this seems that it does need to be handled by the device's driver. Enabling and disabling write-protect are functions that I would expect are exported to the device's driver and not directly enabled in the gpmc driver during probe. However, maybe is could be valid for the write protect to be enabled by default which could make sense. However, I don't see anywhere else in the driver to control it.
Shouldn't we warn on multiple devices trying to use write-protect when parsing their configuration?
Quoted 6 lines
Quoted 1 line
Even if a single device sets write protect, kernel will log it.
That does not seem sufficient. It should be flagged as an error.
Write protect is a resource like the CS and waitpins and so I would have thought that it should be reserved in the same way.
Isn't it valid for multiple devices to make use of write protect pin ?
Regards
Afzal
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
In reply to Afzal MohammedHi Afzal,
On 05/01/2012 07:19 AM, Afzal Mohammed wrote:
[...]
Quoted 26 lines
arch/arm/mach-omap2/gpmc.c +17
-8+static int gpmc_setup_cs_waitpin (struct gpmc *gpmc,struct gpmc_device *gd, +unsigned cs,unsigned conf) +{ +u32 l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG1 ); +unsigned idx = ~0x0 ; +int polarity =0 ; - l =gpmc_read_reg (GPMC_REVISION ); -printk (KERN_INFO "GPMC revision %d.%d\n" , (l >>4 ) &0x0f , l &0x0f ); -/* Set smart idle mode and automatic L3 clock gating */ - l =gpmc_read_reg (GPMC_SYSCONFIG ); - l &=0x03 <<3 ; - l |= (0x02 <<3 ) | (1 <<0 ); -gpmc_write_reg (GPMC_SYSCONFIG , l); -gpmc_mem_init (); +switch (conf &GPMC_WAITPIN_MASK ) { +case GPMC_WAITPIN_0 : + idx =GPMC_WAITPIN_IDX0 ; +break ; +case GPMC_WAITPIN_1 : + idx =GPMC_WAITPIN_IDX1 ; +break ; +case GPMC_WAITPIN_2 : + idx =GPMC_WAITPIN_IDX2 ; +break ; +case GPMC_WAITPIN_3 :
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 948
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10
-0+ idx =GPMC_WAITPIN_IDX3 ; +break ; +/* no waitpin */ +case 0 : +break ; +default : +dev_err (gpmc->dev,"multiple waitpins selected on CS:%u\n" , cs); +return -EINVAL ; +break ; + }
Why not combined case 0 and default? Both are invalid configurations so just report invalid selection.
Quoted 13 lines
arch/arm/mach-omap2/gpmc.c +5
-7-/* initalize the irq_chained */ - irq =OMAP_GPMC_IRQ_BASE ; -for (cs =0 ; cs <GPMC_CS_NUM ; cs++) { -irq_set_chip_and_handler (irq, &dummy_irq_chip, - handle_simple_irq); -set_irq_flags (irq,IRQF_VALID ); - irq++; +switch (conf &GPMC_WAITPIN_POLARITY_MASK ) { +case GPMC_WAITPIN_ACTIVE_LOW : + polarity =LOW ; +break ; +case GPMC_WAITPIN_ACTIVE_HIGH :
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 964
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +9
-0+ polarity =HIGH ; +break ; +/* no waitpin */ +case 0 : +break ; +default : +dev_err (gpmc->dev,"waitpin polarity set to low & high\n" ); +return -EINVAL ; +break ; }
Again, combine case 0 and default as these are invalid.
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 966
Quoted 7 lines
arch/arm/mach-omap2/gpmc.c +1
-5- ret =request_irq (gpmc_irq, gpmc_handle_irq,IRQF_SHARED ,"gpmc" ,NULL ); -if (ret) -pr_err ("gpmc: irq-%d could not claim: err %d\n" , - gpmc_irq, ret); -return ret; +if (idx != ~0x0 ) {
If you combine the above cases, then you can drop the idx test here.
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 975
Quoted 9 lines
arch/arm/mach-omap2/gpmc.c +9
-0+if (gd->have_waitpin) { +if (gd->waitpin != idx || + gd->waitpin_polarity != polarity) { +dev_err (gpmc->dev,"error: conflict: waitpin %u with polarity %d on device %s.%d\n" , + gd->waitpin, gd->waitpin_polarity, + gd->name, gd->id); +return -EBUSY ; + } + }else {
Don't need the else as you are going to return in the above.
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 987
Quoted 12 lines
arch/arm/mach-omap2/gpmc.c +12
-0+ gd->have_waitpin = true; + gd->waitpin = idx; + gd->waitpin_polarity = polarity; + } + + l &= ~GPMC_CONFIG1_WAIT_PIN_SEL_MASK ; + l |=GPMC_CONFIG1_WAIT_PIN_SEL (idx); +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , l); + }else if (polarity) { +dev_err (gpmc->dev,"error: waitpin polarity specified with out wait pin number on device %s.%d\n" , + gd->name, gd->id); +return -EINVAL ;
Drop this else-if. The above switch statements will report the bad configuration. This seems a bit redundant.
Cheers
Jon
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Jon,
Quoted 18 lines · Jon
Quoted 18 lines
arch/arm/mach-omap2/gpmc.c +16
-2-gpmc_write_reg (GPMC_SYSCONFIG , l); -gpmc_mem_init (); +switch (conf &GPMC_WAITPIN_MASK ) { +case GPMC_WAITPIN_0 : + idx =GPMC_WAITPIN_IDX0 ; +break ; +case GPMC_WAITPIN_1 : + idx =GPMC_WAITPIN_IDX1 ; +break ; +case GPMC_WAITPIN_2 : + idx =GPMC_WAITPIN_IDX2 ; +break ; +case GPMC_WAITPIN_3 : + idx =GPMC_WAITPIN_IDX3 ; +break ; +/* no waitpin */ +case 0 : +break ;
Quoted 8 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 948
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c +5
-0+default : +dev_err (gpmc->dev,"multiple waitpins selected on CS:%u\n" , cs); +return -EINVAL ; +break ; + }Why not combined case 0 and default? Both are invalid configurations so just report invalid selection.
Case 0 is not invalid, a case where waitpin is not used, default refers to when a user selects multiple waitpins wrongly.
Quoted 18 lines
Quoted 18 lines
arch/arm/mach-omap2/gpmc.c +9
-7-/* initalize the irq_chained */ - irq =OMAP_GPMC_IRQ_BASE ; -for (cs =0 ; cs <GPMC_CS_NUM ; cs++) { -irq_set_chip_and_handler (irq, &dummy_irq_chip, - handle_simple_irq); -set_irq_flags (irq,IRQF_VALID ); - irq++; +switch (conf &GPMC_WAITPIN_POLARITY_MASK ) { +case GPMC_WAITPIN_ACTIVE_LOW : + polarity =LOW ; +break ; +case GPMC_WAITPIN_ACTIVE_HIGH : + polarity =HIGH ; +break ; +/* no waitpin */ +case 0 :
Quoted 8 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 964
Quoted 6 lines
arch/arm/mach-omap2/gpmc.c +5
-0+break ; +default : +dev_err (gpmc->dev,"waitpin polarity set to low & high\n" ); +return -EINVAL ; +break ; }Again, combine case 0 and default as these are invalid.
Similar to above
Quoted 12 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 975
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +9
-0+if (gd->have_waitpin) { +if (gd->waitpin != idx || + gd->waitpin_polarity != polarity) { +dev_err (gpmc->dev,"error: conflict: waitpin %u with polarity %d on device %s.%d\n" , + gd->waitpin, gd->waitpin_polarity, + gd->name, gd->id); +return -EBUSY ; + } + }else {Don't need the else as you are going to return in the above.
Not always, only in case of error
Quoted 16 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 987
Quoted 13 lines
arch/arm/mach-omap2/gpmc.c +12
-0+ gd->have_waitpin = true; + gd->waitpin = idx; + gd->waitpin_polarity = polarity; + } + + l &= ~GPMC_CONFIG1_WAIT_PIN_SEL_MASK ; + l |=GPMC_CONFIG1_WAIT_PIN_SEL (idx); +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , l); + }else if (polarity) { +dev_err (gpmc->dev,"error: waitpin polarity specified with out wait pin number on device %s.%d\n" , + gd->name, gd->id); +return -EINVAL ;Drop this else-if. The above switch statements will report the bad configuration. This seems a bit redundant.
This is required as switch statements will not report error if polarity is specified, w/o waitpin to be used.
Regards
Afzal
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Afzal,
Quoted 30 lines · Afzal
Hi Jon,
Quoted 18 lines · Jon
Quoted 18 lines
arch/arm/mach-omap2/gpmc.c +16
-2-gpmc_write_reg (GPMC_SYSCONFIG , l); -gpmc_mem_init (); +switch (conf &GPMC_WAITPIN_MASK ) { +case GPMC_WAITPIN_0 : + idx =GPMC_WAITPIN_IDX0 ; +break ; +case GPMC_WAITPIN_1 : + idx =GPMC_WAITPIN_IDX1 ; +break ; +case GPMC_WAITPIN_2 : + idx =GPMC_WAITPIN_IDX2 ; +break ; +case GPMC_WAITPIN_3 : + idx =GPMC_WAITPIN_IDX3 ; +break ; +/* no waitpin */ +case 0 : +break ;Quoted 8 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 948
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c +5
-0+default : +dev_err (gpmc->dev,"multiple waitpins selected on CS:%u\n" , cs); +return -EINVAL ; +break ; + }Why not combined case 0 and default? Both are invalid configurations so just report invalid selection.
Quoted 2 lines
Case 0 is not invalid, a case where waitpin is not used, default refers to when a user selects multiple waitpins wrongly.
Ok. Then for case 0, just return here. If the polarity is set, you could print an error here.
Quoted 27 lines
Quoted 18 lines
Quoted 18 lines
arch/arm/mach-omap2/gpmc.c +9
-7-/* initalize the irq_chained */ - irq =OMAP_GPMC_IRQ_BASE ; -for (cs =0 ; cs <GPMC_CS_NUM ; cs++) { -irq_set_chip_and_handler (irq, &dummy_irq_chip, - handle_simple_irq); -set_irq_flags (irq,IRQF_VALID ); - irq++; +switch (conf &GPMC_WAITPIN_POLARITY_MASK ) { +case GPMC_WAITPIN_ACTIVE_LOW : + polarity =LOW ; +break ; +case GPMC_WAITPIN_ACTIVE_HIGH : + polarity =HIGH ; +break ; +/* no waitpin */ +case 0 :Quoted 8 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 964
Quoted 6 lines
arch/arm/mach-omap2/gpmc.c +5
-0+break ; +default : +dev_err (gpmc->dev,"waitpin polarity set to low & high\n" ); +return -EINVAL ; +break ; }Again, combine case 0 and default as these are invalid.
Quoted 1 line
Similar to above
If you return above, then case 0 is not needed.
Quoted 13 lines
Quoted 12 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 975
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +9
-0+if (gd->have_waitpin) { +if (gd->waitpin != idx || + gd->waitpin_polarity != polarity) { +dev_err (gpmc->dev,"error: conflict: waitpin %u with polarity %d on device %s.%d\n" , + gd->waitpin, gd->waitpin_polarity, + gd->name, gd->id); +return -EBUSY ; + } + }else {Don't need the else as you are going to return in the above.
Quoted 1 line
Not always, only in case of error
Ok, but seems that it can be simplified a little.
What happens if a device uses more than one wait-pin? In other words a device with two chip-selects that uses two wait-pins?
Quoted 17 lines
Quoted 16 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 987
Quoted 13 lines
arch/arm/mach-omap2/gpmc.c +12
-0+ gd->have_waitpin = true; + gd->waitpin = idx; + gd->waitpin_polarity = polarity; + } + + l &= ~GPMC_CONFIG1_WAIT_PIN_SEL_MASK ; + l |=GPMC_CONFIG1_WAIT_PIN_SEL (idx); +gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , l); + }else if (polarity) { +dev_err (gpmc->dev,"error: waitpin polarity specified with out wait pin number on device %s.%d\n" , + gd->name, gd->id); +return -EINVAL ;Drop this else-if. The above switch statements will report the bad configuration. This seems a bit redundant.
Quoted 2 lines
This is required as switch statements will not report error if polarity is specified, w/o waitpin to be used.
Ok, may be you can print that above when you detect that there are no wait-pins selected.
Jon
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Jon,
Quoted 12 lines · Jon
Quoted 12 lines
Quoted 11 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 948
Quoted 8 lines
arch/arm/mach-omap2/gpmc.c +8
-0+/* no waitpin */ +case 0 : +break ; +default : +dev_err (gpmc->dev,"multiple waitpins selected on CS:%u\n" , cs); +return -EINVAL ; +break ; + }Why not combined case 0 and default? Both are invalid configurations so just report invalid selection.
Quoted 5 lines
Quoted 2 lines
Case 0 is not invalid, a case where waitpin is not used, default refers to when a user selects multiple waitpins wrongly.
Ok. Then for case 0, just return here. If the polarity is set, you could print an error here.
Different ways of doing things, this looks cleaner to me as already it is checked, and time of execution in both cases would not differ much.
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 975
Quoted 9 lines
arch/arm/mach-omap2/gpmc.c +9
-0+if (gd->have_waitpin) { +if (gd->waitpin != idx || + gd->waitpin_polarity != polarity) { +dev_err (gpmc->dev,"error: conflict: waitpin %u with polarity %d on device %s.%d\n" , + gd->waitpin, gd->waitpin_polarity, + gd->name, gd->id); +return -EBUSY ; + } + }else {Don't need the else as you are going to return in the above.
Quoted 6 lines
Quoted 1 line
Not always, only in case of error
Ok, but seems that it can be simplified a little.
What happens if a device uses more than one wait-pin? In other words a device with two chip-selects that uses two wait-pins?
Please re-read http://www.mail-archive.com/linux-omap at vger.kernel.org/msg67702.html and your reply
Regards
Afzal
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Afzal,
Quoted 16 lines · Afzal
Hi Jon,
Quoted 12 lines · Jon
Quoted 12 lines
Quoted 11 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 948
Quoted 8 lines
arch/arm/mach-omap2/gpmc.c +8
-0+/* no waitpin */ +case 0 : +break ; +default : +dev_err (gpmc->dev,"multiple waitpins selected on CS:%u\n" , cs); +return -EINVAL ; +break ; + }Why not combined case 0 and default? Both are invalid configurations so just report invalid selection.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Case 0 is not invalid, a case where waitpin is not used, default refers to when a user selects multiple waitpins wrongly.
Ok. Then for case 0, just return here. If the polarity is set, you could print an error here.
Different ways of doing things, this looks cleaner to me as already it is checked, and time of execution in both cases would not differ much.
Sure. However, I think that this could be simplified so that it is easier to read. At a minimum you may wish to add some comments to explain the purposes of the multi-level if-statements as it is not intuitive for the reader.
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
Quoted 11 lines
arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 975
Quoted 9 lines
arch/arm/mach-omap2/gpmc.c +9
-0+if (gd->have_waitpin) { +if (gd->waitpin != idx || + gd->waitpin_polarity != polarity) { +dev_err (gpmc->dev,"error: conflict: waitpin %u with polarity %d on device %s.%d\n" , + gd->waitpin, gd->waitpin_polarity, + gd->name, gd->id); +return -EBUSY ; + } + }else {Don't need the else as you are going to return in the above.
Not always, only in case of error
Quoted 7 lines
Quoted 4 lines
Ok, but seems that it can be simplified a little.
What happens if a device uses more than one wait-pin? In other words a device with two chip-selects that uses two wait-pins?
Please re-read http://www.mail-archive.com/linux-omap at vger.kernel.org/msg67702.html and your reply
Ok thats fine. Sorry for my repeated questions, but I think that this just highlights that this code is not clear in it purpose. So again may be some comments would make this all clearer.
Jon
PATCH v4 1/39 ARM: OMAP2+: gpmc: driver conversion
Hi Jon,
Quoted 7 lines · Jon
Quoted 2 lines
Different ways of doing things, this looks cleaner to me as already it is checked, and time of execution in both cases would not differ much.
Sure. However, I think that this could be simplified so that it is easier to read. At a minimum you may wish to add some comments to explain the purposes of the multi-level if-statements as it is not intuitive for the reader.
Ok
Quoted 9 lines
Quoted 5 lines
Quoted 2 lines
What happens if a device uses more than one wait-pin? In other words a device with two chip-selects that uses two wait-pins?
Please re-read http://www.mail-archive.com/linux-omap at vger.kernel.org/msg67702.html and your reply
Ok thats fine. Sorry for my repeated questions, but I think that this just highlights that this code is not clear in it purpose. So again may be some comments would make this all clearer.
Ok
Regards
Afzal
PATCH v4 2/39 ARM: OMAP2+: gpmc: Adapt to HWMOD
In reply to Afzal MohammedCreate API for platforms to adapt gpmc to HWMOD
--- arch/arm/mach-omap2/gpmc.c | 52 +++++++++++++++++++++++--------- arch/arm/plat-omap/include/plat/gpmc.h | 1 + 2 files changed, 38 insertions(+), 15 deletions(-)
arch/arm/mach-omap2/gpmc.c +37 -15
@@ -33,6 +33,8 @@#include <plat/sdrc.h> +#include <plat/omap_device.h> +/* GPMC register offsets */ #define GPMC_REVISION 0x00#define GPMC_SYSCONFIG 0x10
@@ -276,6 +278,31 @@ unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)return ticks *gpmc_get_fclk_period () /1000 ; } +int __init omap_init_gpmc (struct gpmc_pdata *pdata) +{ +struct omap_hwmod *oh; +struct platform_device *pdev; +char *name ="omap-gpmc" ; +char *oh_name ="gpmc" ; + + pdata->clk_prd =gpmc_get_fclk_period (); + + oh =omap_hwmod_lookup (oh_name); +if (!oh) { +pr_err ("Could not look up %s\n" , oh_name); +return -ENODEV ; + } + + pdev =omap_device_build (name,-1 , oh, pdata, +sizeof (*pdata),NULL ,0 ,0 ); +if (IS_ERR (pdev)) { +WARN (1 ,"Can't build omap_device for %s:%s.\n" , + name, oh->name); +return PTR_ERR (pdev); + } + +return 0 ; +}#ifdef DEBUG static int set_gpmc_timing_reg (int cs,int reg,int st_bit,int end_bit,int time,const char *name)
@@ -843,24 +870,19 @@ static __devinit void gpmc_mem_init(void)static int __init gpmc_init (void ) { -int ret = -EINVAL ; -char *ck =NULL ; - -if (cpu_is_omap24xx ()) { - ck ="core_l3_ck" ; - }else if (cpu_is_omap34xx ()) { - ck ="gpmc_fck" ; - }else if (cpu_is_omap44xx ()) { - ck ="gpmc_ck" ; - } +char *oh_name ="gpmc" ; +struct omap_hwmod *oh; -if (WARN_ON (!ck)) -return ret; + oh =omap_hwmod_lookup (oh_name); +if (!oh) { +pr_err ("Could not look up %s\n" , oh_name); +return -ENODEV ; + } - gpmc_l3_clk =clk_get (NULL , ck); + gpmc_l3_clk =clk_get (NULL , oh->main_clk);if (IS_ERR (gpmc_l3_clk)) { -printk (KERN_ERR "Could not get GPMC clock %s\n" , ck); -BUG (); +pr_err ("error: clk_get on %s\n" , oh->main_clk); +return -EINVAL ; }clk_enable (gpmc_l3_clk);
arch/arm/plat-omap/include/plat/gpmc.h +1 -0
@@ -217,6 +217,7 @@ struct gpmc_pdata { };extern int gpmc_cs_reconfigure (char *name,int id,struct gpmc_cs_data *cs); +extern int omap_init_gpmc (struct gpmc_pdata *pdata);extern unsigned int gpmc_ns_to_ticks (unsigned int time_ns);extern unsigned int gpmc_ps_to_ticks (unsigned int time_ps);
Signature · 1 line
1.7.10
PATCH v4 2/39 ARM: OMAP2+: gpmc: Adapt to HWMOD
Hi Afzal,
Quoted 23 lines · Afzal Mohammed
Create API for platforms to adapt gpmc to HWMOD
Signed-off-by Afzal Mohammed <[email protected]>--- arch/arm/mach-omap2/gpmc.c | 52 +++++++++++++++++++++++--------- arch/arm/plat-omap/include/plat/gpmc.h | 1 + 2 files changed, 38 insertions(+), 15 deletions(-)arch/arm/mach-omap2/gpmc.c +2
-0@@ -33,6 +33,8 @@#include <plat/sdrc.h> +#include <plat/omap_device.h> +/* GPMC register offsets */ #define GPMC_REVISION 0x00#define GPMC_SYSCONFIG 0x10@@ -276,6 +278,31 @@ unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)return ticks *gpmc_get_fclk_period () /1000 ;
arch/arm/mach-omap2/gpmc.c unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns) · line 288
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +8
-0} +int __init omap_init_gpmc (struct gpmc_pdata *pdata) +{ +struct omap_hwmod *oh; +struct platform_device *pdev; +char *name ="omap-gpmc" ; +char *oh_name ="gpmc" ; + + pdata->clk_prd =gpmc_get_fclk_period ();
Does this need to be done here? May be this should be done in the probe function. You could store the handle to the main clk in the pdata.
Quoted 45 lines
arch/arm/mach-omap2/gpmc.c +24
-12+ + oh =omap_hwmod_lookup (oh_name); +if (!oh) { +pr_err ("Could not look up %s\n" , oh_name); +return -ENODEV ; + } + + pdev =omap_device_build (name,-1 , oh, pdata, +sizeof (*pdata),NULL ,0 ,0 ); +if (IS_ERR (pdev)) { +WARN (1 ,"Can't build omap_device for %s:%s.\n" , + name, oh->name); +return PTR_ERR (pdev); + } + +return 0 ; +}#ifdef DEBUG static int set_gpmc_timing_reg (int cs,int reg,int st_bit,int end_bit,int time,const char *name)@@ -843,24 +870,19 @@ static __devinit void gpmc_mem_init(void)static int __init gpmc_init (void ) { -int ret = -EINVAL ; -char *ck =NULL ; - -if (cpu_is_omap24xx ()) { - ck ="core_l3_ck" ; - }else if (cpu_is_omap34xx ()) { - ck ="gpmc_fck" ; - }else if (cpu_is_omap44xx ()) { - ck ="gpmc_ck" ; - } +char *oh_name ="gpmc" ; +struct omap_hwmod *oh; -if (WARN_ON (!ck)) -return ret; + oh =omap_hwmod_lookup (oh_name); +if (!oh) { +pr_err ("Could not look up %s\n" , oh_name); +return -ENODEV ; + }
arch/arm/mach-omap2/gpmc.c static __devinit void gpmc_mem_init(void) · line 888
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +3
-3- gpmc_l3_clk =clk_get (NULL , ck); + gpmc_l3_clk =clk_get (NULL , oh->main_clk);if (IS_ERR (gpmc_l3_clk)) { -printk (KERN_ERR "Could not get GPMC clock %s\n" , ck); -BUG (); +pr_err ("error: clk_get on %s\n" , oh->main_clk); +return -EINVAL ; }clk_enable (gpmc_l3_clk);
I would have thought we should be able to remove the gpmc_init function completely by now. Most of the code should be moved to the probe function.
Also now with hwmod in place, we should be able to remove the clk_enable/disable functions and use the pm_runtime APIs instead.
Cheers
Jon
PATCH v4 2/39 ARM: OMAP2+: gpmc: Adapt to HWMOD
Hi Jon,
Quoted 5 lines · Jon
arch/arm/mach-omap2/gpmc.c unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns) · line 288
Quoted 2 lines
arch/arm/mach-omap2/gpmc.c +2
-0+ + pdata->clk_prd =gpmc_get_fclk_period ();Does this need to be done here? May be this should be done in the probe function. You could store the handle to the main clk in the pdata.
This is done so that migration of gpmc driver to the drivers folder would be smooth, remember that this function will still live here.
Quoted 11 lines
arch/arm/mach-omap2/gpmc.c static __devinit void gpmc_mem_init(void) · line 888
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c +2
-0+pr_err ("error: clk_get on %s\n" , oh->main_clk); +return -EINVAL ; }clk_enable (gpmc_l3_clk);I would have thought we should be able to remove the
gpmc_initfunction completely by now. Most of the code should be moved to the probe function.Also now with hwmod in place, we should be able to remove the clk_enable/disable functions and use the
pm_runtimeAPIs instead.
There was no plan to add rpm in this series, but now that you have brought it up, I will adapt the driver to rpm.
Regards
Afzal
PATCH v4 2/39 ARM: OMAP2+: gpmc: Adapt to HWMOD
Hi Afzal,
Quoted 11 lines · Afzal
Hi Jon,
Quoted 5 lines · Jon
arch/arm/mach-omap2/gpmc.c unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns) · line 288
Quoted 2 lines
arch/arm/mach-omap2/gpmc.c +2
-0+ + pdata->clk_prd =gpmc_get_fclk_period ();Does this need to be done here? May be this should be done in the probe function. You could store the handle to the main clk in the pdata.
This is done so that migration of gpmc driver to the drivers folder would be smooth, remember that this function will still live here.
Sure, but why call this here?
Quoted 9 lines
Quoted 9 lines
arch/arm/mach-omap2/gpmc.c static __devinit void gpmc_mem_init(void) · line 888
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c +2
-0+pr_err ("error: clk_get on %s\n" , oh->main_clk); +return -EINVAL ; }clk_enable (gpmc_l3_clk);I would have thought we should be able to remove the
gpmc_initfunction completely by now. Most of the code should be moved to the probe function.
Quoted 5 lines
Quoted 2 lines
Also now with hwmod in place, we should be able to remove the clk_enable/disable functions and use the
pm_runtimeAPIs instead.There was no plan to add rpm in this series, but now that you have brought it up, I will adapt the driver to rpm.
Ok, great.
Jon
PATCH v4 2/39 ARM: OMAP2+: gpmc: Adapt to HWMOD
Hi Jon,
Quoted 10 lines · Jon
Quoted 8 lines
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns) · line 288
Quoted 2 lines
arch/arm/mach-omap2/gpmc.c +2
-0+ + pdata->clk_prd =gpmc_get_fclk_period ();Does this need to be done here? May be this should be done in the probe function. You could store the handle to the main clk in the pdata.
This is done so that migration of gpmc driver to the drivers folder would be smooth, remember that this function will still live here.
Sure, but why call this here?
Clk_prd is a platform data passed to the driver, so platform code updates it, where else can it be done ?
Regards
Afzal
PATCH v4 2/39 ARM: OMAP2+: gpmc: Adapt to HWMOD
Hi Afzal,
Quoted 9 lines · Afzal
Hi Jon,
Quoted 6 lines · Jon
Quoted 6 lines
Quoted 5 lines
arch/arm/mach-omap2/gpmc.c unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns) · line 288
Quoted 2 lines
arch/arm/mach-omap2/gpmc.c +2
-0+ + pdata->clk_prd =gpmc_get_fclk_period ();Does this need to be done here? May be this should be done in the probe function. You could store the handle to the main clk in the pdata.
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
This is done so that migration of gpmc driver to the drivers folder would be smooth, remember that this function will still live here.
Sure, but why call this here?
Clk_prdis a platform data passed to the driver, so platform code updates it, where else can it be done ?
The point is that you can pass what ever you like. You do not need to pass the frequency you can pass the clock handle instead.
What happens it the clk_get() of the gpmc_l3_clk fails during the init?
In fact if you migrate to runtime pm then we should not have the clk_get in the gpmc_init any more.
Jon
PATCH v4 2/39 ARM: OMAP2+: gpmc: Adapt to HWMOD
Hi Jon,
Quoted 5 lines · Jon
Quoted 2 lines
Clk_prdis a platform data passed to the driver, so platform code updates it, where else can it be done ?The point is that you can pass what ever you like. You do not need to pass the frequency you can pass the clock handle instead.
As clk rate is required in platform code for timing calculation, and already available, period was passed
Quoted 2 lines
What happens it the
clk_get()of thegpmc_l3_clkfails during the init?
Thanks for bringing this point, invalid clk_prd has to be handled by driver.
Quoted 3 lines
In fact if you migrate to runtime pm then we should not have the
clk_getin thegpmc_initany more.
Even if converted to RPM, to get clk rate, clk_get has to be done somewhere, right ?
Regards
Afzal
PATCH v4 2/39 ARM: OMAP2+: gpmc: Adapt to HWMOD
Hi Afzal,
Quoted 4 lines · Afzal
Hi Jon,
On Mon, May 07, 2012 at 21:42:35, Hunter, Jon wrote:
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Clk_prdis a platform data passed to the driver, so platform code updates it, where else can it be done ?The point is that you can pass what ever you like. You do not need to pass the frequency you can pass the clock handle instead.
As clk rate is required in platform code for timing calculation, and already available, period was passed
Sure.
Quoted 11 lines
Quoted 2 lines
What happens it the
clk_get()of thegpmc_l3_clkfails during the init?Thanks for bringing this point, invalid
clk_prdhas to be handled by driver.Quoted 3 lines
In fact if you migrate to runtime pm then we should not have the
clk_getin thegpmc_initany more.Even if converted to RPM, to get clk rate,
clk_gethas to be done somewhere, right ?
Yes exactly. However, you could now do this in the driver itself like the probe function. Or may be just pass the frequency of the gpmc fclk to the driver and let the driver convert to the period. No reason we need to convert to the period outside of the driver. Hence, we can keep the function to do the conversion static in the driver and don't need to expose externally.
Jon
PATCH v4 2/39 ARM: OMAP2+: gpmc: Adapt to HWMOD
Hi Jon,
Quoted 6 lines · Jon
Quoted 5 lines
Quoted 2 lines
In fact if you migrate to runtime pm then we should not have the
clk_getin thegpmc_initany more.Even if converted to RPM, to get clk rate,
clk_gethas to be done somewhere, right ?
Quoted 6 lines
Yes exactly. However, you could now do this in the driver itself like the probe function. Or may be just pass the frequency of the gpmc fclk to the driver and let the driver convert to the period. No reason we need to convert to the period outside of the driver. Hence, we can keep the function to do the conversion static in the driver and don't need to expose externally.
But platform need period before driver is probed (for calculating peripheral timings to be passed for driver)
Regards
Afzal
PATCH v4 3/39 ARM: OMAP2+: gpmc: register details for nand driver
In reply to Afzal MohammedIf peripheral connected is NAND, update NAND drivers platform data with NAND related register addresses so that NAND driver can handle GPMC NAND operations by itself
--- arch/arm/mach-omap2/gpmc.c | 25 +++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/gpmc.h | 16 ++++++++++++++++ arch/arm/plat-omap/include/plat/nand.h | 1 + 3 files changed, 42 insertions(+)
arch/arm/mach-omap2/gpmc.c +25 -0
@@ -30,6 +30,7 @@#include <asm/mach-types.h> #include <plat/gpmc.h> +#include <plat/nand.h> #include <plat/sdrc.h>
@@ -891,6 +892,28 @@ static int __init gpmc_init(void) }postcore_initcall (gpmc_init); +static __devinit void gpmc_update_nand_reg (struct gpmc *gpmc, +struct omap_nand_platform_data *nand) +{ +int cs = nand->cs; + + nand->reg.gpmc_status = gpmc->io_base +GPMC_STATUS ; + nand->reg.gpmc_nand_command = gpmc->io_base +GPMC_CS0_OFFSET + +GPMC_CS_NAND_COMMAND +GPMC_CS_SIZE * cs; + nand->reg.gpmc_nand_address = gpmc->io_base +GPMC_CS0_OFFSET + +GPMC_CS_NAND_ADDRESS +GPMC_CS_SIZE * cs; + nand->reg.gpmc_nand_data = gpmc->io_base +GPMC_CS0_OFFSET + +GPMC_CS_NAND_DATA +GPMC_CS_SIZE * cs; + nand->reg.gpmc_prefetch_config1 = gpmc->io_base +GPMC_PREFETCH_CONFIG1 ; + nand->reg.gpmc_prefetch_config2 = gpmc->io_base +GPMC_PREFETCH_CONFIG2 ; + nand->reg.gpmc_prefetch_control = gpmc->io_base +GPMC_PREFETCH_CONTROL ; + nand->reg.gpmc_prefetch_status = gpmc->io_base +GPMC_PREFETCH_STATUS ; + nand->reg.gpmc_ecc_config = gpmc->io_base +GPMC_ECC_CONFIG ; + nand->reg.gpmc_ecc_control = gpmc->io_base +GPMC_ECC_CONTROL ; + nand->reg.gpmc_ecc_size_config = gpmc->io_base +GPMC_ECC_SIZE_CONFIG ; + nand->reg.gpmc_ecc1_result = gpmc->io_base +GPMC_ECC1_RESULT ; +} +static inline int gpmc_waitpin_is_reserved (struct gpmc *gpmc,unsigned waitpin) {return gpmc->waitpin_map & (0x1 << waitpin);
@@ -1427,6 +1450,8 @@ static __devinit int gpmc_probe(struct platform_device *pdev)for (i =0 , gdq = gp->device_pdata, gd = gpmc->device; (i < gp->num_device) && (*gdq); i++, gdq++) { +if ((*gdq)->is_nand) +gpmc_update_nand_reg (gpmc, (*gdq)->pdata); ret =gpmc_setup_device (gpmc, gd, *gdq);if (IS_ERR_VALUE (ret)) dev_err(gpmc->dev, "gpmc setup on %s failed\n",
arch/arm/plat-omap/include/plat/gpmc.h +16 -0
@@ -207,6 +207,7 @@ struct gpmc_device_pdata {unsigned per_res_cnt;struct gpmc_cs_data *cs_data;unsigned num_cs; +bool is_nand; };struct gpmc_pdata {
@@ -216,6 +217,21 @@ struct gpmc_pdata {struct gpmc_device_pdata **device_pdata; }; +struct gpmc_nand_regs { +void __iomem *gpmc_status; +void __iomem *gpmc_nand_command; +void __iomem *gpmc_nand_address; +void __iomem *gpmc_nand_data; +void __iomem *gpmc_prefetch_config1; +void __iomem *gpmc_prefetch_config2; +void __iomem *gpmc_prefetch_control; +void __iomem *gpmc_prefetch_status; +void __iomem *gpmc_ecc_config; +void __iomem *gpmc_ecc_control; +void __iomem *gpmc_ecc_size_config; +void __iomem *gpmc_ecc1_result; +}; +extern int gpmc_cs_reconfigure (char *name,int id,struct gpmc_cs_data *cs);extern int omap_init_gpmc (struct gpmc_pdata *pdata);
arch/arm/plat-omap/include/plat/nand.h +1 -0
@@ -29,6 +29,7 @@ struct omap_nand_platform_data {unsigned long phys_base;int devsize;enum omap_ecc ecc_opt; +struct gpmc_nand_regs reg; };/* minimum size for IO mapping */
Signature · 1 line
1.7.10
PATCH v4 4/39 ARM: OMAP2+: gpmc: Acquire NAND CS value
In reply to Afzal MohammedSome boards depend on bootloader to update chip select value for NAND. It is felt that Kernel should not depend on bootloader to get CS, as for a particular board CS is hardwired and is fixed, hence this can directly be updated in Kernel. But as CS value for boards that depend on this behaviour is not available, educate gpmc driver to acquire chip select value for NAND. this ideally should be removed once CS for those boards are available.
--- arch/arm/mach-omap2/gpmc.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/gpmc.c +31 -1
@@ -892,6 +892,30 @@ static int __init gpmc_init(void) }postcore_initcall (gpmc_init); +static __devinit int gpmc_acquire_nand_cs (struct gpmc *gpmc, +struct gpmc_device_pdata *gdp) +{ +int cs =0 ; +struct omap_nand_platform_data *nand = gdp->pdata; + +if ((nand->cs >=0 ) && (nand->cs <GPMC_CS_NUM )) +return 0 ; + +while (cs <GPMC_CS_NUM ) { +u32 l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG1 ); + +if ((l &GPMC_CONFIG1_DEVICETYPE (~0 )) == +GPMC_CONFIG1_DEVICETYPE_NAND ) { +dev_info (gpmc->dev,"found NAND on CS: %d\n" , cs); + nand->cs = cs; + gdp->cs_data->cs = cs; +return 0 ; + } + cs++; + } +return -ENODEV ; +} +static __devinit void gpmc_update_nand_reg (struct gpmc *gpmc,struct omap_nand_platform_data *nand) {
@@ -1450,8 +1474,14 @@ static __devinit int gpmc_probe(struct platform_device *pdev)for (i =0 , gdq = gp->device_pdata, gd = gpmc->device; (i < gp->num_device) && (*gdq); i++, gdq++) { -if ((*gdq)->is_nand) +if ((*gdq)->is_nand) { + ret =gpmc_acquire_nand_cs (gpmc, *gdq); +if (IS_ERR_VALUE (ret)) { +dev_err (gpmc->dev,"CS error: %d\n" , ret); +continue ; + }gpmc_update_nand_reg (gpmc, (*gdq)->pdata); + } ret =gpmc_setup_device (gpmc, gd, *gdq);if (IS_ERR_VALUE (ret)) dev_err(gpmc->dev, "gpmc setup on %s failed\n",
Signature · 1 line
1.7.10
PATCH v4 4/39 ARM: OMAP2+: gpmc: Acquire NAND CS value
Hi Afzal,
Quoted 7 lines · Afzal Mohammed
Some boards depend on bootloader to update chip select value for NAND. It is felt that Kernel should not depend on bootloader to get CS, as for a particular board CS is hardwired and is fixed, hence this can directly be updated in Kernel. But as CS value for boards that depend on this behaviour is not available, educate gpmc driver to acquire chip select value for NAND. this ideally should be removed once CS for those boards are available.
Do you know how many boards require this? If so which are those boards?
Quoted 41 lines
Signed-off-by Afzal Mohammed <[email protected]>--- arch/arm/mach-omap2/gpmc.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-)arch/arm/mach-omap2/gpmc.c +24
-0@@ -892,6 +892,30 @@ static int __init gpmc_init(void) }postcore_initcall (gpmc_init); +static __devinit int gpmc_acquire_nand_cs (struct gpmc *gpmc, +struct gpmc_device_pdata *gdp) +{ +int cs =0 ; +struct omap_nand_platform_data *nand = gdp->pdata; + +if ((nand->cs >=0 ) && (nand->cs <GPMC_CS_NUM )) +return 0 ; + +while (cs <GPMC_CS_NUM ) { +u32 l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG1 ); + +if ((l &GPMC_CONFIG1_DEVICETYPE (~0 )) == +GPMC_CONFIG1_DEVICETYPE_NAND ) { +dev_info (gpmc->dev,"found NAND on CS: %d\n" , cs); + nand->cs = cs; + gdp->cs_data->cs = cs; +return 0 ; + } + cs++; + } +return -ENODEV ; +} +static __devinit void gpmc_update_nand_reg (struct gpmc *gpmc,struct omap_nand_platform_data *nand) {
arch/arm/mach-omap2/gpmc.c static __devinit int gpmc_probe(struct platform_device *pdev) · line 1482
Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +6
-1@@ -1450,8 +1474,14 @@ static __devinit int gpmc_probe(struct platform_device *pdev)for (i =0 , gdq = gp->device_pdata, gd = gpmc->device; (i < gp->num_device) && (*gdq); i++, gdq++) { -if ((*gdq)->is_nand) +if ((*gdq)->is_nand) { + ret =gpmc_acquire_nand_cs (gpmc, *gdq); +if (IS_ERR_VALUE (ret)) { +dev_err (gpmc->dev,"CS error: %d\n" , ret); +continue ; + }
Should this code be marked with a FIXME?
Cheers
Jon
PATCH v4 4/39 ARM: OMAP2+: gpmc: Acquire NAND CS value
Hi Jon,
Quoted 9 lines · Jon
Quoted 7 lines
Some boards depend on bootloader to update chip select value for NAND. It is felt that Kernel should not depend on bootloader to get CS, as for a particular board CS is hardwired and is fixed, hence this can directly be updated in Kernel. But as CS value for boards that depend on this behaviour is not available, educate gpmc driver to acquire chip select value for NAND. this ideally should be removed once CS for those boards are available.
Do you know how many boards require this? If so which are those boards?
devkit8000, beagle board, omap3touchbook, overo.
Beagle board, found out to be zero.
Quoted 1 line
Should this code be marked with a FIXME?
Will let Tony decide it.
Regards
Afzal
RE: [PATCH v4 04/39] ARM: OMAP2+: gpmc: Acquire NAND CS value
Hi All,
Quoted 8 lines · Afzal
Quoted 8 lines
Quoted 7 lines
Some boards depend on bootloader to update chip select value for NAND. It is felt that Kernel should not depend on bootloader to get CS, as for a particular board CS is hardwired and is fixed, hence this can directly be updated in Kernel. But as CS value for boards that depend on this behaviour is not available, educate gpmc driver to acquire chip select value for NAND. this ideally should be removed once CS for those boards are available.
Quoted 5 lines
Quoted 1 line
Do you know how many boards require this? If so which are those boards?
devkit8000, beagle board, omap3touchbook, overo.
Beagle board, found out to be zero.
I need a help.
Can someone familiar with boards - devkit8000, omap3touchbook, overo boards, let me know GPMC CS on which NAND is connected.
Hi Tony,
I am planning to provide actual CS # used for NAND on above boards instead of finding the value at runtime. Is there any reason that NAND CS# is found out at runtime ? (hence remove necessity of omap_nand_flash_init()).
Presence of this also causes an additional dependency of bootloader.
As CS # depends on wiring on the board, my understanding is that it will be fixed for a given board. Are you ok if acquiring NAND CS # is removed ?
Removal of this helps in simplifying gpmc driver (undergoing conversion).
Regards
Afzal
Re: [PATCH v4 04/39] ARM: OMAP2+: gpmc: Acquire NAND CS value
Hello Afzal,
Quoted 11 lines · Afzal
Hi All,
Quoted 7 lines · Afzal
Quoted 7 lines
Quoted 7 lines
Some boards depend on bootloader to update chip select value for NAND. It is felt that Kernel should not depend on bootloader to get CS, as for a particular board CS is hardwired and is fixed, hence this can directly be updated in Kernel. But as CS value for boards that depend on this behaviour is not available, educate gpmc driver to acquire chip select value for NAND. this ideally should be removed once CS for those boards are available.
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
Do you know how many boards require this? If so which are those boards?
devkit8000, beagle board, omap3touchbook, overo.
Beagle board, found out to be zero.
I need a help.
Can someone familiar with boards - devkit8000, omap3touchbook, overo boards, let me know GPMC CS on which NAND is connected.
On Devkit8000 the NAND is connected to CS0.
I thought that all NAND devices for booting are connected to CS0, because of ROM code?
According to spruf98w.pdf:
25.4.7.4 NAND
...
* The device is connected to CS0.
...
Regards,
Thomas
Quoted 19 lines
Hi Tony,
I am planning to provide actual CS # used for NAND on above boards instead of finding the value at runtime. Is there any reason that NAND CS# is found out at runtime ? (hence remove necessity of
omap_nand_flash_init()).Presence of this also causes an additional dependency of bootloader.
As CS # depends on wiring on the board, my understanding is that it will be fixed for a given board. Are you ok if acquiring NAND CS # is removed ?
Removal of this helps in simplifying gpmc driver (undergoing conversion).
Regards
Afzal
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
RE: [PATCH v4 04/39] ARM: OMAP2+: gpmc: Acquire NAND CS value
Hi Thomas,
Quoted 5 lines · Thomas Weber
Quoted 4 lines
I need a help.
Can someone familiar with boards - devkit8000, omap3touchbook, overo boards, let me know GPMC CS on which NAND is connected.
On Devkit8000 the NAND is connected to CS0.
Thanks for the information
Quoted 8 lines
I thought that all NAND devices for booting are connected to CS0, because of ROM code?
According to spruf98w.pdf:
25.4.7.4 NAND
...
* The device is connected to CS0.
Yes, expecting they should be, looking for confirmation.
Regards
Afzal
Tony Lindgren
maintainerRe: [PATCH v4 04/39] ARM: OMAP2+: gpmc: Acquire NAND CS value
In reply to Mohammed, AfzalQuoted 6 lines · Mohammed, Afzal
Hi Tony,
I am planning to provide actual CS # used for NAND on above boards instead of finding the value at runtime. Is there any reason that NAND CS# is found out at runtime ? (hence remove necessity of
omap_nand_flash_init()).
Yes makes sense. All the board specific data like that should come from device tree eventually.
Regards,
Tony
PATCH v4 5/39 ARM: OMAP2+: nand: create platform data structure
In reply to Afzal MohammedNew API for updating nand platform data. This has been created by unifying the two existing ones and taking out gpmc hardware handling.
Quoted 1 line
From now on, platforms can call
omap_nand_initto
initialize platform nand structures, it's fields. Or can statically create the same.
Acquiring gpmc CS for has been removed. Acquiring CS is done in GPMC driver. To leverage this feature, pass CS # as any value outside the allowed range of 0 - 7 (this is valid only for connected NAND), eg. GPMC_CS_NUM (8)
--- arch/arm/mach-omap2/board-devkit8000.c | 6 ++- arch/arm/mach-omap2/board-flash.c | 61 ++++++++++++++-------------- arch/arm/mach-omap2/board-flash.h | 13 ++++-- arch/arm/mach-omap2/board-ldp.c | 4 +- arch/arm/mach-omap2/board-omap3beagle.c | 6 ++- arch/arm/mach-omap2/board-omap3touchbook.c | 6 ++- arch/arm/mach-omap2/board-overo.c | 5 ++- arch/arm/mach-omap2/board-zoom.c | 5 ++- arch/arm/mach-omap2/common-board-devices.c | 46 --------------------- arch/arm/mach-omap2/common-board-devices.h | 1 - 10 files changed, 60 insertions(+), 93 deletions(-)
arch/arm/mach-omap2/board-devkit8000.c +4 -2
@@ -59,6 +59,7 @@#include "mux.h" #include "hsmmc.h" +#include "board-flash.h" #include "common-board-devices.h" #define OMAP_DM9000_GPIO_IRQ 25
@@ -648,8 +649,9 @@ static void __init devkit8000_init(void)usb_musb_init (NULL );usbhs_init (&usbhs_bdata); -omap_nand_flash_init (NAND_BUSWIDTH_16 , devkit8000_nand_partitions, -ARRAY_SIZE (devkit8000_nand_partitions)); +board_nand_init (devkit8000_nand_partitions, +ARRAY_SIZE (devkit8000_nand_partitions),GPMC_CS_NUM , +NAND_BUSWIDTH_16 ,NULL );/* Ensure SDRC pins are mux'd for self-refresh */ omap_mux_init_signal ("sdrc_cke0" ,OMAP_PIN_OUTPUT );
arch/arm/mach-omap2/board-flash.c +31 -30
81 lines not on this page · raw message
arch/arm/mach-omap2/board-flash.h +9 -4
@@ -39,11 +39,16 @@ static inline void board_flash_init(struct flash_partitions part[],#if defined(CONFIG_MTD_NAND_OMAP2 ) || \ defined(CONFIG_MTD_NAND_OMAP2_MODULE ) -extern void board_nand_init (struct mtd_partition *nand_parts, -u8 nr_parts,u8 cs,int nand_type); +extern struct gpmc_timings nand_default_timings[]; +extern struct omap_nand_platform_data * +__init board_nand_init (struct mtd_partition *nand_parts,u8 nr_parts,u8 cs, +int nand_type,struct gpmc_timings *gpmc_t);#else -static inline void board_nand_init (struct mtd_partition *nand_parts, -u8 nr_parts,u8 cs,int nand_type) +#define nand_default_timings NULL +static inline struct omap_nand_platform_data * +board_nand_init (struct mtd_partition *nand_parts, +u8 nr_parts,u8 cs,int nand_type,struct gpmc_timings *gpmc_t) { +return NULL ; }#endif
arch/arm/mach-omap2/board-ldp.c +2 -2
@@ -427,8 +427,8 @@ static void __init omap_ldp_init(void)omap_serial_init ();omap_sdrc_init (NULL ,NULL );usb_musb_init (NULL ); -board_nand_init (ldp_nand_partitions, -ARRAY_SIZE (ldp_nand_partitions),ZOOM_NAND_CS ,0 ); +board_nand_init (ldp_nand_partitions,ARRAY_SIZE (ldp_nand_partitions), +ZOOM_NAND_CS ,0 , nand_default_timings);omap_hsmmc_init (mmc);ldp_display_init ();
arch/arm/mach-omap2/board-omap3beagle.c +4 -2
@@ -51,6 +51,7 @@#include "mux.h" #include "hsmmc.h" #include "pm.h" +#include "board-flash.h" #include "common-board-devices.h" /*
@@ -542,8 +543,9 @@ static void __init omap3_beagle_init(void)usb_musb_init (NULL );usbhs_init (&usbhs_bdata); -omap_nand_flash_init (NAND_BUSWIDTH_16 , omap3beagle_nand_partitions, -ARRAY_SIZE (omap3beagle_nand_partitions)); +board_nand_init (omap3beagle_nand_partitions, +ARRAY_SIZE (omap3beagle_nand_partitions),GPMC_CS_NUM , +NAND_BUSWIDTH_16 ,NULL );/* Ensure msecure is mux'd to be able to set the RTC. */ omap_mux_init_signal ("sys_drm_msecure" ,OMAP_PIN_OFF_OUTPUT_HIGH );
arch/arm/mach-omap2/board-omap3touchbook.c +4 -2
@@ -52,6 +52,7 @@#include "mux.h" #include "hsmmc.h" +#include "board-flash.h" #include "common-board-devices.h" #include <asm/setup.h>
@@ -370,8 +371,9 @@ static void __init omap3_touchbook_init(void)omap_ads7846_init (4 ,OMAP3_TS_GPIO ,310 , &ads7846_pdata);usb_musb_init (NULL );usbhs_init (&usbhs_bdata); -omap_nand_flash_init (NAND_BUSWIDTH_16 , omap3touchbook_nand_partitions, -ARRAY_SIZE (omap3touchbook_nand_partitions)); +board_nand_init (omap3touchbook_nand_partitions, +ARRAY_SIZE (omap3touchbook_nand_partitions),GPMC_CS_NUM , +NAND_BUSWIDTH_16 ,NULL );/* Ensure SDRC pins are mux'd for self-refresh */ omap_mux_init_signal ("sdrc_cke0" ,OMAP_PIN_OUTPUT );
arch/arm/mach-omap2/board-overo.c +3 -2
@@ -57,6 +57,7 @@#include "mux.h" #include "sdram-micron-mt46h32m32lf-6.h" #include "hsmmc.h" +#include "board-flash.h" #include "common-board-devices.h" #define OVERO_GPIO_BT_XGATE 15
@@ -517,8 +518,8 @@ static void __init overo_init(void)omap_serial_init ();omap_sdrc_init (mt46h32m32lf6_sdrc_params, mt46h32m32lf6_sdrc_params); -omap_nand_flash_init (0 , overo_nand_partitions, -ARRAY_SIZE (overo_nand_partitions)); +board_nand_init (overo_nand_partitions, +ARRAY_SIZE (overo_nand_partitions),GPMC_CS_NUM ,0 ,NULL );usb_musb_init (NULL );usbhs_init (&usbhs_bdata);overo_spi_init ();
arch/arm/mach-omap2/board-zoom.c +3 -2
@@ -114,8 +114,9 @@ static void __init omap_zoom_init(void)usbhs_init (&usbhs_bdata); } -board_nand_init (zoom_nand_partitions,ARRAY_SIZE (zoom_nand_partitions), -ZOOM_NAND_CS ,NAND_BUSWIDTH_16 ); +board_nand_init (zoom_nand_partitions, +ARRAY_SIZE (zoom_nand_partitions),ZOOM_NAND_CS , +NAND_BUSWIDTH_16 , nand_default_timings);zoom_debugboard_init ();zoom_peripherals_init ();
arch/arm/mach-omap2/common-board-devices.c +0 -46
49 lines not on this page · raw message
arch/arm/mach-omap2/common-board-devices.h +0 -1
@@ -10,6 +10,5 @@ struct ads7846_platform_data;void omap_ads7846_init (int bus_num,int gpio_pendown,int gpio_debounce,struct ads7846_platform_data *board_pdata); -void omap_nand_flash_init (int opts,struct mtd_partition *parts,int n_parts);#endif /* __OMAP_COMMON_BOARD_DEVICES__ */
Signature · 1 line
1.7.10
PATCH v4 6/39 ARM: OMAP2+: onenand: return value in init function
In reply to Afzal MohammedModify board_onenand_init to return platform data. This would be required for boards to be able to pass it to gpmc driver so that it finally reaches onenand driver.
Also un-static the function so that boards can use it.
--- arch/arm/mach-omap2/board-flash.c | 14 ++++---------- arch/arm/mach-omap2/board-flash.h | 12 ++++++++++++ 2 files changed, 16 insertions(+), 10 deletions(-)
arch/arm/mach-omap2/board-flash.c +4 -10
@@ -87,22 +87,16 @@ static struct omap_onenand_platform_data board_onenand_data = { .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */ }; -static void -__init board_onenand_init (struct mtd_partition *onenand_parts, -u8 nr_parts,u8 cs) +struct omap_onenand_platform_data *__init +board_onenand_init (struct mtd_partition *onenand_parts,u8 nr_parts,u8 cs) { board_onenand_data.cs = cs; board_onenand_data.parts = onenand_parts; board_onenand_data.nr_parts = nr_parts; -gpmc_onenand_init (&board_onenand_data); -} -#else -static void -__init board_onenand_init (struct mtd_partition *nor_parts,u8 nr_parts,u8 cs) -{ +return &board_onenand_data; } -#endif /* CONFIG_MTD_ONENAND_OMAP2 || CONFIG_MTD_ONENAND_OMAP2_MODULE */ +#endif #if defined(CONFIG_MTD_NAND_OMAP2 ) || \ defined(CONFIG_MTD_NAND_OMAP2_MODULE )
arch/arm/mach-omap2/board-flash.h +12 -0
@@ -52,3 +52,15 @@ board_nand_init(struct mtd_partition *nand_parts, return NULL; }#endif + +#if defined(CONFIG_MTD_ONENAND_OMAP2 ) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE ) +extern struct omap_onenand_platform_data *__init +board_onenand_init (struct mtd_partition *onenand_parts,u8 nr_parts,u8 cs); +#else +static inline struct omap_onenand_platform_data * +__init board_onenand_init (struct mtd_partition *nor_parts,u8 nr_parts,u8 cs) +{ +return NULL ; +} +#endif
Signature · 1 line
1.7.10
PATCH v4 6/39 ARM: OMAP2+: onenand: return value in init function
Hello.
Quoted 7 lines · Afzal Mohammed
Modify
board_onenand_initto return platform data. This would be required for boards to be able to pass it to gpmc driver so that it finally reaches onenand driver.Also un-static the function so that boards can use it.
Signed-off-by Afzal Mohammed<[email protected]>
[...]
arch/arm/mach-omap2/board-flash.h board_nand_init(struct mtd_partition *nand_parts, · line 57
Quoted 11 lines
arch/arm/mach-omap2/board-flash.h +3
-0@@ -52,3 +52,15 @@ board_nand_init(struct mtd_partition *nand_parts, return NULL; }#endif + +#if defined(CONFIG_MTD_ONENAND_OMAP2 ) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE )
You can use IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2) instead these two.
arch/arm/mach-omap2/board-flash.h board_nand_init(struct mtd_partition *nand_parts, · line 66
Quoted 9 lines
arch/arm/mach-omap2/board-flash.h +9
-0+extern struct omap_onenand_platform_data *__init +board_onenand_init (struct mtd_partition *onenand_parts,u8 nr_parts,u8 cs); +#else +static inline struct omap_onenand_platform_data * +__init board_onenand_init (struct mtd_partition *nor_parts,u8 nr_parts,u8 cs) +{ +return NULL ; +} +#endif
WBR, Sergei
PATCH v4 6/39 ARM: OMAP2+: onenand: return value in init function
Hi Sergei,
Quoted 5 lines · Sergei Shtylyov
arch/arm/mach-omap2/board-flash.h board_nand_init(struct mtd_partition *nand_parts, · line 57
Quoted 3 lines
arch/arm/mach-omap2/board-flash.h +3
-0+ +#if defined(CONFIG_MTD_ONENAND_OMAP2 ) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE )You can use
IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2)instead these two.
Thanks for educating me.
Regards
Afzal
PATCH v4 7/39 ARM: OMAP2+: gpmc-nand: Adapt to use gpmc driver
In reply to Afzal MohammedCurrently gpmc is configured in platform for nand. As configuring gpmc has been moved to gpmc driver, populate details needed for the driver to configure gpmc. gpmc driver would configure based on this information.
--- arch/arm/mach-omap2/gpmc-nand.c | 84 ++++++++++++-------------------- arch/arm/plat-omap/include/plat/nand.h | 8 +-- 2 files changed, 35 insertions(+), 57 deletions(-)
arch/arm/mach-omap2/gpmc-nand.c +30 -54
@@ -21,24 +21,30 @@#include <plat/board.h> #include <plat/gpmc.h> -static struct resource gpmc_nand_resource = { - .flags =IORESOURCE_MEM , + +static struct gpmc_cs_data gpmc_nand_cs_info = { + .have_config = true, + .config =GPMC_DEVICETYPE_NAND , + .irq_config =GPMC_IRQ_FIFOEVENTENABLE |GPMC_IRQ_COUNT_EVENT , }; -static struct platform_device gpmc_nand_device = { +static struct gpmc_device_pdata gpmc_nand_info = { .name ="omap2-nand" , .id =0 , - .num_resources =1 , - .resource = &gpmc_nand_resource, + .cs_data = &gpmc_nand_cs_info, + .num_cs =1 , + .is_nand = true, }; -static int omap2_nand_gpmc_retime (struct omap_nand_platform_data *gpmc_nand_data) -{ -struct gpmc_timings t; -int err; +static struct gpmc_timings t; -if (!gpmc_nand_data->gpmc_t) +static struct gpmc_timings * +gpmc_nand_retime (struct omap_nand_platform_data *gpmc_nand_data) +{ +if (!gpmc_nand_data->gpmc_t) { +pr_warn ("gpmc timings not provided\n" );return 0 ; + }memset (&t,0 ,sizeof (t)); t.sync_clk = gpmc_nand_data->gpmc_t->sync_clk;
@@ -68,56 +74,26 @@ static int omap2_nand_gpmc_retime(struct omap_nand_platform_data *gpmc_nand_data t.cs_wr_off =gpmc_round_ns_to_ticks (gpmc_nand_data->gpmc_t->cs_wr_off); t.wr_cycle =gpmc_round_ns_to_ticks (gpmc_nand_data->gpmc_t->wr_cycle); -/* Configure GPMC */ -if (gpmc_nand_data->devsize ==NAND_BUSWIDTH_16 ) -gpmc_cs_configure (gpmc_nand_data->cs,GPMC_CONFIG_DEV_SIZE ,1 ); -else -gpmc_cs_configure (gpmc_nand_data->cs,GPMC_CONFIG_DEV_SIZE ,0 ); -gpmc_cs_configure (gpmc_nand_data->cs, -GPMC_CONFIG_DEV_TYPE ,GPMC_DEVICETYPE_NAND ); - err =gpmc_cs_set_timings (gpmc_nand_data->cs, &t); -if (err) -return err; - -return 0 ; +return &t; } -int __init gpmc_nand_init (struct omap_nand_platform_data *gpmc_nand_data) +struct gpmc_device_pdata * +__init gpmc_nand_init (struct omap_nand_platform_data *gpmc_nand_data) { -int err =0 ; -struct device *dev = &gpmc_nand_device.dev; + gpmc_nand_info.pdata = gpmc_nand_data; + gpmc_nand_info.pdata_size =sizeof (*gpmc_nand_data); - gpmc_nand_device.dev.platform_data = gpmc_nand_data; + gpmc_nand_cs_info.cs = gpmc_nand_data->cs; + gpmc_nand_cs_info.mem_size =NAND_IO_SIZE ; - err =gpmc_cs_request (gpmc_nand_data->cs,NAND_IO_SIZE , - &gpmc_nand_data->phys_base); -if (err <0 ) { -dev_err (dev,"Cannot request GPMC CS\n" ); -return err; - } + gpmc_nand_cs_info.timing =gpmc_nand_retime (gpmc_nand_data); -/* Set timings in GPMC */ - err =omap2_nand_gpmc_retime (gpmc_nand_data); -if (err <0 ) { -dev_err (dev,"Unable to set gpmc timings: %d\n" , err); -return err; - } - -/* Enable RD PIN Monitoring Reg */ -if (gpmc_nand_data->dev_ready) { -gpmc_cs_configure (gpmc_nand_data->cs,GPMC_CONFIG_RDY_BSY ,1 ); - } - - err =platform_device_register (&gpmc_nand_device); -if (err <0 ) { -dev_err (dev,"Unable to register NAND device\n" ); - goto out_free_cs; - } - -return 0 ; +if (gpmc_nand_data->devsize ==NAND_BUSWIDTH_16 ) + gpmc_nand_cs_info.config |=GPMC_DEVICESIZE_16 ; -out_free_cs: -gpmc_cs_free (gpmc_nand_data->cs); +if (gpmc_nand_data->dev_ready) + gpmc_nand_cs_info.config |=GPMC_WAIT_READ_MON | +GPMC_WAIT_WRITE_MON ; -return err; +return &gpmc_nand_info; }
arch/arm/plat-omap/include/plat/nand.h +5 -3
@@ -36,10 +36,12 @@ struct omap_nand_platform_data {#define NAND_IO_SIZE 4#if defined(CONFIG_MTD_NAND_OMAP2 ) || defined(CONFIG_MTD_NAND_OMAP2_MODULE ) -extern int gpmc_nand_init (struct omap_nand_platform_data *d); +extern struct gpmc_device_pdata * +gpmc_nand_init (struct omap_nand_platform_data *d);#else -static inline int gpmc_nand_init (struct omap_nand_platform_data *d) +static inline struct gpmc_device_pdata * +gpmc_nand_init (struct omap_nand_platform_data *d) { -return 0 ; +return NULL ; }#endif
Signature · 1 line
1.7.10
PATCH v4 8/39 ARM: OMAP2+: gpmc-onenand: Adapt to use gpmc driver
In reply to Afzal MohammedCurrently gpmc is configured in platform for onenand. As configuring gpmc has been moved to gpmc driver, populate details needed for the driver to configure gpmc. gpmc driver would configure based on this information.
--- arch/arm/mach-omap2/gpmc-onenand.c | 111 +++++++++++++++-------------- arch/arm/plat-omap/include/plat/onenand.h | 7 +- 2 files changed, 61 insertions(+), 57 deletions(-)
arch/arm/mach-omap2/gpmc-onenand.c +56 -55
@@ -25,9 +25,17 @@static struct omap_onenand_platform_data *gpmc_onenand_data; -static struct platform_device gpmc_onenand_device = { +#define ONENAND_IO_SIZE SZ_128K + +static struct gpmc_cs_data gpmc_onenand_cs_info = { + .mem_size =ONENAND_IO_SIZE , +}; + +static struct gpmc_device_pdata gpmc_onenand_info = { .name ="omap2-onenand" , .id =-1 , + .cs_data = &gpmc_onenand_cs_info, + .num_cs =1 , };static int omap2_onenand_set_async_mode (int cs,void __iomem *onenand_base)
@@ -79,13 +87,17 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) t.wr_cycle = t.cs_wr_off +gpmc_round_ns_to_ticks (t_cez);/* Configure GPMC for asynchronous read */ -gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , -GPMC_CONFIG1_DEVICESIZE_16 | -GPMC_CONFIG1_MUXADDDATA ); - - err =gpmc_cs_set_timings (cs, &t); -if (err) + gpmc_onenand_cs_info.have_config = true; + gpmc_onenand_cs_info.config =GPMC_DEVICESIZE_16 | +GPMC_MUXADDDATA | +GPMC_DEVICETYPE_NOR ; + gpmc_onenand_cs_info.timing = &t; + err =gpmc_cs_reconfigure (gpmc_onenand_info.name, + gpmc_onenand_info.id, &gpmc_onenand_cs_info); +if (err) { +pr_err ("%s: gpmc_cs_reconfigure failed\n" , __func__);return err; + }/* Ensure sync read and sync write are disabled */ reg =readw (onenand_base +ONENAND_REG_SYS_CFG1 );
@@ -180,7 +192,6 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,int first_time =0 , hf =0 , vhf =0 , sync_read =0 , sync_write =0 ;int err, ticks_cez;int cs = cfg->cs, freq = *freq_ptr; -u32 reg;bool clk_dep = false;if (cfg->flags &ONENAND_SYNC_READ ) {
@@ -276,27 +287,10 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, sync_read, sync_write, hf, vhf);if (div ==1 ) { - reg =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG2 ); - reg |= (1 <<7 ); -gpmc_cs_write_reg (cs,GPMC_CS_CONFIG2 , reg); - reg =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG3 ); - reg |= (1 <<7 ); -gpmc_cs_write_reg (cs,GPMC_CS_CONFIG3 , reg); - reg =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG4 ); - reg |= (1 <<7 ); - reg |= (1 <<23 ); -gpmc_cs_write_reg (cs,GPMC_CS_CONFIG4 , reg); - }else { - reg =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG2 ); - reg &= ~(1 <<7 ); -gpmc_cs_write_reg (cs,GPMC_CS_CONFIG2 , reg); - reg =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG3 ); - reg &= ~(1 <<7 ); -gpmc_cs_write_reg (cs,GPMC_CS_CONFIG3 , reg); - reg =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG4 ); - reg &= ~(1 <<7 ); - reg &= ~(1 <<23 ); -gpmc_cs_write_reg (cs,GPMC_CS_CONFIG4 , reg); + t.control.cs_extra_delay = true; + t.control.adv_extra_delay = true; + t.control.oe_extra_delay = true; + t.control.we_extra_delay = true; }/* Set synchronous read timings */
@@ -348,24 +342,31 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, }/* Configure GPMC for synchronous read */ -gpmc_cs_write_reg (cs,GPMC_CS_CONFIG1 , -GPMC_CONFIG1_WRAPBURST_SUPP | -GPMC_CONFIG1_READMULTIPLE_SUPP | - (sync_read ?GPMC_CONFIG1_READTYPE_SYNC :0 ) | - (sync_write ?GPMC_CONFIG1_WRITEMULTIPLE_SUPP :0 ) | - (sync_write ?GPMC_CONFIG1_WRITETYPE_SYNC :0 ) | -GPMC_CONFIG1_CLKACTIVATIONTIME (fclk_offset) | -GPMC_CONFIG1_PAGE_LEN (2 ) | - (cpu_is_omap34xx () ?0 : - (GPMC_CONFIG1_WAIT_READ_MON | -GPMC_CONFIG1_WAIT_PIN_SEL (0 ))) | -GPMC_CONFIG1_DEVICESIZE_16 | -GPMC_CONFIG1_DEVICETYPE_NOR | -GPMC_CONFIG1_MUXADDDATA ); - - err =gpmc_cs_set_timings (cs, &t); -if (err) + gpmc_onenand_cs_info.have_config = true; + gpmc_onenand_cs_info.config =GPMC_DEVICESIZE_16 |GPMC_MUXADDDATA | +GPMC_DEVICETYPE_NOR |GPMC_WRAPBURST | +GPMC_READMULTIPLE |GPMC_PAGE_LEN_16 ; +if (!cpu_is_omap34xx ()) + gpmc_onenand_cs_info.config |=GPMC_WAIT_READ_MON | +GPMC_WAITPIN_0 ; +if (sync_read) + gpmc_onenand_cs_info.config |=GPMC_READTYPE_SYNC ; +if (sync_write) + gpmc_onenand_cs_info.config |=GPMC_WRITETYPE_SYNC | +GPMC_WRITEMULTIPLE ; +if (fclk_offset ==0 ) + gpmc_onenand_cs_info.config |=GPMC_CLOCKACTIVATIONTIME_0 ; +else if (fclk_offset ==1 ) + gpmc_onenand_cs_info.config |=GPMC_CLOCKACTIVATIONTIME_1 ; +else if (fclk_offset ==2 ) + gpmc_onenand_cs_info.config |=GPMC_CLOCKACTIVATIONTIME_2 ; + gpmc_onenand_cs_info.timing = &t; + err =gpmc_cs_reconfigure (gpmc_onenand_info.name, + gpmc_onenand_info.id, &gpmc_onenand_cs_info); +if (err) { +pr_err ("%s: gpmc_cs_reconfigure failed\n" , __func__);return err; + }set_onenand_cfg (onenand_base, latency, sync_read, sync_write, hf, vhf);
@@ -376,23 +377,21 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,static int gpmc_onenand_setup (void __iomem *onenand_base,int *freq_ptr) { -struct device *dev = &gpmc_onenand_device.dev; -/* Set sync timings in GPMC */ if (omap2_onenand_set_sync_mode (gpmc_onenand_data, onenand_base, freq_ptr) <0 ) { -dev_err (dev,"Unable to set synchronous mode\n" ); +pr_err ("%s: Unable to set synchronous mode\n" , __func__);return -EINVAL ; }return 0 ; } -void __init gpmc_onenand_init (struct omap_onenand_platform_data *_onenand_data) +struct gpmc_device_pdata * +__init gpmc_onenand_init (struct omap_onenand_platform_data *_onenand_data) { gpmc_onenand_data = _onenand_data; gpmc_onenand_data->onenand_setup = gpmc_onenand_setup; - gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;if (cpu_is_omap24xx () && (gpmc_onenand_data->flags &ONENAND_SYNC_READWRITE )) {
@@ -401,8 +400,10 @@ void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) gpmc_onenand_data->flags |=ONENAND_SYNC_READ ; } -if (platform_device_register (&gpmc_onenand_device) <0 ) { -printk (KERN_ERR "Unable to register OneNAND device\n" ); -return ; - } + gpmc_onenand_info.pdata = gpmc_onenand_data; + gpmc_onenand_info.pdata_size =sizeof (*gpmc_onenand_data); + + gpmc_onenand_cs_info.cs = gpmc_onenand_data->cs; + +return &gpmc_onenand_info; }
arch/arm/plat-omap/include/plat/onenand.h +5 -2
@@ -40,14 +40,17 @@ struct omap_onenand_platform_data {#if defined(CONFIG_MTD_ONENAND_OMAP2 ) || \ defined(CONFIG_MTD_ONENAND_OMAP2_MODULE ) -extern void gpmc_onenand_init (struct omap_onenand_platform_data *d); +extern struct gpmc_device_pdata * +gpmc_onenand_init (struct omap_onenand_platform_data *d);#else #define board_onenand_data NULL -static inline void gpmc_onenand_init (struct omap_onenand_platform_data *d) +static inline struct gpmc_device_pdata * +gpmc_onenand_init (struct omap_onenand_platform_data *d) { +return NULL ; }#endif
Signature · 1 line
1.7.10
PATCH v4 9/39 ARM: OMAP2+: flash: Adapt to gpmc driver
In reply to Afzal Mohammedgpmc driver has been converted to driver. Modify board_flash_init so that it can setup gpmc driver platform details for boards
--- arch/arm/mach-omap2/board-3430sdp.c | 2 +- arch/arm/mach-omap2/board-3630sdp.c | 3 +- arch/arm/mach-omap2/board-flash.c | 89 +++++++++++++++++++---------------- arch/arm/mach-omap2/board-flash.h | 11 +++-- 4 files changed, 58 insertions(+), 47 deletions(-)
arch/arm/mach-omap2/board-3430sdp.c +1 -1
@@ -620,7 +620,7 @@ static void __init omap_3430sdp_init(void)omap_sdrc_init (hyb18m512160af6_sdrc_params,NULL );usb_musb_init (NULL );board_smc91x_init (); -board_flash_init (sdp_flash_partitions, chip_sel_3430,0 ); +board_flash_init (sdp_flash_partitions, chip_sel_3430,0 ,NULL );sdp3430_display_init ();enable_board_wakeup_source ();usbhs_init (&usbhs_bdata);
arch/arm/mach-omap2/board-3630sdp.c +2 -1
@@ -204,7 +204,8 @@ static void __init omap_sdp_init(void) h8mbx00u0mer0em_sdrc_params);zoom_display_init ();board_smc91x_init (); -board_flash_init (sdp_flash_partitions, chip_sel_sdp,NAND_BUSWIDTH_16 ); +board_flash_init (sdp_flash_partitions, chip_sel_sdp, +NAND_BUSWIDTH_16 ,NULL );enable_board_wakeup_source ();usbhs_init (&usbhs_bdata); }
arch/arm/mach-omap2/board-flash.c +48 -41
134 lines not on this page · raw message
arch/arm/mach-omap2/board-flash.h +7 -4
@@ -28,12 +28,15 @@ struct flash_partitions {defined (CONFIG_MTD_NAND_OMAP2_MODULE ) || \defined (CONFIG_MTD_ONENAND_OMAP2 ) || \ defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) -extern void board_flash_init (struct flash_partitions [], -char chip_sel[][GPMC_CS_NUM ],int nand_type); +extern struct gpmc_device_pdata **board_flash_init ( +struct flash_partitions [],char chip_sel[][GPMC_CS_NUM ], +int nand_type,struct gpmc_device_pdata **gpmc_data);#else -static inline void board_flash_init (struct flash_partitions part[], -char chip_sel[][GPMC_CS_NUM ],int nand_type) +static inline struct gpmc_device_pdata **board_flash_init ( +struct flash_partitions part[],char chip_sel[][GPMC_CS_NUM ], +int nand_type,struct gpmc_device_pdata **gpmc_data) { +return NULL ; }#endif
Signature · 1 line
1.7.10
PATCH v4 10/39 ARM: OMAP2+: gpmc-smsc911x: Adapt to use gpmc driver
In reply to Afzal Mohammedgpmc has been converted to driver. And all gpmc related configuration would be done by gpmc driver. Provide gpmc driver with sufficient information so that it can configure.
--- arch/arm/mach-omap2/gpmc-smsc911x.c | 59 ++++++++++++----------- arch/arm/plat-omap/include/plat/gpmc-smsc911x.h | 9 +++- 2 files changed, 39 insertions(+), 29 deletions(-)
arch/arm/mach-omap2/gpmc-smsc911x.c +32 -27
@@ -24,13 +24,8 @@#include <plat/gpmc.h> #include <plat/gpmc-smsc911x.h> -static struct resource gpmc_smsc911x_resources[] = { - [0 ] = { - .flags =IORESOURCE_MEM , - }, - [1 ] = { - .flags =IORESOURCE_IRQ |IORESOURCE_IRQ_LOWLEVEL , - }, +static struct resource gpmc_smsc911x_resources = { + .flags =IORESOURCE_IRQ |IORESOURCE_IRQ_LOWLEVEL , };static struct smsc911x_platform_config gpmc_smsc911x_config = {
@@ -44,26 +39,42 @@ static struct smsc911x_platform_config gpmc_smsc911x_config = {* assume that pin multiplexing is done in the board-*.c file, * or in the bootloader. */ -void __init gpmc_smsc911x_init (struct omap_smsc911x_platform_data *gpmc_cfg) +__init struct gpmc_device_pdata * +gpmc_smsc911x_init (struct omap_smsc911x_platform_data *gpmc_cfg) { -struct platform_device *pdev; -unsigned long cs_mem_base;int ret; +struct gpmc_device_pdata *gpmc_pdev; +struct gpmc_cs_data *gpmc_cs; -if (gpmc_cs_request (gpmc_cfg->cs,SZ_16M , &cs_mem_base) <0 ) { -pr_err ("Failed to request GPMC mem region\n" ); -return ; + gpmc_pdev =kzalloc (sizeof (*gpmc_pdev),GFP_KERNEL ); +if (gpmc_pdev ==NULL ) +return gpmc_pdev; + + gpmc_cs =kzalloc (sizeof (*gpmc_cs),GFP_KERNEL ); +if (gpmc_pdev ==NULL ) { +kfree (gpmc_pdev); +return NULL ; } - gpmc_smsc911x_resources[0 ].start = cs_mem_base +0x0 ; - gpmc_smsc911x_resources[0 ].end = cs_mem_base +0xff ; + gpmc_pdev->cs_data = gpmc_cs; + gpmc_pdev->num_cs =1 ; + gpmc_pdev->name ="smsc911x" ; + gpmc_pdev->id = gpmc_cfg->id; + gpmc_pdev->pdata = &gpmc_smsc911x_config; + gpmc_pdev->pdata_size =sizeof (gpmc_smsc911x_config); + + gpmc_cs->cs = gpmc_cfg->cs; + gpmc_cs->mem_size =0x100 ; + + gpmc_pdev->per_res = &gpmc_smsc911x_resources; + gpmc_pdev->per_res_cnt =1 ;if (gpio_request_one (gpmc_cfg->gpio_irq,GPIOF_IN ,"smsc911x irq" )) {pr_err ("Failed to request IRQ GPIO%d\n" , gpmc_cfg->gpio_irq); goto free1; } - gpmc_smsc911x_resources[1 ].start =gpio_to_irq (gpmc_cfg->gpio_irq); + gpmc_smsc911x_resources.start =gpio_to_irq (gpmc_cfg->gpio_irq);if (gpio_is_valid (gpmc_cfg->gpio_reset)) { ret = gpio_request_one(gpmc_cfg->gpio_reset,
@@ -81,21 +92,15 @@ void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *gpmc_cfg) gpmc_smsc911x_config.flags = gpmc_cfg->flags ? :SMSC911X_USE_16BIT ; - pdev =platform_device_register_resndata (NULL ,"smsc911x" , gpmc_cfg->id, - gpmc_smsc911x_resources,ARRAY_SIZE (gpmc_smsc911x_resources), - &gpmc_smsc911x_config,sizeof (gpmc_smsc911x_config)); -if (!pdev) { -pr_err ("Unable to register platform device\n" ); -gpio_free (gpmc_cfg->gpio_reset); - goto free2; - } - -return ; +return gpmc_pdev; free2:gpio_free (gpmc_cfg->gpio_irq); free1: -gpmc_cs_free (gpmc_cfg->cs); +kfree (gpmc_cs); +kfree (gpmc_pdev);pr_err ("Could not initialize smsc911x device\n" ); + +return NULL ; }
arch/arm/plat-omap/include/plat/gpmc-smsc911x.h +7 -2
@@ -11,6 +11,8 @@* published by the Free Software Foundation. */ +#include <plat/gpmc.h> +#ifndef __ASM_ARCH_OMAP_GPMC_SMSC911X_H__ struct omap_smsc911x_platform_data {
@@ -23,12 +25,15 @@ struct omap_smsc911x_platform_data {#if defined(CONFIG_SMSC911X ) || defined(CONFIG_SMSC911X_MODULE ) -extern void gpmc_smsc911x_init (struct omap_smsc911x_platform_data *d); +extern struct gpmc_device_pdata * +gpmc_smsc911x_init (struct omap_smsc911x_platform_data *d);#else -static inline void gpmc_smsc911x_init (struct omap_smsc911x_platform_data *d) +static inline struct gpmc_device_pdata * +gpmc_smsc911x_init (struct omap_smsc911x_platform_data *d) { +return NULL ; }#endif
Signature · 1 line
1.7.10
PATCH v4 11/39 ARM: OMAP2+: gpmc-smc91x: Adapt to use gpmc driver
In reply to Afzal MohammedCurrently gpmc is configured in platform for smc91x. As configuring gpmc has been moved to gpmc driver, populate details needed for the driver to configure gpmc. gpmc driver would configure based on this information.
--- arch/arm/mach-omap2/board-2430sdp.c | 2 +- arch/arm/mach-omap2/board-3430sdp.c | 1 + arch/arm/mach-omap2/board-3630sdp.c | 1 + arch/arm/mach-omap2/gpmc-smc91x.c | 87 +++++++++++-------------- arch/arm/plat-omap/include/plat/gpmc-smc91x.h | 10 ++- 5 files changed, 47 insertions(+), 54 deletions(-)
arch/arm/mach-omap2/board-2430sdp.c +1 -1
@@ -175,7 +175,7 @@ static struct omap_smc91x_platform_data board_smc91x_data = { .gpio_irq = 149, .flags = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 | IORESOURCE_IRQ_LOWLEVEL, - + .skip_timing = true, };static void __init board_smc91x_init (void )
arch/arm/mach-omap2/board-3430sdp.c +1 -0
@@ -434,6 +434,7 @@ static struct omap_smc91x_platform_data board_smc91x_data = { .cs = 3, .flags = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 | IORESOURCE_IRQ_LOWLEVEL, + .skip_timing = true, };static void __init board_smc91x_init (void )
arch/arm/mach-omap2/board-3630sdp.c +1 -0
@@ -32,6 +32,7 @@static struct omap_smc91x_platform_data board_smc91x_data = { .cs =3 , .flags =GPMC_MUX_ADD_DATA |IORESOURCE_IRQ_LOWLEVEL , + .skip_timing = true, };static void __init board_smc91x_init (void )
arch/arm/mach-omap2/gpmc-smc91x.c +37 -50
161 lines not on this page · raw message
arch/arm/plat-omap/include/plat/gpmc-smc91x.h +7 -3
@@ -22,20 +22,24 @@ struct omap_smc91x_platform_data {int gpio_reset;int wait_pin;/* Optional GPMC_CONFIG1_WAITPINSELECT */ u32 flags; -int (*retime)(void ); +bool skip_timing; +void (*retime)(void ); };#if defined(CONFIG_SMC91X ) || \ defined(CONFIG_SMC91X_MODULE ) -extern void gpmc_smc91x_init (struct omap_smc91x_platform_data *d); +extern struct gpmc_device_pdata * +gpmc_smc91x_init (struct omap_smc91x_platform_data *d);#else #define board_smc91x_data NULL -static inline void gpmc_smc91x_init (struct omap_smc91x_platform_data *d) +static inline struct gpmc_device_pdata * +gpmc_smc91x_init (struct omap_smc91x_platform_data *d) { +return NULL ; }#endif
Signature · 1 line
1.7.10
PATCH v4 12/39 ARM: OMAP2+: gpmc-tusb6010: Adapt to gpmc driver
In reply to Afzal MohammedCurrently gpmc is configured in platform for tusb6010. As configuring gpmc has been moved to gpmc driver, populate details needed for the driver to configure gpmc. gpmc driver would configure based on this information.
--- arch/arm/mach-omap2/usb-tusb6010.c | 177 ++++++++++++++---------------------- include/linux/usb/musb.h | 4 +- 2 files changed, 70 insertions(+), 111 deletions(-)
arch/arm/mach-omap2/usb-tusb6010.c +69 -108
@@ -22,6 +22,24 @@#include "mux.h" +static struct resource tusb_resources = { + .name ="mc" , + .flags =IORESOURCE_IRQ , +}; + +#define TUSB_GPMC_CS_ASYNC_IDX 1 +#define TUSB_GPMC_CS_SYNC_IDX 2 +#define TUSB_GPMC_CS_NUM 2 + +static struct gpmc_cs_data gpmc_tusb_cs_data[TUSB_GPMC_CS_NUM ]; + +static struct gpmc_device_pdata gpmc_tusb_data = { + .name ="musb-tusb" , + .id =-1 , + .per_res = &tusb_resources, + .per_res_cnt =1 , +}; +static u8 async_cs, sync_cs;static unsigned refclk_psec;
@@ -51,9 +69,9 @@ next_clk(unsigned t1_NS, unsigned t2_ps, unsigned fclk_ps)/* NOTE: timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */ -static int tusb_set_async_mode (unsigned sysclk_ps,unsigned fclk_ps) +static void tusb_set_async_mode (unsigned sysclk_ps,unsigned fclk_ps) { -struct gpmc_timings t; +static struct gpmc_timings t;unsigned t_acsnh_advnh = sysclk_ps +3000 ;unsigned tmp;
@@ -106,12 +124,12 @@ static int tusb_set_async_mode(unsigned sysclk_ps, unsigned fclk_ps) tmp = t.cs_wr_off *1000 +7000 /* t_acsn_rdy_z */ ; t.wr_cycle =next_clk (t.cs_wr_off, tmp, fclk_ps); -return gpmc_cs_set_timings (async_cs, &t); + gpmc_tusb_cs_data[TUSB_GPMC_CS_ASYNC_IDX ].timing = &t; }static int tusb_set_sync_mode (unsigned sysclk_ps,unsigned fclk_ps) { -struct gpmc_timings t; +static struct gpmc_timings t;unsigned t_scsnh_advnh = sysclk_ps +3000 ;unsigned tmp;
@@ -174,71 +192,30 @@ static int tusb_set_sync_mode(unsigned sysclk_ps, unsigned fclk_ps) tmp = t.cs_wr_off *1000 +7000 /* t_scsn_rdy_z */ ; t.wr_cycle =next_clk (t.cs_wr_off, tmp, fclk_ps); -return gpmc_cs_set_timings (sync_cs, &t); + gpmc_tusb_cs_data[TUSB_GPMC_CS_SYNC_IDX ].timing = &t; + +return 0 ; }extern unsigned long gpmc_get_fclk_period (void );/* tusb driver calls this when it changes the chip's clocking */ -int tusb6010_platform_retime (unsigned is_refclk) +static int tusb6010_platform_retime (unsigned is_refclk) { -static const char error[] = -KERN_ERR "tusb6010 %s retime error %d\n" ; -unsigned fclk_ps =gpmc_get_fclk_period ();unsigned sysclk_ps; -int status;if (!refclk_psec || fclk_ps ==0 )return -ENODEV ; sysclk_ps = is_refclk ? refclk_psec :TUSB6010_OSCCLK_60 ; - status =tusb_set_async_mode (sysclk_ps, fclk_ps); -if (status <0 ) { -printk (error,"async" , status); - goto done; - } - status =tusb_set_sync_mode (sysclk_ps, fclk_ps); -if (status <0 ) -printk (error,"sync" , status); -done: -return status; +tusb_set_async_mode (sysclk_ps, fclk_ps); +return tusb_set_sync_mode (sysclk_ps, fclk_ps); } -EXPORT_SYMBOL_GPL (tusb6010_platform_retime); - -static struct resource tusb_resources[] = { -/* Order is significant! The start/end fields -* are updated during setup.. -*/ - {/* Asynchronous access */ - .flags =IORESOURCE_MEM , - }, - {/* Synchronous access */ - .flags =IORESOURCE_MEM , - }, - {/* IRQ */ - .name ="mc" , - .flags =IORESOURCE_IRQ , - }, -}; - -static u64 tusb_dmamask = ~(u32 )0 ; - -static struct platform_device tusb_device = { - .name ="musb-tusb" , - .id =-1 , - .dev = { - .dma_mask = &tusb_dmamask, - .coherent_dma_mask =0xffffffff , - }, - .num_resources =ARRAY_SIZE (tusb_resources), - .resource = tusb_resources, -}; -/* this may be called only from board-*.c setup code */ -int __init +__init struct gpmc_device_pdata * tusb6010_setup_interface(struct musb_hdrc_platform_data *data, unsigned ps_refclk, unsigned waitpin, unsigned async, unsigned sync,
@@ -249,82 +226,72 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,KERN_ERR "tusb6010 init error %d, %d\n" ;/* ASYNC region, primarily for PIO */ - status =gpmc_cs_request (async,SZ_16M , (unsigned long *) - &tusb_resources[0 ].start); -if (status <0 ) { -printk (error,1 , status); -return status; - } - tusb_resources[0 ].end = tusb_resources[0 ].start +0x9ff ; + gpmc_tusb_cs_data[TUSB_GPMC_CS_ASYNC_IDX ].cs = async; + gpmc_tusb_cs_data[TUSB_GPMC_CS_ASYNC_IDX ].mem_size =0x1000 ; + async_cs = async; -gpmc_cs_write_reg (async,GPMC_CS_CONFIG1 , -GPMC_CONFIG1_PAGE_LEN (2 ) - |GPMC_CONFIG1_WAIT_READ_MON - |GPMC_CONFIG1_WAIT_WRITE_MON - |GPMC_CONFIG1_WAIT_PIN_SEL (waitpin) - |GPMC_CONFIG1_READTYPE_ASYNC - |GPMC_CONFIG1_WRITETYPE_ASYNC - |GPMC_CONFIG1_DEVICESIZE_16 - |GPMC_CONFIG1_DEVICETYPE_NOR - |GPMC_CONFIG1_MUXADDDATA ); + gpmc_tusb_cs_data[TUSB_GPMC_CS_ASYNC_IDX ].have_config = true; + gpmc_tusb_cs_data[TUSB_GPMC_CS_ASYNC_IDX ].config =GPMC_DEVICESIZE_16 | +GPMC_WAIT_READ_MON | +GPMC_WAIT_WRITE_MON | +GPMC_READTYPE_ASYNC | +GPMC_WRITETYPE_ASYNC | +GPMC_DEVICETYPE_NOR | +GPMC_MUXADDDATA | +GPMC_PAGE_LEN_16 | + waitpin;/* SYNC region, primarily for DMA */ - status =gpmc_cs_request (sync,SZ_16M , (unsigned long *) - &tusb_resources[1 ].start); -if (status <0 ) { -printk (error,2 , status); -return status; - } - tusb_resources[1 ].end = tusb_resources[1 ].start +0x9ff ; + gpmc_tusb_cs_data[TUSB_GPMC_CS_SYNC_IDX ].cs = sync; + gpmc_tusb_cs_data[TUSB_GPMC_CS_SYNC_IDX ].mem_size =0x1000 ; + sync_cs = sync; -gpmc_cs_write_reg (sync,GPMC_CS_CONFIG1 , -GPMC_CONFIG1_READMULTIPLE_SUPP - |GPMC_CONFIG1_READTYPE_SYNC - |GPMC_CONFIG1_WRITEMULTIPLE_SUPP - |GPMC_CONFIG1_WRITETYPE_SYNC - |GPMC_CONFIG1_CLKACTIVATIONTIME (1 ) - |GPMC_CONFIG1_PAGE_LEN (2 ) - |GPMC_CONFIG1_WAIT_READ_MON - |GPMC_CONFIG1_WAIT_WRITE_MON - |GPMC_CONFIG1_WAIT_PIN_SEL (waitpin) - |GPMC_CONFIG1_DEVICESIZE_16 - |GPMC_CONFIG1_DEVICETYPE_NOR - |GPMC_CONFIG1_MUXADDDATA -/* fclk divider gets set later */ - ); + + gpmc_tusb_cs_data[TUSB_GPMC_CS_SYNC_IDX ].have_config = true; +/* fclk divider gets set later */ + gpmc_tusb_cs_data[TUSB_GPMC_CS_SYNC_IDX ].config =GPMC_DEVICESIZE_16 | +GPMC_WAIT_READ_MON | +GPMC_WAIT_WRITE_MON | +GPMC_READTYPE_SYNC | +GPMC_WRITETYPE_SYNC | +GPMC_DEVICETYPE_NOR | +GPMC_MUXADDDATA | +GPMC_PAGE_LEN_16 | +GPMC_CLOCKACTIVATION_TIME_1 | +GPMC_READMULTIPLE | +GPMC_WRITEMULTIPLE | + waitpin;/* IRQ */ status =gpio_request_one (irq,GPIOF_IN ,"TUSB6010 irq" );if (status <0 ) {printk (error,3 , status); -return status; +return NULL ; } - tusb_resources[2 ].start = irq +IH_GPIO_BASE ; + tusb_resources.start = irq +IH_GPIO_BASE ;/* set up memory timings ... can speed them up later */ if (!ps_refclk) {printk (error,4 , status); -return -ENODEV ; +return NULL ; } refclk_psec = ps_refclk; status =tusb6010_platform_retime (1 );if (status <0 ) {printk (error,5 , status); -return status; +return NULL ; } -/* finish device setup ... */ if (!data) {printk (error,6 , status); -return -ENODEV ; +return NULL ; } - tusb_device.dev.platform_data = data; + gpmc_tusb_data.pdata = data; + gpmc_tusb_data.pdata_size =sizeof (*data);/* REVISIT let the driver know what DMA channels work */ -if (!dmachan) - tusb_device.dev.dma_mask =NULL ; -else { +if (dmachan) {/* assume OMAP 2420 ES2.0 and later */ if (dmachan & (1 <<0 ))omap_mux_init_signal ("sys_ndmareq0" ,0 );
@@ -340,11 +307,5 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,omap_mux_init_signal ("sys_ndmareq5" ,0 ); } -/* so far so good ... register the device */ - status =platform_device_register (&tusb_device); -if (status <0 ) { -printk (error,7 , status); -return status; - } -return 0 ; +return &gpmc_tusb_data; }
include/linux/usb/musb.h +1 -3
@@ -139,14 +139,12 @@ struct musb_hdrc_platform_data {#ifdef CONFIG_ARCH_OMAP2 -extern int __init tusb6010_setup_interface ( +extern __init struct gpmc_device_pdata *tusb6010_setup_interface (struct musb_hdrc_platform_data *data,unsigned ps_refclk,unsigned waitpin,unsigned async_cs,unsigned sync_cs,unsigned irq,unsigned dmachan); -extern int tusb6010_platform_retime (unsigned is_refclk); -#endif /* OMAP2 */ #endif /* __LINUX_USB_MUSB_H */
Signature · 1 line
1.7.10
PATCH v4 13/39 ARM: OMAP3: hwmod data: add gpmc
In reply to Afzal MohammedAdd gpmc hwmod and associated interconnect data
--- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 52 ++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +52 -0
@@ -1981,6 +1981,40 @@ static struct omap_hwmod omap3xxx_usb_tll_hs_hwmod = { };/* +* 'gpmc' class +* general purpose memory controller +*/ + +static struct omap_hwmod_class_sysconfig omap3xxx_gpmc_sysc = { + .rev_offs =0x0000 , + .sysc_offs =0x0010 , + .syss_offs =0x0014 , + .sysc_flags = (SYSC_HAS_AUTOIDLE |SYSC_HAS_SIDLEMODE | +SYSC_HAS_SOFTRESET |SYSS_HAS_RESET_STATUS ), + .idlemodes = (SIDLE_FORCE |SIDLE_NO |SIDLE_SMART ), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +static struct omap_hwmod_class omap3xxx_gpmc_hwmod_class = { + .name ="gpmc" , + .sysc = &omap3xxx_gpmc_sysc, +}; + +static struct omap_hwmod_irq_info omap3xxx_gpmc_irqs[] = { + { .irq =20 }, + { .irq =-1 } +}; + +static struct omap_hwmod omap3xxx_gpmc_hwmod = { + .name ="gpmc" , + .class = &omap3xxx_gpmc_hwmod_class, + .clkdm_name ="l3_init_clkdm" , + .mpu_irqs = omap3xxx_gpmc_irqs, + .main_clk ="gpmc_fck" , + .flags =HWMOD_INIT_NO_IDLE |HWMOD_INIT_NO_RESET , +}; + +/* * interfaces */
@@ -3059,6 +3093,23 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__usb_tll_hs = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +static struct omap_hwmod_addr_space omap3xxx_gpmc_addrs[] = { + { + .pa_start =0x6E000000 , + .pa_end =0x6E000FFF , + .flags =ADDR_TYPE_RT + }, + { } +}; + +static struct omap_hwmod_ocp_if omap3xxx_l3_main__gpmc = { + .master = &omap3xxx_l3_main_hwmod, + .slave = &omap3xxx_gpmc_hwmod, + .clk ="core_l3_ick" , + .addr = omap3xxx_gpmc_addrs, + .user =OCP_USER_MPU |OCP_USER_SDMA , +}; +static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[]__initdata = { &omap3xxx_l3_main__l4_core, &omap3xxx_l3_main__l4_per,
@@ -3103,6 +3154,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = { &omap34xx_l4_core__mcspi2, &omap34xx_l4_core__mcspi3, &omap34xx_l4_core__mcspi4, + &omap3xxx_l3_main__gpmc, NULL, };
Signature · 1 line
1.7.10
Paul Walmsley
maintainerPATCH v4 13/39 ARM: OMAP3: hwmod data: add gpmc
Hello Afzal,
Quoted 3 lines · Afzal Mohammed
Add gpmc hwmod and associated interconnect data
Signed-off-by Afzal Mohammed <[email protected]>
The comments from
http://marc.info/?l=linux-omap&m=133626998315039&w=2
also apply to this patch.
- Paul
PATCH v4 14/39 ARM: OMAP2xxx: hwmod data: add gpmc
In reply to Afzal MohammedAdd gpmc hwmod and associated interconnect data
--- arch/arm/mach-omap2/omap_hwmod_2420_data.c | 18 +++++++++ arch/arm/mach-omap2/omap_hwmod_2430_data.c | 18 +++++++++ arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 41 ++++++++++++++++++++ arch/arm/mach-omap2/omap_hwmod_common_data.h | 1 + arch/arm/mach-omap2/prcm-common.h | 2 + 5 files changed, 80 insertions(+)
arch/arm/mach-omap2/omap_hwmod_2420_data.c +18 -0
@@ -428,6 +428,23 @@ static struct omap_hwmod_ocp_if omap2420_l4_core__mcbsp2 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +static struct omap_hwmod_addr_space omap2420_gpmc_addrs[] = { + { + .pa_start =0x6800A000 , + .pa_end =0x6800AFFF , + .flags =ADDR_TYPE_RT + }, + { } +}; + +static struct omap_hwmod_ocp_if omap2420_l3__gpmc = { + .master = &omap2xxx_l3_main_hwmod, + .slave = &omap2xxx_gpmc_hwmod, + .clk ="core_l3_ck" , + .addr = omap2420_gpmc_addrs, + .user =OCP_USER_MPU |OCP_USER_SDMA , +}; +static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[]__initdata = { &omap2xxx_l3_main__l4_core, &omap2xxx_mpu__l3_main,
@@ -468,6 +485,7 @@ static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = { &omap2420_l4_core__mailbox, &omap2420_l4_core__mcbsp1, &omap2420_l4_core__mcbsp2, + &omap2420_l3__gpmc, NULL, };
arch/arm/mach-omap2/omap_hwmod_2430_data.c +18 -0
@@ -838,6 +838,23 @@ static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp5 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +static struct omap_hwmod_addr_space omap2430_gpmc_addrs[] = { + { + .pa_start =0x6E000000 , + .pa_end =0x6E000FFF , + .flags =ADDR_TYPE_RT + }, + { } +}; + +static struct omap_hwmod_ocp_if omap2430_l3__gpmc = { + .master = &omap2xxx_l3_main_hwmod, + .slave = &omap2xxx_gpmc_hwmod, + .clk ="core_l3_ck" , + .addr = omap2430_gpmc_addrs, + .user =OCP_USER_MPU |OCP_USER_SDMA , +}; +static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[]__initdata = { &omap2xxx_l3_main__l4_core, &omap2xxx_mpu__l3_main,
@@ -886,6 +903,7 @@ static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = { &omap2430_l4_core__mcbsp3, &omap2430_l4_core__mcbsp4, &omap2430_l4_core__mcbsp5, + &omap2430_l3__gpmc, NULL, };
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c +41 -0
50 lines not on this page · raw message
arch/arm/mach-omap2/omap_hwmod_common_data.h +1 -0
@@ -74,6 +74,7 @@ extern struct omap_hwmod omap2xxx_gpio3_hwmod;extern struct omap_hwmod omap2xxx_gpio4_hwmod;extern struct omap_hwmod omap2xxx_mcspi1_hwmod;extern struct omap_hwmod omap2xxx_mcspi2_hwmod; +extern struct omap_hwmod omap2xxx_gpmc_hwmod;/* Common interface data across OMAP2xxx */ extern struct omap_hwmod_ocp_if omap2xxx_l3_main__l4_core;
arch/arm/mach-omap2/prcm-common.h +2 -0
@@ -109,6 +109,8 @@#define OMAP2430_EN_MDM_INTC_MASK (1 << 11)#define OMAP2430_EN_USBHS_SHIFT 6#define OMAP2430_EN_USBHS_MASK (1 << 6) +#define OMAP24XX_EN_GPMC_SHIFT 1 +#define OMAP24XX_EN_GPMC_MASK (1 << 1)/* CM_IDLEST1_CORE, PM_WKST1_CORE shared bits */ #define OMAP2420_ST_MMC_SHIFT 26
Signature · 1 line
1.7.10
Paul Walmsley
maintainerPATCH v4 14/39 ARM: OMAP2xxx: hwmod data: add gpmc
Hello Afzal,
Quoted 3 lines · Afzal Mohammed
Add gpmc hwmod and associated interconnect data
Signed-off-by Afzal Mohammed <[email protected]>
The comments from
http://marc.info/?l=linux-omap&m=133626998315039&w=2
also apply to this patch.
- Paul
PATCH v4 15/39 mtd: nand: omap2: obtain memory from resource
In reply to Afzal Mohammedgpmc being converted to driver, provides drivers
of peripheral connected memory space used by the
peripheral as memory resource.
Modify nand omap driver to obtain memory detials
from resource structure.
--- arch/arm/plat-omap/include/plat/nand.h | 1 - drivers/mtd/nand/omap2.c | 20 ++++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-)
arch/arm/plat-omap/include/plat/nand.h +0 -1
@@ -26,7 +26,6 @@ struct omap_nand_platform_data {bool dev_ready;int gpmc_irq;enum nand_io xfer_type; -unsigned long phys_base;int devsize;enum omap_ecc ecc_opt;struct gpmc_nand_regs reg;
drivers/mtd/nand/omap2.c +14 -6
@@ -118,6 +118,7 @@ struct omap_nand_info {int gpmc_cs;unsigned long phys_base; +unsigned long mem_size;struct completion comp;int dma_ch;int gpmc_irq;
@@ -931,6 +932,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)struct omap_nand_platform_data *pdata;int err;int i, offset; +struct resource *res; pdata = pdev->dev.platform_data;if (pdata ==NULL ) {
@@ -950,7 +952,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->pdev = pdev; info->gpmc_cs = pdata->cs; - info->phys_base = pdata->phys_base; info->mtd.priv = &info->nand; info->mtd.name =dev_name (&pdev->dev);
@@ -959,16 +960,23 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->nand.options = pdata->devsize; info->nand.options |=NAND_SKIP_BBTSCAN ; -/* NAND write protect off */ -gpmc_cs_configure (info->gpmc_cs,GPMC_CONFIG_WP ,0 ); + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (res ==NULL ) { + err = -EINVAL ; +dev_err (&pdev->dev,"error getting memory resource\n" ); + goto out_free_info; + } + + info->phys_base = res->start; + info->mem_size =resource_size (res); -if (!request_mem_region (info->phys_base,NAND_IO_SIZE , +if (!request_mem_region (info->phys_base, info->mem_size, pdev->dev.driver->name)) { err = -EBUSY ; goto out_free_info; } - info->nand.IO_ADDR_R =ioremap (info->phys_base,NAND_IO_SIZE ); + info->nand.IO_ADDR_R =ioremap (info->phys_base, info->mem_size);if (!info->nand.IO_ADDR_R) { err = -ENOMEM ; goto out_release_mem_region;
@@ -1110,7 +1118,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)return 0 ; out_release_mem_region: -release_mem_region (info->phys_base,NAND_IO_SIZE ); +release_mem_region (info->phys_base, info->mem_size); out_free_info:kfree (info);
Signature · 1 line
1.7.10
PATCH v4 16/39 mtd: nand: omap2: use gpmc provided irqs
In reply to Afzal MohammedGPMC driver provides it's clientsd with interrupts that can be used through struct resource. Make use of it for irq mode functionality.
--- drivers/mtd/nand/omap2.c | 67 +++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 25 deletions(-)
drivers/mtd/nand/omap2.c +42 -25
@@ -121,7 +121,8 @@ struct omap_nand_info {unsigned long mem_size;struct completion comp;int dma_ch; -int gpmc_irq; +int gpmc_irq_fifo; +int gpmc_irq_count;enum {OMAP_NAND_IO_READ =0 ,/* read */ OMAP_NAND_IO_WRITE ,/* write */
@@ -472,13 +473,11 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) {struct omap_nand_info *info = (struct omap_nand_info *) dev;u32 bytes; -u32 irq_stat; - irq_stat =gpmc_read_status (GPMC_GET_IRQ_STATUS ); bytes =gpmc_read_status (GPMC_PREFETCH_FIFO_CNT ); bytes = bytes &0xFFFC ;/* io in multiple of 4 bytes */ if (info->iomode ==OMAP_NAND_IO_WRITE ) {/* checks for write io */ -if (irq_stat &0x2 ) +if (this_irq == info->gpmc_irq_count) goto done;if (info->buf_len && (info->buf_len < bytes))
@@ -495,20 +494,17 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) (u32 *)info->buf, bytes >> 2); info->buf = info->buf + bytes; -if (irq_stat &0x2 ) +if (this_irq == info->gpmc_irq_count) goto done; } -gpmc_cs_configure (info->gpmc_cs,GPMC_SET_IRQ_STATUS , irq_stat);return IRQ_HANDLED ; done:complete (&info->comp); -/* disable irq */ -gpmc_cs_configure (info->gpmc_cs,GPMC_ENABLE_IRQ ,0 ); -/* clear status */ -gpmc_cs_configure (info->gpmc_cs,GPMC_SET_IRQ_STATUS , irq_stat); +disable_irq_nosync (info->gpmc_irq_fifo); +disable_irq_nosync (info->gpmc_irq_count);return IRQ_HANDLED ; }
@@ -542,9 +538,9 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len) goto out_copy; info->buf_len = len; -/* enable irq */ -gpmc_cs_configure (info->gpmc_cs,GPMC_ENABLE_IRQ , - (GPMC_IRQ_FIFOEVENTENABLE |GPMC_IRQ_COUNT_EVENT )); + +enable_irq (info->gpmc_irq_count); +enable_irq (info->gpmc_irq_fifo);/* waiting for read to complete */ wait_for_completion (&info->comp);
@@ -591,12 +587,13 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, goto out_copy; info->buf_len = len; -/* enable irq */ -gpmc_cs_configure (info->gpmc_cs,GPMC_ENABLE_IRQ , - (GPMC_IRQ_FIFOEVENTENABLE |GPMC_IRQ_COUNT_EVENT )); + +enable_irq (info->gpmc_irq_count); +enable_irq (info->gpmc_irq_fifo);/* waiting for write to complete */ wait_for_completion (&info->comp); +/* wait for data to flushed-out before reset the prefetch */ tim =0 ; limit = (loops_per_jiffy *msecs_to_jiffies (OMAP_NAND_TIMEOUT_MS ));
@@ -982,6 +979,14 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) goto out_release_mem_region; } + info->gpmc_irq_fifo =platform_get_irq (pdev,0 ); +if (info->gpmc_irq_fifo == -ENXIO ) +dev_warn (&pdev->dev,"error getting FIFO IRQ\n" ); + + info->gpmc_irq_count =platform_get_irq (pdev,1 ); +if (info->gpmc_irq_fifo == -ENXIO ) +dev_warn (&pdev->dev,"error getting TERMINALCOUNT IRQ\n" ); + info->nand.controller = &info->controller; info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
@@ -1037,17 +1042,24 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)break ;case NAND_OMAP_PREFETCH_IRQ : - err =request_irq (pdata->gpmc_irq, - omap_nand_irq,IRQF_SHARED ,"gpmc-nand" , info); + err =request_irq (info->gpmc_irq_fifo, omap_nand_irq, +IRQF_SHARED ,"gpmc-nand-fifo" , info);if (err) {dev_err (&pdev->dev,"requesting irq(%d) error:%d" , - pdata->gpmc_irq, err); + info->gpmc_irq_fifo, err); goto out_release_mem_region; - }else { - info->gpmc_irq = pdata->gpmc_irq; - info->nand.read_buf = omap_read_buf_irq_pref; - info->nand.write_buf = omap_write_buf_irq_pref; } + err =request_irq (info->gpmc_irq_count, omap_nand_irq, +IRQF_SHARED ,"gpmc-nand-count" , info); +if (err) { +dev_err (&pdev->dev,"requesting irq(%d) error:%d" , + info->gpmc_irq_count, err); + goto out_free_irq_gpmc_fifo; + } + + info->nand.read_buf = omap_read_buf_irq_pref; + info->nand.write_buf = omap_write_buf_irq_pref; +break ;default :
@@ -1117,6 +1129,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)return 0 ; +out_free_irq_gpmc_fifo: +free_irq (info->gpmc_irq_fifo, info); out_release_mem_region:release_mem_region (info->phys_base, info->mem_size); out_free_info:
@@ -1135,8 +1149,11 @@ static int omap_nand_remove(struct platform_device *pdev)if (info->dma_ch !=-1 )omap_free_dma (info->dma_ch); -if (info->gpmc_irq) -free_irq (info->gpmc_irq, info); +if (info->gpmc_irq_fifo >0 ) +free_irq (info->gpmc_irq_fifo, info); + +if (info->gpmc_irq_count >0 ) +free_irq (info->gpmc_irq_count, info);/* Release NAND device, its internal structures and partitions */ nand_release (&info->mtd);
Signature · 1 line
1.7.10
PATCH v4 17/39 mtd: nand: omap2: handle nand on gpmc
In reply to Afzal MohammedGPMC driver has been modified to fill NAND platform data with GPMC NAND register details. As these registers are accessible in NAND driver itself, configure NAND in GPMC by itself.
Note: Verfying that other CS have not yet enabled for prefetch & ecc has to be incorporated. Currently this causes no issues as there are no boards that use NAND on multiple CS. With GPMC modifications, perhaps it would be better to consider NAND connected on multiple CS as a single peripheral using multiple CS. This would make handling multiple CS issues easier.
--- drivers/mtd/nand/omap2.c | 209 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 165 insertions(+), 44 deletions(-)
drivers/mtd/nand/omap2.c +165 -44
@@ -129,8 +129,79 @@ struct omap_nand_info { } iomode;u_char *buf;int buf_len; +struct gpmc_nand_regs reg; }; +#define PREFETCH_CONFIG1_CS_SHIFT 24 +#define ECC_CONFIG_CS_SHIFT 1 +#define CS_MASK 0x7 +#define ENABLE_PREFETCH (0x1 << 7) +#define DMA_MPU_MODE_SHIFT 2 +#define ECCSIZE1_SHIFT 22 +#define ECC1RESULTSIZE 0x1 +#define ECC_CLEAR_SHIFT 8 +#define ECC1 0x1 + +/** +* omap_prefetch_enable - configures and starts prefetch transfer +* @cs: cs (chip select) number +* @fifo_th: fifo threshold to be used for read/ write +* @dma_mode: dma mode enable (1) or disable (0) +* @u32_count: number of bytes to be transferred +* @is_write: prefetch read(0) or write post(1) mode +*/ +static int omap_prefetch_enable (int cs,int fifo_th,int dma_mode, +unsigned int u32_count,int is_write,struct omap_nand_info *info) +{ +u32 val; + +if (fifo_th >PREFETCH_FIFOTHRESHOLD_MAX ) { +pr_err ("gpmc: fifo threshold is not supported\n" ); +return -1 ; + }else if (!(readl (info->reg.gpmc_prefetch_control))) { +/* Set the amount of bytes to be prefetched */ +writel (u32_count, info->reg.gpmc_prefetch_config2); + +/* Set dma/mpu mode, the prefetch read / post write and +* enable the engine. Set which cs is has requested for. +*/ + val = ((cs <<PREFETCH_CONFIG1_CS_SHIFT ) | +PREFETCH_FIFOTHRESHOLD (fifo_th) | +ENABLE_PREFETCH | + (dma_mode <<DMA_MPU_MODE_SHIFT ) | + (0x1 & is_write)); +writel (val, info->reg.gpmc_prefetch_config1); + +/* Start the prefetch engine */ +writel (0x1 , info->reg.gpmc_prefetch_control); + }else { +return -EBUSY ; + } + +return 0 ; +} + +/** +* omap_prefetch_reset - disables and stops the prefetch engine +*/ +static int omap_prefetch_reset (int cs,struct omap_nand_info *info) +{ +u32 config1; + +/* check if the same module/cs is trying to reset */ + config1 =readl (info->reg.gpmc_prefetch_config1); +if (((config1 >>PREFETCH_CONFIG1_CS_SHIFT ) &CS_MASK ) != cs) +return -EINVAL ; + +/* Stop the PFPW engine */ +writel (0x0 , info->reg.gpmc_prefetch_control); + +/* Reset/disable the PFPW engine */ +writel (0x0 , info->reg.gpmc_prefetch_config1); + +return 0 ; +} +/** * omap_hwcontrol - hardware specific access to control-lines * @mtd: MTD device structure
@@ -149,13 +220,13 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)if (cmd !=NAND_CMD_NONE ) {if (ctrl &NAND_CLE ) -gpmc_nand_write (info->gpmc_cs,GPMC_NAND_COMMAND , cmd); +writeb (cmd, info->reg.gpmc_nand_command);else if (ctrl &NAND_ALE ) -gpmc_nand_write (info->gpmc_cs,GPMC_NAND_ADDRESS , cmd); +writeb (cmd, info->reg.gpmc_nand_address);else /* NAND_NCE */ -gpmc_nand_write (info->gpmc_cs,GPMC_NAND_DATA , cmd); +writeb (cmd, info->reg.gpmc_nand_data); } }
@@ -189,7 +260,8 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)iowrite8 (*p++, info->nand.IO_ADDR_W);/* wait until buffer is available for write */ do { - status =gpmc_read_status (GPMC_STATUS_BUFFER ); + status =readl (info->reg.gpmc_status) & +GPMC_STATUS_BUFF_EMPTY ; }while (!status); } }
@@ -226,7 +298,8 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)iowrite16 (*p++, info->nand.IO_ADDR_W);/* wait until buffer is available for write */ do { - status =gpmc_read_status (GPMC_STATUS_BUFFER ); + status =readl (info->reg.gpmc_status) & +GPMC_STATUS_BUFF_EMPTY ; }while (!status); } }
@@ -256,8 +329,8 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) }/* configure and start prefetch transfer */ - ret =gpmc_prefetch_enable (info->gpmc_cs, -PREFETCH_FIFOTHRESHOLD_MAX ,0x0 , len,0x0 ); + ret =omap_prefetch_enable (info->gpmc_cs, +PREFETCH_FIFOTHRESHOLD_MAX ,0x0 , len,0x0 , info);if (ret) {/* PFPW engine is busy, use cpu copy method */ if (info->nand.options &NAND_BUSWIDTH_16 )
@@ -266,14 +339,15 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)omap_read_buf8 (mtd, (u_char *)p, len); }else {do { - r_count =gpmc_read_status (GPMC_PREFETCH_FIFO_CNT ); + r_count =readl (info->reg.gpmc_prefetch_status); + r_count =GPMC_PREFETCH_STATUS_FIFO_CNT (r_count); r_count = r_count >>2 ;ioread32_rep (info->nand.IO_ADDR_R, p, r_count); p += r_count; len -= r_count <<2 ; }while (len);/* disable and stop the PFPW engine */ -gpmc_prefetch_reset (info->gpmc_cs); +omap_prefetch_reset (info->gpmc_cs, info); } }
@@ -292,6 +366,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,int i =0 , ret =0 ;u16 *p = (u16 *)buf;unsigned long tim, limit; +u32 val;/* take care of subpage writes */ if (len %2 !=0 ) {
@@ -301,8 +376,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd, }/* configure and start prefetch transfer */ - ret =gpmc_prefetch_enable (info->gpmc_cs, -PREFETCH_FIFOTHRESHOLD_MAX ,0x0 , len,0x1 ); + ret =omap_prefetch_enable (info->gpmc_cs, +PREFETCH_FIFOTHRESHOLD_MAX ,0x0 , len,0x1 , info);if (ret) {/* PFPW engine is busy, use cpu copy method */ if (info->nand.options &NAND_BUSWIDTH_16 )
@@ -311,7 +386,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd,omap_write_buf8 (mtd, (u_char *)p, len); }else {while (len) { - w_count =gpmc_read_status (GPMC_PREFETCH_FIFO_CNT ); + w_count =readl (info->reg.gpmc_prefetch_status); + w_count =GPMC_PREFETCH_STATUS_FIFO_CNT (w_count); w_count = w_count >>1 ;for (i =0 ; (i < w_count) && len; i++, len -=2 )iowrite16 (*p++, info->nand.IO_ADDR_W);
@@ -320,11 +396,14 @@ static void omap_write_buf_pref(struct mtd_info *mtd, tim =0 ; limit = (loops_per_jiffy *msecs_to_jiffies (OMAP_NAND_TIMEOUT_MS )); -while (gpmc_read_status (GPMC_PREFETCH_COUNT ) && (tim++ < limit)) +do {cpu_relax (); + val =readl (info->reg.gpmc_prefetch_status); + val =GPMC_PREFETCH_STATUS_COUNT (val); + }while (val && (tim++ < limit));/* disable and stop the PFPW engine */ -gpmc_prefetch_reset (info->gpmc_cs); +omap_prefetch_reset (info->gpmc_cs, info); } }
@@ -356,6 +435,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,dma_addr_t dma_addr;int ret;unsigned long tim, limit; +u32 val;/* The fifo depth is 64 bytes max. * But configure the FIFO-threahold to 32 to get a sync at each frame
@@ -400,8 +480,8 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, OMAP24XX_DMA_GPMC, OMAP_DMA_SRC_SYNC); }/* configure and start prefetch transfer */ - ret =gpmc_prefetch_enable (info->gpmc_cs, -PREFETCH_FIFOTHRESHOLD_MAX ,0x1 , len, is_write); + ret =omap_prefetch_enable (info->gpmc_cs, +PREFETCH_FIFOTHRESHOLD_MAX ,0x1 , len, is_write, info);if (ret)/* PFPW engine is busy, use cpu copy method */ goto out_copy;
@@ -414,11 +494,15 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,wait_for_completion (&info->comp); tim =0 ; limit = (loops_per_jiffy *msecs_to_jiffies (OMAP_NAND_TIMEOUT_MS )); -while (gpmc_read_status (GPMC_PREFETCH_COUNT ) && (tim++ < limit)) + +do {cpu_relax (); + val =readl (info->reg.gpmc_prefetch_status); + val =GPMC_PREFETCH_STATUS_COUNT (val); + }while (val && (tim++ < limit));/* disable and stop the PFPW engine */ -gpmc_prefetch_reset (info->gpmc_cs); +omap_prefetch_reset (info->gpmc_cs, info);dma_unmap_single (&info->pdev->dev, dma_addr, len, dir);return 0 ;
@@ -474,7 +558,8 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)struct omap_nand_info *info = (struct omap_nand_info *) dev;u32 bytes; - bytes =gpmc_read_status (GPMC_PREFETCH_FIFO_CNT ); + bytes =readl (info->reg.gpmc_prefetch_status); + bytes =GPMC_PREFETCH_STATUS_FIFO_CNT (bytes); bytes = bytes &0xFFFC ;/* io in multiple of 4 bytes */ if (info->iomode ==OMAP_NAND_IO_WRITE ) {/* checks for write io */ if (this_irq == info->gpmc_irq_count)
@@ -531,8 +616,8 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)init_completion (&info->comp);/* configure and start prefetch transfer */ - ret =gpmc_prefetch_enable (info->gpmc_cs, -PREFETCH_FIFOTHRESHOLD_MAX /2 ,0x0 , len,0x0 ); + ret =omap_prefetch_enable (info->gpmc_cs, +PREFETCH_FIFOTHRESHOLD_MAX /2 ,0x0 , len,0x0 , info);if (ret)/* PFPW engine is busy, use cpu copy method */ goto out_copy;
@@ -546,7 +631,7 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)wait_for_completion (&info->comp);/* disable and stop the PFPW engine */ -gpmc_prefetch_reset (info->gpmc_cs); +omap_prefetch_reset (info->gpmc_cs, info);return ; out_copy:
@@ -569,6 +654,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, struct omap_nand_info, mtd);int ret =0 ;unsigned long tim, limit; +u32 val;if (len <= mtd->oobsize) {omap_write_buf_pref (mtd, buf, len);
@@ -580,8 +666,8 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,init_completion (&info->comp);/* configure and start prefetch transfer : size=24 */ - ret =gpmc_prefetch_enable (info->gpmc_cs, - (PREFETCH_FIFOTHRESHOLD_MAX *3 ) /8 ,0x0 , len,0x1 ); + ret =omap_prefetch_enable (info->gpmc_cs, + (PREFETCH_FIFOTHRESHOLD_MAX *3 ) /8 ,0x0 , len,0x1 , info);if (ret)/* PFPW engine is busy, use cpu copy method */ goto out_copy;
@@ -597,11 +683,14 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,/* wait for data to flushed-out before reset the prefetch */ tim =0 ; limit = (loops_per_jiffy *msecs_to_jiffies (OMAP_NAND_TIMEOUT_MS )); -while (gpmc_read_status (GPMC_PREFETCH_COUNT ) && (tim++ < limit)) +do { + val =readl (info->reg.gpmc_prefetch_status); + val =GPMC_PREFETCH_STATUS_COUNT (val);cpu_relax (); + }while (val && (tim++ < limit));/* disable and stop the PFPW engine */ -gpmc_prefetch_reset (info->gpmc_cs); +omap_prefetch_reset (info->gpmc_cs, info);return ; out_copy:
@@ -841,7 +930,20 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat, { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); -return gpmc_calculate_ecc (info->gpmc_cs, dat, ecc_code); +u32 val; + + val =readl (info->reg.gpmc_ecc_config); +if (((val >>ECC_CONFIG_CS_SHIFT ) & ~CS_MASK ) != info->gpmc_cs) +return -EINVAL ; + +/* read ecc result */ + val =readl (info->reg.gpmc_ecc1_result); + *ecc_code++ = val;/* P128e, ..., P1e */ + *ecc_code++ = val >>16 ;/* P128o, ..., P1o */ +/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */ + *ecc_code++ = ((val >>8 ) &0x0f ) | ((val >>20 ) &0xf0 ); + +return 0 ; }/**
@@ -855,8 +957,36 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) mtd);struct nand_chip *chip = mtd->priv;unsigned int dev_width = (chip->options &NAND_BUSWIDTH_16 ) ?1 :0 ; +u32 val; + +/* clear ecc and enable bits */ + val = ((0x1 <<ECC_CLEAR_SHIFT ) |ECC1 ); +writel (val, info->reg.gpmc_ecc_control); + +/* program ecc and result sizes */ + val = ((((info->nand.ecc.size >>1 ) -1 ) <<ECCSIZE1_SHIFT ) | +ECC1RESULTSIZE ); +writel (val, info->reg.gpmc_ecc_size_config); + +switch (mode) { +case NAND_ECC_READ : +writel (0x101 , info->reg.gpmc_ecc_control); +break ; +case NAND_ECC_READSYN : +writel (0x100 , info->reg.gpmc_ecc_control); +break ; +case NAND_ECC_WRITE : +writel (0x101 , info->reg.gpmc_ecc_control); +break ; +default : +dev_info (&info->pdev->dev, +"error: unrecognized Mode[%d]!\n" , mode); +break ; + } -gpmc_enable_hwecc (info->gpmc_cs, mode, dev_width, info->nand.ecc.size); +/* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */ + val = (dev_width <<7 ) | (info->gpmc_cs <<1 ) | (0x1 ); +writel (val, info->reg.gpmc_ecc_config); }/**
@@ -884,10 +1014,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)else timeo += (HZ *20 ) /1000 ; -gpmc_nand_write (info->gpmc_cs, -GPMC_NAND_COMMAND , (NAND_CMD_STATUS &0xFF )); +writeb (NAND_CMD_STATUS &0xFF , info->reg.gpmc_nand_command);while (time_before (jiffies, timeo)) { - status =gpmc_nand_read (info->gpmc_cs,GPMC_NAND_DATA ); + status =readb (info->reg.gpmc_nand_data);if (status &NAND_STATUS_READY )break ;cond_resched ();
@@ -905,22 +1034,13 @@ static int omap_dev_ready(struct mtd_info *mtd) struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - val =gpmc_read_status (GPMC_GET_IRQ_STATUS ); + val =readl (info->reg.gpmc_status); +if ((val &0x100 ) ==0x100 ) { -/* Clear IRQ Interrupt */ - val |=0x100 ; - val &= ~(0x0 ); -gpmc_cs_configure (info->gpmc_cs,GPMC_SET_IRQ_STATUS , val); +return 1 ; }else { -unsigned int cnt =0 ; -while (cnt++ <0x1FF ) { -if ((val &0x100 ) ==0x100 ) -return 0 ; - val =gpmc_read_status (GPMC_GET_IRQ_STATUS ); - } +return 0 ; } - -return 1 ; }static int __devinit omap_nand_probe (struct platform_device *pdev)
@@ -949,6 +1069,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->pdev = pdev; info->gpmc_cs = pdata->cs; + info->reg = pdata->reg; info->mtd.priv = &info->nand; info->mtd.name =dev_name (&pdev->dev);
Signature · 1 line
1.7.10
PATCH v4 18/39 mtd: onenand: omap: obtain memory from resource
In reply to Afzal Mohammedgpmc being converted to driver, provides drivers of peripheral connected memory space used by the peripheral as memory resource. Modify nand omap driver to obtain memory detials from resource structure. And so remove usage of gpmc exported symbols.
--- drivers/mtd/onenand/omap2.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-)
drivers/mtd/onenand/omap2.c +16 -13
@@ -48,13 +48,13 @@#define DRIVER_NAME "omap2-onenand" -#define ONENAND_IO_SIZE SZ_128K#define ONENAND_BUFRAM_SIZE (1024 * 5)struct omap2_onenand {struct platform_device *pdev;int gpmc_cs;unsigned long phys_base; +unsigned int mem_size;int gpio_irq;struct mtd_info mtd;struct onenand_chip onenand;
@@ -626,6 +626,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)struct omap2_onenand *c;struct onenand_chip *this;int r; +struct resource *res; pdata = pdev->dev.platform_data;if (pdata ==NULL ) {
@@ -647,20 +648,24 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) c->gpio_irq =0 ; } - r =gpmc_cs_request (c->gpmc_cs,ONENAND_IO_SIZE , &c->phys_base); -if (r <0 ) { -dev_err (&pdev->dev,"Cannot request GPMC CS\n" ); + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (res ==NULL ) { + r = -EINVAL ; +dev_err (&pdev->dev,"error getting memory resource\n" ); goto err_kfree; } -if (request_mem_region (c->phys_base,ONENAND_IO_SIZE , + c->phys_base = res->start; + c->mem_size =resource_size (res); + +if (request_mem_region (c->phys_base, c->mem_size, pdev->dev.driver->name) ==NULL ) { -dev_err (&pdev->dev,"Cannot reserve memory region at 0x%08lx, " -"size: 0x%x\n" , c->phys_base,ONENAND_IO_SIZE ); +dev_err (&pdev->dev,"Cannot reserve memory region at 0x%08lx, size: 0x%x\n" , + c->phys_base, c->mem_size); r = -EBUSY ; - goto err_free_cs; + goto err_kfree; } - c->onenand.base =ioremap (c->phys_base,ONENAND_IO_SIZE ); + c->onenand.base =ioremap (c->phys_base, c->mem_size);if (c->onenand.base ==NULL ) { r = -ENOMEM ; goto err_release_mem_region;
@@ -776,9 +781,7 @@ err_release_gpio: err_iounmap:iounmap (c->onenand.base); err_release_mem_region: -release_mem_region (c->phys_base,ONENAND_IO_SIZE ); -err_free_cs: -gpmc_cs_free (c->gpmc_cs); +release_mem_region (c->phys_base, c->mem_size); err_kfree:kfree (c);
@@ -800,7 +803,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)gpio_free (c->gpio_irq); }iounmap (c->onenand.base); -release_mem_region (c->phys_base,ONENAND_IO_SIZE ); +release_mem_region (c->phys_base, c->mem_size);gpmc_cs_free (c->gpmc_cs);kfree (c);
Signature · 1 line
1.7.10
PATCH v4 19/39 ARM: OMAP2+: board omap3evm: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information
--- arch/arm/mach-omap2/board-omap3evm.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/board-omap3evm.c +13 -1
@@ -43,6 +43,7 @@#include <plat/board.h> #include <plat/usb.h> +#include <plat/gpmc.h> #include "common.h" #include <plat/mcspi.h> #include <video/omapdss.h>
@@ -102,6 +103,12 @@ static void __init omap3_evm_get_revision(void) } } +static struct gpmc_device_pdata *gpmc_device_data[1 ]; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +#if defined(CONFIG_SMSC911X ) || defined(CONFIG_SMSC911X_MODULE )#include <plat/gpmc-smsc911x.h>
@@ -122,7 +129,11 @@ static inline void __init omap3evm_init_smsc911x(void) smsc911x_cfg.gpio_reset = OMAP3EVM_GEN2_ETHR_GPIO_RST; } -gpmc_smsc911x_init (&smsc911x_cfg); + *gpmc_device_data =gpmc_smsc911x_init (&smsc911x_cfg); +if (*gpmc_device_data) + gpmc_data.num_device++; +else +pr_err ("error: unable to initilaize gpmc smsc911x\n" ); }#else
@@ -679,6 +690,7 @@ static void __init omap3_evm_init(void)usbhs_init (&usbhs_bdata);omap_ads7846_init (1 ,OMAP3_EVM_TS_GPIO ,310 ,NULL );omap3evm_init_smsc911x (); +omap_init_gpmc (&gpmc_data);omap3_evm_display_init ();omap3_evm_wl12xx_init (); }
Signature · 1 line
1.7.10
PATCH v4 20/39 ARM: OMAP2+: board omap3beagle: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information
--- arch/arm/mach-omap2/board-omap3beagle.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/board-omap3beagle.c +17 -1
@@ -517,8 +517,16 @@ static void __init beagle_opp_init(void)return ; } +static struct gpmc_device_pdata *gpmc_device_data[1 ]; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +static void __init omap3_beagle_init (void ) { +struct omap_nand_platform_data *nand_data; +omap3_mux_init (board_mux,OMAP_PACKAGE_CBB );omap3_beagle_init_rev ();
@@ -543,9 +551,17 @@ static void __init omap3_beagle_init(void)usb_musb_init (NULL );usbhs_init (&usbhs_bdata); -board_nand_init (omap3beagle_nand_partitions, + nand_data =board_nand_init (omap3beagle_nand_partitions,ARRAY_SIZE (omap3beagle_nand_partitions),GPMC_CS_NUM ,NAND_BUSWIDTH_16 ,NULL ); +if (nand_data !=NULL ) { + *gpmc_device_data =gpmc_nand_init (nand_data); +if (*gpmc_device_data) + gpmc_data.num_device++; + }else +pr_err ("error: %s: nand init\n" , __func__); + +omap_init_gpmc (&gpmc_data);/* Ensure msecure is mux'd to be able to set the RTC. */ omap_mux_init_signal ("sys_drm_msecure" ,OMAP_PIN_OFF_OUTPUT_HIGH );
Signature · 1 line
1.7.10
PATCH v4 21/39 ARM: OMAP2+: board apollon: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information. It is believed that apollon board was added before gpmc-smc91x helper functions were added. Reuse the now available gpmc_smc91x_init adapted for gpmc driver.
Note: Timing values were hardcoded and written onto registers, whether making use of gpmc_smc91x_init would configure timing properly has to be tested.
--- arch/arm/mach-omap2/board-apollon.c | 152 +++++++++-------------------------- 1 file changed, 38 insertions(+), 114 deletions(-)
arch/arm/mach-omap2/board-apollon.c +38 -114
@@ -39,6 +39,7 @@#include <plat/board.h> #include "common.h" #include <plat/gpmc.h> +#include <plat/gpmc-smc91x.h> #include <video/omapdss.h> #include <video/omap-panel-generic-dpi.h>
@@ -58,6 +59,12 @@#define APOLLON_ETH_CS 1#define APOLLON_ETHR_GPIO_IRQ 74 +static struct gpmc_device_pdata *gpmc_device_data[2 ]; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +static struct mtd_partition apollon_partitions[] = { { .name ="X-Loader + U-Boot" ,
@@ -97,57 +104,26 @@ static struct onenand_platform_data apollon_flash_data = { .nr_parts = ARRAY_SIZE(apollon_partitions), }; -static struct resource apollon_flash_resource[] = { - [0 ] = { - .flags =IORESOURCE_MEM , - }, +static struct gpmc_cs_data apollon_gpmc_onenand_cs_data = { + .cs =APOLLON_FLASH_CS , + .mem_size =SZ_128K , }; -static struct platform_device apollon_onenand_device = { +static struct gpmc_device_pdata apollon_gpmc_onenand_data = { .name ="onenand-flash" , .id =-1 , - .dev = { - .platform_data = &apollon_flash_data, - }, - .num_resources =ARRAY_SIZE (apollon_flash_resource), - .resource = apollon_flash_resource, -}; - -static void __init apollon_flash_init (void ) -{ -unsigned long base; - -if (gpmc_cs_request (APOLLON_FLASH_CS ,SZ_128K , &base) <0 ) { -printk (KERN_ERR "Cannot request OneNAND GPMC CS\n" ); -return ; - } - apollon_flash_resource[0 ].start = base; - apollon_flash_resource[0 ].end = base +SZ_128K -1 ; -} - -static struct smc91x_platdata appolon_smc91x_info = { - .flags =SMC91X_USE_16BIT |SMC91X_NOWAIT , - .leda =RPC_LED_100_10 , - .ledb =RPC_LED_TX_RX , + .pdata = &apollon_flash_data, + .pdata_size =sizeof (apollon_flash_data), + .cs_data = &apollon_gpmc_onenand_cs_data, + .num_cs =1 , }; -static struct resource apollon_smc91x_resources[] = { - [0 ] = { - .flags =IORESOURCE_MEM , - }, - [1 ] = { - .flags =IORESOURCE_IRQ |IORESOURCE_IRQ_HIGHEDGE , - }, -}; - -static struct platform_device apollon_smc91x_device = { - .name ="smc91x" , - .id =-1 , - .dev = { - .platform_data = &appolon_smc91x_info, - }, - .num_resources =ARRAY_SIZE (apollon_smc91x_resources), - .resource = apollon_smc91x_resources, +static struct omap_smc91x_platform_data apollon_smc91x_data = { + .gpio_irq =APOLLON_ETHR_GPIO_IRQ , + .cs =APOLLON_ETH_CS , + .wait_pin =GPMC_WAITPIN_1 , + .flags =GPMC_TIMINGS_SMC91C96 |IORESOURCE_IRQ_HIGHEDGE | +GPMC_MUXADDDATA , };static struct omap_led_config apollon_led_config[] = {
@@ -185,74 +161,9 @@ static struct platform_device apollon_led_device = { };static struct platform_device *apollon_devices[]__initdata = { - &apollon_onenand_device, - &apollon_smc91x_device, &apollon_led_device, }; -static inline void __init apollon_init_smc91x (void ) -{ -unsigned long base; - -unsigned int rate; -struct clk *gpmc_fck; -int eth_cs; -int err; - - gpmc_fck =clk_get (NULL ,"gpmc_fck" );/* Always on ENABLE_ON_INIT */ -if (IS_ERR (gpmc_fck)) { -WARN_ON (1 ); -return ; - } - -clk_enable (gpmc_fck); - rate =clk_get_rate (gpmc_fck); - - eth_cs =APOLLON_ETH_CS ; - -/* Make sure CS1 timings are correct */ -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG1 ,0x00011200 ); - -if (rate >=160000000 ) { -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG2 ,0x001f1f01 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG3 ,0x00080803 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG4 ,0x1c0b1c0a ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG5 ,0x041f1F1F ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG6 ,0x000004C4 ); - }else if (rate >=130000000 ) { -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG2 ,0x001f1f00 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG3 ,0x00080802 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG4 ,0x1C091C09 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG5 ,0x041f1F1F ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG6 ,0x000004C4 ); - }else {/* rate = 100000000 */ -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG2 ,0x001f1f00 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG3 ,0x00080802 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG4 ,0x1C091C09 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG5 ,0x031A1F1F ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG6 ,0x000003C2 ); - } - -if (gpmc_cs_request (APOLLON_ETH_CS ,SZ_16M , &base) <0 ) { -printk (KERN_ERR "Failed to request GPMC CS for smc91x\n" ); - goto out; - } - apollon_smc91x_resources[0 ].start = base +0x300 ; - apollon_smc91x_resources[0 ].end = base +0x30f ; -udelay (100 ); - -omap_mux_init_gpio (APOLLON_ETHR_GPIO_IRQ ,0 ); - err =gpio_request_one (APOLLON_ETHR_GPIO_IRQ ,GPIOF_IN ,"SMC91x irq" ); -if (err) { -printk (KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n" , -APOLLON_ETHR_GPIO_IRQ ); -gpmc_cs_free (APOLLON_ETH_CS ); - } -out: -clk_disable (gpmc_fck); -clk_put (gpmc_fck); -} -static struct omap_usb_config apollon_usb_config__initdata = { .register_dev =1 , .hmc_mode =0x14 ,/* 0:dev 1:host1 2:disable */
@@ -315,12 +226,27 @@ static struct omap_board_mux board_mux[] __initdata = {static void __init omap_apollon_init (void ) {u32 v; +int err, idx =0 ;omap2420_mux_init (board_mux,OMAP_PACKAGE_ZAC ); -apollon_init_smc91x (); + gpmc_device_data[idx++] = &apollon_gpmc_onenand_data; + gpmc_data.num_device++; + +omap_mux_init_gpio (apollon_smc91x_data.gpio_irq,0 ); + err =gpio_request_one (apollon_smc91x_data.gpio_irq, +GPIOF_IN ,"SMC91x irq" ); +if (err) { +pr_err ("error: %s: Failed to request GPIO%d for smc91x IRQ\n" , + __func__, apollon_smc91x_data.gpio_irq); + }else { + gpmc_device_data[idx++] = +gpmc_smc91x_init (&apollon_smc91x_data); + gpmc_data.num_device++; + } +omap_init_gpmc (&gpmc_data); +apollon_led_init (); -apollon_flash_init ();apollon_usb_init ();/* REVISIT: where's the correct place */
@@ -339,8 +265,6 @@ static void __init omap_apollon_init(void)* You have to mux them off in device drivers later on * if not needed. */ - apollon_smc91x_resources[1 ].start =gpio_to_irq (APOLLON_ETHR_GPIO_IRQ ); - apollon_smc91x_resources[1 ].end =gpio_to_irq (APOLLON_ETHR_GPIO_IRQ );platform_add_devices (apollon_devices,ARRAY_SIZE (apollon_devices));omap_serial_init ();omap_sdrc_init (NULL ,NULL );
Signature · 1 line
1.7.10
PATCH v4 22/39 ARM: OMAP2+: board h4: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information. Remove unused h4_init_debug too.
--- arch/arm/mach-omap2/board-h4.c | 130 +++++----------------------------------- 1 file changed, 15 insertions(+), 115 deletions(-)
arch/arm/mach-omap2/board-h4.c +15 -115
@@ -186,22 +186,24 @@ static struct physmap_flash_data h4_flash_data = { .nr_parts = ARRAY_SIZE(h4_partitions), }; -static struct resource h4_flash_resource = { - .flags =IORESOURCE_MEM , +static struct gpmc_cs_data h4_gpmc_cs_flash_data = { + .cs =H4_FLASH_CS , + .mem_size =SZ_64M , }; -static struct platform_device h4_flash_device = { +static struct gpmc_device_pdata h4_gpmc_flash_data = { .name ="physmap-flash" , .id =0 , - .dev = { - .platform_data = &h4_flash_data, - }, - .num_resources =1 , - .resource = &h4_flash_resource, + .pdata = &h4_flash_data, + .pdata_size =sizeof (h4_flash_data), + .cs_data = &h4_gpmc_cs_flash_data, + .num_cs =1 , }; -static struct platform_device *h4_devices[]__initdata = { - &h4_flash_device, +static struct gpmc_device_pdata *gpmc_device_data[1 ]; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, };static struct panel_generic_dpi_data h4_panel_data = {
@@ -226,109 +228,6 @@ static struct omap_dss_board_info h4_dss_data = { .default_device = &h4_lcd_device, }; -/* 2420 Sysboot setup (2430 is different) */ -static u32 get_sysboot_value (void ) -{ -return (omap_ctrl_readl (OMAP24XX_CONTROL_STATUS ) & - (OMAP2_SYSBOOT_5_MASK |OMAP2_SYSBOOT_4_MASK | -OMAP2_SYSBOOT_3_MASK |OMAP2_SYSBOOT_2_MASK | -OMAP2_SYSBOOT_1_MASK |OMAP2_SYSBOOT_0_MASK )); -} - -/* H4-2420's always used muxed mode, H4-2422's always use non-muxed -* -* Note: OMAP-GIT doesn't correctly do is_cpu_omap2422 and is_cpu_omap2423 -* correctly. The macro needs to look at production_id not just hawkeye. -*/ -static u32 is_gpmc_muxed (void ) -{ -u32 mux; - mux =get_sysboot_value (); -if ((mux &0xF ) ==0xd ) -return 1 ;/* NAND config (could be either) */ -if (mux &0x2 )/* if mux'ed */ -return 1 ; -else -return 0 ; -} - -static inline void __init h4_init_debug (void ) -{ -int eth_cs; -unsigned long cs_mem_base; -unsigned int muxed, rate; -struct clk *gpmc_fck; - - eth_cs =H4_SMC91X_CS ; - - gpmc_fck =clk_get (NULL ,"gpmc_fck" );/* Always on ENABLE_ON_INIT */ -if (IS_ERR (gpmc_fck)) { -WARN_ON (1 ); -return ; - } - -clk_enable (gpmc_fck); - rate =clk_get_rate (gpmc_fck); -clk_disable (gpmc_fck); -clk_put (gpmc_fck); - -if (is_gpmc_muxed ()) - muxed =0x200 ; -else - muxed =0 ; - -/* Make sure CS1 timings are correct */ -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG1 , -0x00011000 | muxed); - -if (rate >=160000000 ) { -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG2 ,0x001f1f01 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG3 ,0x00080803 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG4 ,0x1c0b1c0a ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG5 ,0x041f1F1F ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG6 ,0x000004C4 ); - }else if (rate >=130000000 ) { -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG2 ,0x001f1f00 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG3 ,0x00080802 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG4 ,0x1C091C09 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG5 ,0x041f1F1F ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG6 ,0x000004C4 ); - }else {/* rate = 100000000 */ -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG2 ,0x001f1f00 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG3 ,0x00080802 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG4 ,0x1C091C09 ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG5 ,0x031A1F1F ); -gpmc_cs_write_reg (eth_cs,GPMC_CS_CONFIG6 ,0x000003C2 ); - } - -if (gpmc_cs_request (eth_cs,SZ_16M , &cs_mem_base) <0 ) { -printk (KERN_ERR "Failed to request GPMC mem for smc91x\n" ); - goto out; - } - -udelay (100 ); - -omap_mux_init_gpio (92 ,0 ); -if (debug_card_init (cs_mem_base,H4_ETHR_GPIO_IRQ ) <0 ) -gpmc_cs_free (eth_cs); - -out: -clk_disable (gpmc_fck); -clk_put (gpmc_fck); -} - -static void __init h4_init_flash (void ) -{ -unsigned long base; - -if (gpmc_cs_request (H4_FLASH_CS ,SZ_64M , &base) <0 ) { -printk ("Can't request GPMC CS for flash\n" ); -return ; - } - h4_flash_resource.start = base; - h4_flash_resource.end = base +SZ_64M -1 ; -} -static struct omap_usb_config h4_usb_config__initdata = {/* S1.10 OFF -- usb "download port" * usb0 switched to Mini-B port and isp1105 transceiver;
@@ -380,11 +279,12 @@ static void __init omap_h4_init(void)i2c_register_board_info (1 , h4_i2c_board_info,ARRAY_SIZE (h4_i2c_board_info)); -platform_add_devices (h4_devices,ARRAY_SIZE (h4_devices));omap2_usbfs_init (&h4_usb_config);omap_serial_init ();omap_sdrc_init (NULL ,NULL ); -h4_init_flash (); + *gpmc_device_data = &h4_gpmc_flash_data; + gpmc_data.num_device++; +omap_init_gpmc (&gpmc_data);omap_display_init (&h4_dss_data); }
Signature · 1 line
1.7.10
PATCH v4 23/39 ARM: OMAP2+: board 3630sdp: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-3630sdp.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-)
arch/arm/mach-omap2/board-3630sdp.c +19 -4
@@ -27,18 +27,29 @@#include "mux.h" #include "sdram-hynix-h8mbx00u0mer-0em.h" +static struct gpmc_device_pdata *gpmc_device_data[4 ]; +static struct gpmc_device_pdata **gpmc_cur = gpmc_device_data; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +#if defined(CONFIG_SMC91X ) || defined(CONFIG_SMC91X_MODULE )static struct omap_smc91x_platform_data board_smc91x_data = { .cs =3 , .flags =GPMC_MUX_ADD_DATA |IORESOURCE_IRQ_LOWLEVEL , .skip_timing = true, + .gpio_irq =158 , };static void __init board_smc91x_init (void ) { - board_smc91x_data.gpio_irq =158 ; -gpmc_smc91x_init (&board_smc91x_data); + *gpmc_cur =gpmc_smc91x_init (&board_smc91x_data); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else +pr_err ("error: unable to initilaize gpmc smsc911x\n" ); }#else
@@ -204,9 +215,13 @@ static void __init omap_sdp_init(void)omap_sdrc_init (h8mbx00u0mer0em_sdrc_params, h8mbx00u0mer0em_sdrc_params);zoom_display_init (); +board_smc91x_init (); -board_flash_init (sdp_flash_partitions, chip_sel_sdp, -NAND_BUSWIDTH_16 ,NULL ); + gpmc_data.num_device +=board_flash_init (sdp_flash_partitions, + chip_sel_sdp,NAND_BUSWIDTH_16 , + gpmc_cur) - gpmc_cur; +omap_init_gpmc (&gpmc_data); +enable_board_wakeup_source ();usbhs_init (&usbhs_bdata); }
Signature · 1 line
1.7.10
PATCH v4 24/39 ARM: OMAP2+: board 3430sdp: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-3430sdp.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/board-3430sdp.c +15 -2
@@ -59,6 +59,12 @@#define TWL4030_MSECURE_GPIO 22 +static struct gpmc_device_pdata *gpmc_device_data[4 ]; +static struct gpmc_device_pdata **gpmc_cur = gpmc_device_data; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +};static uint32_t board_keymap[] = {KEY (0 ,0 ,KEY_LEFT ),KEY (0 ,1 ,KEY_RIGHT ),
@@ -444,7 +450,11 @@ static void __init board_smc91x_init(void) else board_smc91x_data.gpio_irq = 29; - gpmc_smc91x_init(&board_smc91x_data); + *gpmc_cur =gpmc_smc91x_init (&board_smc91x_data); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else + pr_err("error: unable to initilaize gpmc smsc911x\n"); }#else
@@ -621,7 +631,10 @@ static void __init omap_3430sdp_init(void)omap_sdrc_init (hyb18m512160af6_sdrc_params,NULL );usb_musb_init (NULL );board_smc91x_init (); -board_flash_init (sdp_flash_partitions, chip_sel_3430,0 ,NULL ); + gpmc_data.num_device +=board_flash_init (sdp_flash_partitions, + chip_sel_3430,0 , gpmc_cur) - gpmc_cur; +omap_init_gpmc (&gpmc_data); +sdp3430_display_init ();enable_board_wakeup_source ();usbhs_init (&usbhs_bdata);
Signature · 1 line
1.7.10
PATCH v4 25/39 ARM: OMAP2+: board 2430sdp: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-2430sdp.c | 42 +++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 17 deletions(-)
arch/arm/mach-omap2/board-2430sdp.c +25 -17
@@ -46,9 +46,16 @@#include "hsmmc.h" #include "common-board-devices.h" -#define SDP2430_CS0_BASE 0x04000000 +#define SDP2430_FLASH_CS 0#define SECONDARY_LCD_GPIO 147 +static struct gpmc_device_pdata *gpmc_device_data[2 ]; +static struct gpmc_device_pdata **gpmc_cur = gpmc_device_data; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +static struct mtd_partition sdp2430_partitions[] = {/* bootloader (U-Boot, etc) in first sector */ {
@@ -86,24 +93,18 @@ static struct physmap_flash_data sdp2430_flash_data = { .nr_parts = ARRAY_SIZE(sdp2430_partitions), }; -static struct resource sdp2430_flash_resource = { - .start =SDP2430_CS0_BASE , - .end =SDP2430_CS0_BASE +SZ_64M -1 , - .flags =IORESOURCE_MEM , +static struct gpmc_cs_data sdp2430_gpmc_cs_flash_data = { + .cs =SDP2430_FLASH_CS , + .mem_size =SZ_64M , }; -static struct platform_device sdp2430_flash_device = { +static struct gpmc_device_pdata sdp2430_gpmc_flash_device = { .name ="physmap-flash" , .id =0 , - .dev = { - .platform_data = &sdp2430_flash_data, - }, - .num_resources =1 , - .resource = &sdp2430_flash_resource, -}; - -static struct platform_device *sdp2430_devices[]__initdata = { - &sdp2430_flash_device, + .pdata = &sdp2430_flash_data, + .pdata_size =sizeof (sdp2430_flash_data), + .cs_data = &sdp2430_gpmc_cs_flash_data, + .num_cs =1 , };/* LCD */
@@ -181,7 +182,11 @@ static struct omap_smc91x_platform_data board_smc91x_data = {static void __init board_smc91x_init (void ) {omap_mux_init_gpio (149 ,OMAP_PIN_INPUT ); -gpmc_smc91x_init (&board_smc91x_data); + *gpmc_cur =gpmc_smc91x_init (&board_smc91x_data); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else +pr_err ("error: unable to initilaize gpmc smsc911x\n" ); }#else
@@ -276,7 +281,9 @@ static void __init omap_2430sdp_init(void)omap2430_i2c_init (); -platform_add_devices (sdp2430_devices,ARRAY_SIZE (sdp2430_devices)); + *gpmc_cur++ = &sdp2430_gpmc_flash_device; + gpmc_data.num_device++; +omap_serial_init ();omap_sdrc_init (NULL ,NULL );omap_hsmmc_init (mmc);
@@ -286,6 +293,7 @@ static void __init omap_2430sdp_init(void)usb_musb_init (NULL );board_smc91x_init (); +omap_init_gpmc (&gpmc_data);/* Turn off secondary LCD backlight */ gpio_request_one(SECONDARY_LCD_GPIO, GPIOF_OUT_INIT_LOW,
Signature · 1 line
1.7.10
PATCH v4 26/39 ARM: OMAP2+: board cm-t3517: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-cm-t3517.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/board-cm-t3517.c +8 -2
@@ -234,6 +234,11 @@ static struct mtd_partition cm_t3517_nand_partitions[] = { }, }; +static struct gpmc_device_pdata *gpmc_device_data[1 ]; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +};static struct omap_nand_platform_data cm_t3517_nand_data = { .parts = cm_t3517_nand_partitions, .nr_parts =ARRAY_SIZE (cm_t3517_nand_partitions),
@@ -242,8 +247,8 @@ static struct omap_nand_platform_data cm_t3517_nand_data = {static void __init cm_t3517_init_nand (void ) { -if (gpmc_nand_init (&cm_t3517_nand_data) <0 ) -pr_err ("CM-T3517: NAND initialization failed\n" ); + *gpmc_device_data =gpmc_nand_init (&cm_t3517_nand_data); + gpmc_data.num_device++; }#else static inline void cm_t3517_init_nand (void ) {}
@@ -289,6 +294,7 @@ static void __init cm_t3517_init(void) omap_board_config_size =ARRAY_SIZE (cm_t3517_config);cm_t3517_init_leds ();cm_t3517_init_nand (); +omap_init_gpmc (&gpmc_data);cm_t3517_init_rtc ();cm_t3517_init_usbh ();cm_t3517_init_hecc ();
Signature · 1 line
1.7.10
PATCH v4 27/39 ARM: OMAP2+: board cm-t35: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-cm-t35.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/board-cm-t35.c +19 -2
@@ -66,6 +66,13 @@#include <linux/smsc911x.h> #include <plat/gpmc-smsc911x.h> +static struct gpmc_device_pdata *gpmc_device_data[2 ]; +static struct gpmc_device_pdata **gpmc_cur = gpmc_device_data; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +static struct omap_smsc911x_platform_data cm_t35_smsc911x_cfg = { .id =0 , .cs =CM_T35_SMSC911X_CS ,
@@ -99,8 +106,17 @@ static void __init cm_t35_init_ethernet(void)regulator_register_fixed (1 , sb_t35_smsc911x_supplies,ARRAY_SIZE (sb_t35_smsc911x_supplies)); -gpmc_smsc911x_init (&cm_t35_smsc911x_cfg); - gpmc_smsc911x_init(&sb_t35_smsc911x_cfg); + *gpmc_cur =gpmc_smsc911x_init (&cm_t35_smsc911x_cfg); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else +pr_err ("error: initilaizing gpmc smsc911x instance 1\n" ); + + *gpmc_cur =gpmc_smsc911x_init (&sb_t35_smsc911x_cfg); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else + pr_err("error: initilaizing gpmc smsc911x instance 2\n"); }#else static inline void __init cm_t35_init_ethernet (void ) {return ; }
@@ -658,6 +674,7 @@ static void __init cm_t3x_common_init(void)cm_t35_init_i2c ();omap_ads7846_init (1 ,CM_T35_GPIO_PENDOWN ,0 ,NULL );cm_t35_init_ethernet (); +omap_init_gpmc (&gpmc_data);cm_t35_init_led ();cm_t35_init_display ();
Signature · 1 line
1.7.10
PATCH v4 28/39 ARM: OMAP2+: board ldp: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-ldp.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-)
arch/arm/mach-omap2/board-ldp.c +23 -3
@@ -43,6 +43,7 @@#include <asm/delay.h> #include <plat/usb.h> #include <plat/gpmc-smsc911x.h> +#include <plat/nand.h> #include <video/omapdss.h> #include <video/omap-panel-generic-dpi.h>
@@ -58,6 +59,13 @@#define DEBUG_BASE 0x08000000#define LDP_ETHR_START DEBUG_BASE +static struct gpmc_device_pdata *gpmc_device_data[2 ]; +static struct gpmc_device_pdata **gpmc_cur = gpmc_device_data; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +static uint32_t board_keymap[] = {KEY (0 ,0 ,KEY_1 ),KEY (1 ,0 ,KEY_2 ),
@@ -180,7 +188,9 @@ static struct omap_smsc911x_platform_data smsc911x_cfg = {static inline void __init ldp_init_smsc911x (void ) { -gpmc_smsc911x_init (&smsc911x_cfg); + *gpmc_cur =gpmc_smsc911x_init (&smsc911x_cfg); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; }/* LCD */
@@ -418,6 +428,8 @@ static struct regulator_consumer_supply dummy_supplies[] = {static void __init omap_ldp_init (void ) { +struct omap_nand_platform_data *nand_data; +regulator_register_fixed (0 , dummy_supplies,ARRAY_SIZE (dummy_supplies));omap3_mux_init (board_mux,OMAP_PACKAGE_CBB );ldp_init_smsc911x ();
@@ -427,8 +439,16 @@ static void __init omap_ldp_init(void)omap_serial_init ();omap_sdrc_init (NULL ,NULL );usb_musb_init (NULL ); -board_nand_init (ldp_nand_partitions,ARRAY_SIZE (ldp_nand_partitions), -ZOOM_NAND_CS ,0 , nand_default_timings); + + nand_data =board_nand_init (ldp_nand_partitions, +ARRAY_SIZE (ldp_nand_partitions),ZOOM_NAND_CS , +0 , nand_default_timings); +if (nand_data !=NULL ) { + *gpmc_cur++ =gpmc_nand_init (nand_data); + gpmc_data.num_device++; + } + +omap_init_gpmc (&gpmc_data);omap_hsmmc_init (mmc);ldp_display_init ();
Signature · 1 line
1.7.10
PATCH v4 29/39 ARM: OMAP2+: board n8x0: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-n8x0.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
arch/arm/mach-omap2/board-n8x0.c +15 -3
@@ -36,6 +36,7 @@#include <plat/onenand.h> #include <plat/mmc.h> #include <plat/serial.h> +#include <plat/gpmc.h> #include "mux.h"
@@ -45,6 +46,13 @@#define TUSB6010_GPIO_ENABLE 0#define TUSB6010_DMACHAN 0x3f +static struct gpmc_device_pdata *gpmc_device_data[2 ]; +static struct gpmc_device_pdata **gpmc_cur = gpmc_device_data; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +#if defined(CONFIG_USB_MUSB_TUSB6010 ) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE )/* * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
@@ -114,10 +122,12 @@ static void __init n8x0_usb_init(void) }tusb_set_power (0 ); - ret =tusb6010_setup_interface (&tusb_data,TUSB6010_REFCLK_19 ,2 , + *gpmc_cur =tusb6010_setup_interface (&tusb_data,TUSB6010_REFCLK_19 ,2 ,TUSB6010_ASYNC_CS ,TUSB6010_SYNC_CS ,TUSB6010_GPIO_INT ,TUSB6010_DMACHAN ); -if (ret !=0 ) +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else goto err;printk (announce);
@@ -785,7 +795,9 @@ static void __init n8x0_init_machine(void) ARRAY_SIZE(n810_i2c_board_info_2));board_serial_init ();omap_sdrc_init (NULL ,NULL ); -gpmc_onenand_init (board_onenand_data); + *gpmc_cur++ =gpmc_onenand_init (board_onenand_data); + gpmc_data.num_device++; +omap_init_gpmc (&gpmc_data);n8x0_mmc_init ();n8x0_usb_init (); }
Signature · 1 line
1.7.10
PATCH v4 30/39 ARM: OMAP2+: board omap3logic: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-omap3logic.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/board-omap3logic.c +12 -1
@@ -55,6 +55,12 @@#define OMAP3_TORPEDO_MMC_GPIO_CD 127#define OMAP3_TORPEDO_SMSC911X_GPIO_IRQ 129 +static struct gpmc_device_pdata *gpmc_device_data[1 ]; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +static struct regulator_consumer_supply omap3logic_vmmc1_supply[] = {REGULATOR_SUPPLY ("vmmc" ,"omap_hsmmc.0" ), };
@@ -180,7 +186,11 @@ static inline void __init board_smsc911x_init(void)return ; } -gpmc_smsc911x_init (&board_smsc911x_data); + *gpmc_device_data =gpmc_smsc911x_init (&board_smsc911x_data); +if (*gpmc_device_data) + gpmc_data.num_device++; +else +pr_err ("error: unable to initilaize gpmc smsc911x\n" ); }#ifdef CONFIG_OMAP_MUX
@@ -204,6 +214,7 @@ static void __init omap3logic_init(void)omap_sdrc_init (NULL ,NULL );board_mmc_init ();board_smsc911x_init (); +omap_init_gpmc (&gpmc_data);/* Ensure SDRC pins are mux'd for self-refresh */ omap_mux_init_signal ("sdrc_cke0" ,OMAP_PIN_OUTPUT );
Signature · 1 line
1.7.10
PATCH v4 31/39 ARM: OMAP2+: board omap3pandora: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-omap3pandora.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/board-omap3pandora.c +9 -2
@@ -57,6 +57,12 @@#define PANDORA_WIFI_NRESET_GPIO 23#define OMAP3_PANDORA_TS_GPIO 94 +static struct gpmc_device_pdata *gpmc_device_data[1 ]; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +static struct mtd_partition omap3pandora_nand_partitions[] = { { .name ="xloader" ,
@@ -607,8 +613,9 @@ static void __init omap3pandora_init(void)omap_ads7846_init (1 ,OMAP3_PANDORA_TS_GPIO ,0 ,NULL );usbhs_init (&usbhs_bdata);usb_musb_init (NULL ); -gpmc_nand_init (&pandora_nand_data); - + *gpmc_device_data =gpmc_nand_init (&pandora_nand_data); + gpmc_data.num_device++; +omap_init_gpmc (&gpmc_data);/* Ensure SDRC pins are mux'd for self-refresh */ omap_mux_init_signal ("sdrc_cke0" ,OMAP_PIN_OUTPUT );omap_mux_init_signal ("sdrc_cke1" ,OMAP_PIN_OUTPUT );
Signature · 1 line
1.7.10
PATCH v4 32/39 ARM: OMAP2+: board omap3stalker: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-omap3stalker.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/board-omap3stalker.c +12 -1
@@ -56,6 +56,12 @@#include "hsmmc.h" #include "common-board-devices.h" +static struct gpmc_device_pdata *gpmc_device_data[1 ]; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +#if defined(CONFIG_SMSC911X ) || defined(CONFIG_SMSC911X_MODULE )#include <plat/gpmc-smsc911x.h>
@@ -74,7 +80,11 @@ static struct omap_smsc911x_platform_data smsc911x_cfg = {static inline void __init omap3stalker_init_eth (void ) {omap_mux_init_gpio (19 ,OMAP_PIN_INPUT_PULLUP ); -gpmc_smsc911x_init (&smsc911x_cfg); + *gpmc_device_data =gpmc_smsc911x_init (&smsc911x_cfg); +if (*gpmc_device_data) + gpmc_data.num_device++; +else +pr_err ("error: unable to initilaize gpmc smsc911x\n" ); }#else
@@ -443,6 +453,7 @@ static void __init omap3_stalker_init(void)omap_mux_init_gpio (18 ,OMAP_PIN_INPUT_PULLUP );omap3stalker_init_eth (); +omap_init_gpmc (&gpmc_data);omap3_stalker_display_init ();/* Ensure SDRC pins are mux'd for self-refresh */ omap_mux_init_signal ("sdr_cke0" ,OMAP_PIN_OUTPUT );
Signature · 1 line
1.7.10
PATCH v4 33/39 ARM: OMAP2+: board omap4pcm049: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-omap4pcm049.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/board-omap4pcm049.c +12 -1
@@ -130,6 +130,12 @@ static struct omap2_hsmmc_info mmc[] = { }, {} /* Terminator */ }; +static struct gpmc_device_pdata *gpmc_device_data[1 ]; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +#if defined(CONFIG_SMSC911X ) || defined(CONFIG_SMSC911X_MODULE )static struct regulator_consumer_supply dummy_supplies[] = { REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
@@ -147,7 +153,11 @@ static inline void __init pcm049_init_smsc911x(void) {omap_mux_init_gpio (OMAP4_PCM049_ETH_GPIO_IRQ ,OMAP_PIN_INPUT );regulator_register_fixed (0 , dummy_supplies,ARRAY_SIZE (dummy_supplies)); -gpmc_smsc911x_init (&board_smsc911x_data); + *gpmc_device_data =gpmc_smsc911x_init (&board_smsc911x_data); +if (*gpmc_device_data) + gpmc_data.num_device++; +else +pr_err ("error: unable to initilaize gpmc smsc911x\n" ); }#else static inline void __init pcm049_init_smsc911x (void ) {return ; }
@@ -562,6 +572,7 @@ static void __init pcm049_init(void) pm_power_off = pcm049_power_off;omap4_mux_init (board_mux,NULL ,OMAP_PACKAGE_CBS );pcm049_init_smsc911x (); +omap_init_gpmc (&gpmc_data);pcm049_i2c_init ();platform_add_devices (pcm049_devices,ARRAY_SIZE (pcm049_devices));board_serial_init ();
Signature · 1 line
1.7.10
PATCH v4 34/39 ARM: OMAP2+: board overo: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-overo.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-)
arch/arm/mach-omap2/board-overo.c +26 -3
@@ -72,6 +72,13 @@#define OVERO_SMSC911X2_CS 4#define OVERO_SMSC911X2_GPIO 65 +static struct gpmc_device_pdata *gpmc_device_data[3 ]; +static struct gpmc_device_pdata **gpmc_cur = gpmc_device_data; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +#if defined(CONFIG_TOUCHSCREEN_ADS7846 ) || \ defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE )
@@ -137,8 +144,16 @@ static struct omap_smsc911x_platform_data smsc911x2_cfg = {static void __init overo_init_smsc911x (void ) { -gpmc_smsc911x_init (&smsc911x_cfg); -gpmc_smsc911x_init (&smsc911x2_cfg); + *gpmc_cur =gpmc_smsc911x_init (&smsc911x_cfg); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else +pr_err ("error: %s: smsc911x instance 1 setup\n" , __func__); + *gpmc_cur =gpmc_smsc911x_init (&smsc911x2_cfg); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else +pr_err ("error: %s: smsc911x instance 1 setup\n" , __func__); }#else
@@ -509,6 +524,7 @@ static struct regulator_consumer_supply dummy_supplies[] = {static void __init overo_init (void ) {int ret; +struct omap_nand_platform_data *nand_data;regulator_register_fixed (0 , dummy_supplies,ARRAY_SIZE (dummy_supplies));omap3_mux_init (board_mux,OMAP_PACKAGE_CBB );
@@ -518,12 +534,19 @@ static void __init overo_init(void)omap_serial_init ();omap_sdrc_init (mt46h32m32lf6_sdrc_params, mt46h32m32lf6_sdrc_params); -board_nand_init (overo_nand_partitions, + + nand_data =board_nand_init (overo_nand_partitions,ARRAY_SIZE (overo_nand_partitions),GPMC_CS_NUM ,0 ,NULL ); +if (nand_data !=NULL ) { + *gpmc_cur++ =gpmc_nand_init (nand_data); + gpmc_data.num_device++; + } +usb_musb_init (NULL );usbhs_init (&usbhs_bdata);overo_spi_init ();overo_init_smsc911x (); +omap_init_gpmc (&gpmc_data);overo_display_init ();overo_init_led ();overo_init_keys ();
Signature · 1 line
1.7.10
PATCH v4 35/39 ARM: OMAP2+: board rm680: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-rm680.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/board-rm680.c +9 -1
@@ -33,6 +33,12 @@#include "sdram-nokia.h" #include "common-board-devices.h" +static struct gpmc_device_pdata *gpmc_device_data[1 ]; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +static struct regulator_consumer_supply rm680_vemmc_consumers[] = {REGULATOR_SUPPLY ("vmmc" ,"omap_hsmmc.1" ), };
@@ -119,7 +125,8 @@ static void __init rm680_peripherals_init(void)platform_add_devices (rm680_peripherals_devices,ARRAY_SIZE (rm680_peripherals_devices));rm680_i2c_init (); -gpmc_onenand_init (board_onenand_data); + *gpmc_device_data =gpmc_onenand_init (board_onenand_data); + gpmc_data.num_device++;omap_hsmmc_init (mmc); }
@@ -141,6 +148,7 @@ static void __init rm680_init(void)usb_musb_init (NULL );rm680_peripherals_init (); +omap_init_gpmc (&gpmc_data); }MACHINE_START (NOKIA_RM680 ,"Nokia RM-680 board" )
Signature · 1 line
1.7.10
PATCH v4 36/39 ARM: OMAP2+: board rx51: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-rx51-peripherals.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/board-rx51-peripherals.c +15 -2
@@ -73,6 +73,13 @@ enum {static struct wl12xx_platform_data wl1251_pdata;static struct tsc2005_platform_data tsc2005_pdata; +static struct gpmc_device_pdata *gpmc_device_data[2 ]; +static struct gpmc_device_pdata **gpmc_cur = gpmc_device_data; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +#if defined(CONFIG_SENSORS_TSL2563 ) || defined(CONFIG_SENSORS_TSL2563_MODULE )static struct tsl2563_platform_data rx51_tsl2563_platform_data = { .cover_comp_gain = 16,
@@ -1039,7 +1046,11 @@ static void __init board_smc91x_init(void)omap_mux_init_gpio (86 ,OMAP_PIN_OUTPUT );omap_mux_init_gpio (164 ,OMAP_PIN_OUTPUT ); - gpmc_smc91x_init(&board_smc91x_data); + *gpmc_cur =gpmc_smc91x_init (&board_smc91x_data); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else + pr_err("error: gpmc smsc911x setup\n"); }#else
@@ -1136,8 +1147,10 @@ void __init rx51_peripherals_init(void) {rx51_i2c_init ();regulator_has_full_constraints (); -gpmc_onenand_init (board_onenand_data); + *gpmc_cur++ =gpmc_onenand_init (board_onenand_data); + gpmc_data.num_device++;board_smc91x_init (); +omap_init_gpmc (&gpmc_data);rx51_add_gpio_keys ();rx51_init_wl1251 ();rx51_init_tsc2005 ();
Signature · 1 line
1.7.10
PATCH v4 37/39 ARM: OMAP2+: board zoom-debugboard: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-zoom-debugboard.c | 47 +++++++++++++++------------ 1 file changed, 27 insertions(+), 20 deletions(-)
arch/arm/mach-omap2/board-zoom-debugboard.c +27 -20
@@ -31,6 +31,13 @@#define DEBUG_BASE 0x08000000#define ZOOM_ETHR_START DEBUG_BASE +static struct gpmc_device_pdata *gpmc_device_data[2 ]; +static struct gpmc_device_pdata **gpmc_cur = gpmc_device_data; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; +static struct omap_smsc911x_platform_data zoom_smsc911x_cfg = { .cs =ZOOM_SMSC911X_CS , .gpio_irq =ZOOM_SMSC911X_GPIO ,
@@ -40,7 +47,11 @@ static struct omap_smsc911x_platform_data zoom_smsc911x_cfg = {static inline void __init zoom_init_smsc911x (void ) { -gpmc_smsc911x_init (&zoom_smsc911x_cfg); + *gpmc_cur =gpmc_smsc911x_init (&zoom_smsc911x_cfg); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else +pr_err ("error: %s: gpmc smsc911x setup\n" , __func__); }static struct plat_serial8250_port serial_platform_data[] = {
@@ -56,18 +67,22 @@ static struct plat_serial8250_port serial_platform_data[] = { } }; -static struct platform_device zoom_debugboard_serial_device = { +static struct gpmc_cs_data zoom_debugboard_gpmc_cs_serial_data = { + .cs =ZOOM_QUADUART_CS , + .mem_size =SZ_1M , +}; + +static struct gpmc_device_pdata zoom_debugboard_gpmc_serial_data = { .name ="serial8250" , .id =PLAT8250_DEV_PLATFORM , - .dev = { - .platform_data = serial_platform_data, - }, + .pdata = serial_platform_data, + .pdata_size =sizeof (serial_platform_data), + .cs_data = &zoom_debugboard_gpmc_cs_serial_data, + .num_cs =1 , };static inline void __init zoom_init_quaduart (void ) { -int quart_cs; -unsigned long cs_mem_base;int quart_gpio =0 ; if (gpio_request_one(ZOOM_QUADUART_RST_GPIO,
@@ -78,14 +93,6 @@ static inline void __init zoom_init_quaduart(void)return ; } - quart_cs =ZOOM_QUADUART_CS ; - -if (gpmc_cs_request (quart_cs,SZ_1M , &cs_mem_base) <0 ) { -printk (KERN_ERR "Failed to request GPMC mem" -"for Quad UART(TL16CP754C)\n" ); -return ; - } - quart_gpio =ZOOM_QUADUART_GPIO ;if (gpio_request_one (quart_gpio,GPIOF_IN ,"TL16CP754C GPIO" ) <0 )
@@ -93,6 +100,9 @@ static inline void __init zoom_init_quaduart(void) quart_gpio); serial_platform_data[0 ].irq =gpio_to_irq (102 ); + + *gpmc_cur++ = &zoom_debugboard_gpmc_serial_data; + gpmc_data.num_device++; }static inline int omap_zoom_debugboard_detect (void )
@@ -116,10 +126,6 @@ static inline int omap_zoom_debugboard_detect(void)return ret; } -static struct platform_device *zoom_devices[]__initdata = { - &zoom_debugboard_serial_device, -}; -static struct regulator_consumer_supply dummy_supplies[] = {REGULATOR_SUPPLY ("vddvario" ,"smsc911x.0" ),REGULATOR_SUPPLY ("vdd33a" ,"smsc911x.0" ),
@@ -133,5 +139,6 @@ int __init zoom_debugboard_init(void)regulator_register_fixed (0 , dummy_supplies,ARRAY_SIZE (dummy_supplies));zoom_init_smsc911x ();zoom_init_quaduart (); -return platform_add_devices (zoom_devices,ARRAY_SIZE (zoom_devices)); +omap_init_gpmc (&gpmc_data); +return 0 ; }
Signature · 1 line
1.7.10
PATCH v4 38/39 OMAP3: igep0020: Add support for Micron NAND Flash storage memory
In reply to Afzal MohammedFrom: Javier Martinez Canillas <[email protected]>
IGEP-based boards can have two different flash memories, a OneNAND or a NAND device. The boot configuration pins (sys_boot) are used to specify which memory is available.
Also, this patch removes unnecesary code for registering the OneNAND.
afzal at ti.com: Update to use modified board_nand_init
fixup: igep
--- arch/arm/mach-omap2/board-igep0020.c | 75 ++++++++++++++-------------------- 1 file changed, 31 insertions(+), 44 deletions(-)
arch/arm/mach-omap2/board-igep0020.c +31 -44
@@ -24,6 +24,8 @@#include <linux/i2c/twl.h> #include <linux/mmc/host.h> +#include <linux/mtd/nand.h> +#include <asm/mach-types.h> #include <asm/mach/arch.h>
@@ -39,6 +41,8 @@#include "hsmmc.h" #include "sdram-numonyx-m65kxxxxam.h" #include "common-board-devices.h" +#include "board-flash.h" +#include "control.h" #define IGEP2_SMSC911X_CS 5#define IGEP2_SMSC911X_GPIO 176
@@ -60,6 +64,10 @@#define IGEP3_GPIO_LED1_RED 16#define IGEP3_GPIO_USBH_NRESET 183 +#define IGEP_SYSBOOT_MASK 0x1f +#define IGEP_SYSBOOT_NAND 0x0f +#define IGEP_SYSBOOT_ONENAND 0x10 +/* * IGEP2 Hardware Revision Table *
@@ -110,8 +118,10 @@ static void __init igep2_get_revision(void)gpio_free (IGEP2_GPIO_LED1_RED ); } -#if defined(CONFIG_MTD_ONENAND_OMAP2 ) || \ - defined(CONFIG_MTD_ONENAND_OMAP2_MODULE ) +#if defined(CONFIG_MTD_ONENAND_OMAP2 ) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE ) || \ + defined(CONFIG_MTD_NAND_OMAP2 ) || \ + defined(CONFIG_MTD_NAND_OMAP2_MODULE )#define ONENAND_MAP 0x20000000
@@ -123,7 +133,7 @@ static void __init igep2_get_revision(void)* So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048) */ -static struct mtd_partition igep_onenand_partitions[] = { +static struct mtd_partition igep_flash_partitions[] = { { .name ="X-Loader" , .offset =0 ,
@@ -151,50 +161,27 @@ static struct mtd_partition igep_onenand_partitions[] = { }, }; -static struct omap_onenand_platform_data igep_onenand_data = { - .parts = igep_onenand_partitions, - .nr_parts =ARRAY_SIZE (igep_onenand_partitions), - .dma_channel =-1 ,/* disable DMA in OMAP OneNAND driver */ -}; - -static struct platform_device igep_onenand_device = { - .name ="omap2-onenand" , - .id =-1 , - .dev = { - .platform_data = &igep_onenand_data, - }, -}; +static inline u32 igep_get_sysboot_value (void ) +{ +return omap_ctrl_readl (OMAP343X_CONTROL_STATUS ) &IGEP_SYSBOOT_MASK ; +}static void __init igep_flash_init (void ) { -u8 cs =0 ; -u8 onenandcs =GPMC_CS_NUM +1 ; - -for (cs =0 ; cs <GPMC_CS_NUM ; cs++) { -u32 ret; - ret =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG1 ); - -/* Check if NAND/oneNAND is configured */ -if ((ret &0xC00 ) ==0x800 ) -/* NAND found */ -pr_err ("IGEP: Unsupported NAND found\n" ); -else { - ret =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG7 ); -if ((ret &0x3F ) == (ONENAND_MAP >>24 )) -/* ONENAND found */ - onenandcs = cs; - } - } - -if (onenandcs >GPMC_CS_NUM ) { -pr_err ("IGEP: Unable to find configuration in GPMC\n" ); -return ; - } - - igep_onenand_data.cs = onenandcs; - -if (platform_device_register (&igep_onenand_device) <0 ) -pr_err ("IGEP: Unable to register OneNAND device\n" ); +u32 mux; + mux =igep_get_sysboot_value (); + +if (mux ==IGEP_SYSBOOT_NAND ) { +pr_info ("IGEP: initializing NAND memory device\n" ); +board_nand_init (igep_flash_partitions, +ARRAY_SIZE (igep_flash_partitions), +0 ,NAND_BUSWIDTH_16 ,NULL ); + }else if (mux ==IGEP_SYSBOOT_ONENAND ) { +pr_info ("IGEP: initializing OneNAND memory device\n" ); +board_onenand_init (igep_flash_partitions, +ARRAY_SIZE (igep_flash_partitions),0 ); + }else +pr_err ("IGEP: Flash: unsupported sysboot sequence found\n" ); }#else
Signature · 1 line
1.7.10
PATCH v4 39/39 ARM: OMAP2+: board igep0020: gpmc driver adaptation
In reply to Afzal Mohammedgpmc code has been converted to driver. Modify the board code to provide gpmc driver with required information.
--- arch/arm/mach-omap2/board-igep0020.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-)
arch/arm/mach-omap2/board-igep0020.c +28 -4
@@ -36,6 +36,7 @@#include <video/omapdss.h> #include <video/omap-panel-dvi.h> #include <plat/onenand.h> +#include <plat/nand.h> #include "mux.h" #include "hsmmc.h"
@@ -118,6 +119,13 @@ static void __init igep2_get_revision(void)gpio_free (IGEP2_GPIO_LED1_RED ); } +static struct gpmc_device_pdata *gpmc_device_data[2 ]; +static struct gpmc_device_pdata **gpmc_cur = gpmc_device_data; + +static struct gpmc_pdata gpmc_data = { + .device_pdata = gpmc_device_data, +}; + #if defined(CONFIG_MTD_ONENAND_OMAP2) || \ defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) || \ defined(CONFIG_MTD_NAND_OMAP2) || \
@@ -172,14 +180,26 @@ static void __init igep_flash_init(void) mux =igep_get_sysboot_value ();if (mux ==IGEP_SYSBOOT_NAND ) { +struct omap_nand_platform_data *nand_data; +pr_info ("IGEP: initializing NAND memory device\n" ); -board_nand_init (igep_flash_partitions, + nand_data =board_nand_init (igep_flash_partitions,ARRAY_SIZE (igep_flash_partitions), -0 ,NAND_BUSWIDTH_16 ,NULL ); +0 ,NAND_BUSWIDTH_16 , nand_default_timings); +if (nand_data !=NULL ) { + *gpmc_cur++ =gpmc_nand_init (nand_data); + gpmc_data.num_device++; + } }else if (mux ==IGEP_SYSBOOT_ONENAND ) { +struct omap_onenand_platform_data *onenand_data; +pr_info ("IGEP: initializing OneNAND memory device\n" ); -board_onenand_init (igep_flash_partitions, + onenand_data =board_onenand_init (igep_flash_partitions,ARRAY_SIZE (igep_flash_partitions),0 ); +if (onenand_data !=NULL ) { + *gpmc_cur++ =gpmc_onenand_init (onenand_data); + gpmc_data.num_device++; + } }else pr_err ("IGEP: Flash: unsupported sysboot sequence found\n" ); }
@@ -202,7 +222,11 @@ static struct omap_smsc911x_platform_data smsc911x_cfg = {static inline void __init igep2_init_smsc911x (void ) { -gpmc_smsc911x_init (&smsc911x_cfg); + *gpmc_cur =gpmc_smsc911x_init (&smsc911x_cfg); +if (*gpmc_cur) + gpmc_data.num_device++, gpmc_cur++; +else +pr_err ("error: gpmc smsc911x setup\n" ); }#else
Signature · 1 line
1.7.10
v4 cover OMAP GPMC driver conversion
In reply to Afzal MohammedHi Tony,
Quoted 15 lines · Afzal
GPMC driver conversion patch series. Some peripherals has GPMC helper functions, these has been modified to cater to the needs of GPMC driver. All the boards using GPMC has been adapted to use the new GPMC driver.
GPMC HWMOD entry for OMAP2/3 has been added. On OMAP3, kernel does spit "
omap_hwmod: gpmc: cannot be enabled for reset (3)", but peripherals connected via GPMC are working. Really shaky about OMAP2 GPMC HWMOD entry. Would be helpful if someone can help me in resolving warning on OMAP3 & verify whether OMAP2 entry is proper. The series adapts to HWMOD.Drivers, NAND & OneNAND of OMAP has been modified to make use of GPMC changes & cleaned up the now unnecessary exported symbol usages.
Quoted 8 lines
This series has been made on top of,
5e136da Linux-omap rebuilt: Updated to -rc5,
A patch by Javier Martinez Canillas <[email protected]>,
OMAP3: igep0020: Add support for Micron NAND Flash storage memory, has also been incorporated into the series as this was necessary for igep0020 board.This has been tested on omap3 evm (SMSC911x) & beagle board (NAND)
Please let me know your comments on this series.
Regards
Afzal