mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-16 07:24:39 +08:00
GPMC updates from Jon Hunter <jon-hunter@ti.com>:
Adds GPMC (General Purpose Memory Controller) DT support for NOR flash and Ethernet and includes various GPMC cleans-up and fixes. This series is dependent on commit7185684
(ARM: OMAP: use consistent error checking) from RMK's clean-up branch and commit31d9adc
(ARM: OMAP2+: Fix broken gpmc support). -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJRXcsJAAoJEBvUPslcq6VzwKYQANHrnD6R0sv5kTcxT6wqIOv/ GXaN5aOI7xvplSwORTUuw4wGt9M0kTf/nDKcu+THSYzVsrIXD/zIXoOzH0q8FBPG 2qmVYJah5LiKCT0M53/DityXD4teCOfK/Ld3w6JqepbAH63ZrNyFI1Zo+JcEvJEW qVM16UzEU9k4dk6ENq3PV1HYGnk/cvreG0TkRFnIYHR/+JsUNiderx4ucYYO7oNT 3Ft4LYMx2p6pOO1K1FqqikN8m+C1Z2Q+1uouo/b9Yvi3phFW+f2e32NEKdtXMQjV Eqbz9q0O0mWx9tBq2C+y4nlI+QwjoEcZ5WsU9PNAwyUqu+dZiac28uJo6eIdmlOr sw1zwni5XdxnnnjAjG9o9WZAJPpRv6sMLpEaVu2rm4tRi27l1oh6OTfmHsyEv+CR mp6cXi9HaDw0ErBxE6kkDiBUkyK0ayyx+v58NJUT363Mc48felKi1ZMoyFLPtbBb BnQ91uEp2Kjkx1ebVvKO+8AsrNF6e6rTSVUHfPCef6zJH/v/+6XXxLerQGD5jNDB HWFsIwQj+76hOpp4rpUU46HFKgHWyp4qvFBx0y/U2txv8ruD26XemowUhch/ONK6 3niZzOcXhesjM41bZRmUhzSuW685ZHKN0lBO5U4i+IEL0YHEnpkYbp34hHLzp1ll 4PaIxx6CZz1QV+IIO91z =sfId -----END PGP SIGNATURE----- Merge tag 'omap-for-v3.10/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/drivers From Tony Lindgren <tony@atomide.com>: GPMC updates from Jon Hunter <jon-hunter@ti.com>: Adds GPMC (General Purpose Memory Controller) DT support for NOR flash and Ethernet and includes various GPMC cleans-up and fixes. This series is dependent on commit7185684
(ARM: OMAP: use consistent error checking) from RMK's clean-up branch and commit31d9adc
(ARM: OMAP2+: Fix broken gpmc support). * tag 'omap-for-v3.10/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: (29 commits) ARM: OMAP2+: Add GPMC DT support for Ethernet child nodes ARM: OMAP2+: rename gpmc_probe_nor_child() to gpmc_probe_generic_child() ARM: OMAP2+: return -ENODEV if GPMC child device creation fails ARM: OMAP2+: Allow GPMC probe to complete even if CS mapping fails ARM: OMAP2+: Remove unnecesssary GPMC definitions and variable ARM: OMAP2+: Detect incorrectly aligned GPMC base address ARM: OMAP2+: Convert ONENAND to retrieve GPMC settings from DT ARM: OMAP2+: Convert NAND to retrieve GPMC settings from DT ARM: OMAP2+: Add device-tree support for NOR flash ARM: OMAP2+: Add additional GPMC timing parameters ARM: OMAP2+: Add function to read GPMC settings from device-tree ARM: OMAP2+: Don't configure of chip-select options in gpmc_cs_configure() ARM: OMAP2+: Convert TUSB to use gpmc_cs_program_settings() ARM: OMAP2+: Convert SMC91x to use gpmc_cs_program_settings() ARM: OMAP2+: Convert NAND to use gpmc_cs_program_settings() ARM: OMAP2+: Convert ONENAND to use gpmc_cs_program_settings() ARM: OMAP2+: Add function for configuring GPMC settings ARM: OMAP2+: Add structure for storing GPMC settings ARM: OMAP2+: Add variable to store number of GPMC waitpins ARM: OMAP2+: Simplify code configuring ONENAND devices ... Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
86feb64f5b
@ -35,36 +35,83 @@ Required properties:
|
||||
|
||||
Timing properties for child nodes. All are optional and default to 0.
|
||||
|
||||
- gpmc,sync-clk: Minimum clock period for synchronous mode, in picoseconds
|
||||
- gpmc,sync-clk-ps: Minimum clock period for synchronous mode, in picoseconds
|
||||
|
||||
Chip-select signal timings corresponding to GPMC_CONFIG2:
|
||||
- gpmc,cs-on: Assertion time
|
||||
- gpmc,cs-rd-off: Read deassertion time
|
||||
- gpmc,cs-wr-off: Write deassertion time
|
||||
Chip-select signal timings (in nanoseconds) corresponding to GPMC_CONFIG2:
|
||||
- gpmc,cs-on-ns: Assertion time
|
||||
- gpmc,cs-rd-off-ns: Read deassertion time
|
||||
- gpmc,cs-wr-off-ns: Write deassertion time
|
||||
|
||||
ADV signal timings corresponding to GPMC_CONFIG3:
|
||||
- gpmc,adv-on: Assertion time
|
||||
- gpmc,adv-rd-off: Read deassertion time
|
||||
- gpmc,adv-wr-off: Write deassertion time
|
||||
ADV signal timings (in nanoseconds) corresponding to GPMC_CONFIG3:
|
||||
- gpmc,adv-on-ns: Assertion time
|
||||
- gpmc,adv-rd-off-ns: Read deassertion time
|
||||
- gpmc,adv-wr-off-ns: Write deassertion time
|
||||
|
||||
WE signals timings corresponding to GPMC_CONFIG4:
|
||||
- gpmc,we-on: Assertion time
|
||||
- gpmc,we-off: Deassertion time
|
||||
WE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4:
|
||||
- gpmc,we-on-ns Assertion time
|
||||
- gpmc,we-off-ns: Deassertion time
|
||||
|
||||
OE signals timings corresponding to GPMC_CONFIG4:
|
||||
- gpmc,oe-on: Assertion time
|
||||
- gpmc,oe-off: Deassertion time
|
||||
OE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4:
|
||||
- gpmc,oe-on-ns: Assertion time
|
||||
- gpmc,oe-off-ns: Deassertion time
|
||||
|
||||
Access time and cycle time timings corresponding to GPMC_CONFIG5:
|
||||
- gpmc,page-burst-access: Multiple access word delay
|
||||
- gpmc,access: Start-cycle to first data valid delay
|
||||
- gpmc,rd-cycle: Total read cycle time
|
||||
- gpmc,wr-cycle: Total write cycle time
|
||||
Access time and cycle time timings (in nanoseconds) corresponding to
|
||||
GPMC_CONFIG5:
|
||||
- gpmc,page-burst-access-ns: Multiple access word delay
|
||||
- gpmc,access-ns: Start-cycle to first data valid delay
|
||||
- gpmc,rd-cycle-ns: Total read cycle time
|
||||
- gpmc,wr-cycle-ns: Total write cycle time
|
||||
- gpmc,bus-turnaround-ns: Turn-around time between successive accesses
|
||||
- gpmc,cycle2cycle-delay-ns: Delay between chip-select pulses
|
||||
- gpmc,clk-activation-ns: GPMC clock activation time
|
||||
- gpmc,wait-monitoring-ns: Start of wait monitoring with regard to valid
|
||||
data
|
||||
|
||||
Boolean timing parameters. If property is present parameter enabled and
|
||||
disabled if omitted:
|
||||
- gpmc,adv-extra-delay: ADV signal is delayed by half GPMC clock
|
||||
- gpmc,cs-extra-delay: CS signal is delayed by half GPMC clock
|
||||
- gpmc,cycle2cycle-diffcsen: Add "cycle2cycle-delay" between successive
|
||||
accesses to a different CS
|
||||
- gpmc,cycle2cycle-samecsen: Add "cycle2cycle-delay" between successive
|
||||
accesses to the same CS
|
||||
- gpmc,oe-extra-delay: OE signal is delayed by half GPMC clock
|
||||
- gpmc,we-extra-delay: WE signal is delayed by half GPMC clock
|
||||
- gpmc,time-para-granularity: Multiply all access times by 2
|
||||
|
||||
The following are only applicable to OMAP3+ and AM335x:
|
||||
- gpmc,wr-access
|
||||
- gpmc,wr-data-mux-bus
|
||||
- gpmc,wr-access-ns: In synchronous write mode, for single or
|
||||
burst accesses, defines the number of
|
||||
GPMC_FCLK cycles from start access time
|
||||
to the GPMC_CLK rising edge used by the
|
||||
memory device for the first data capture.
|
||||
- gpmc,wr-data-mux-bus-ns: In address-data multiplex mode, specifies
|
||||
the time when the first data is driven on
|
||||
the address-data bus.
|
||||
|
||||
GPMC chip-select settings properties for child nodes. All are optional.
|
||||
|
||||
- gpmc,burst-length Page/burst length. Must be 4, 8 or 16.
|
||||
- gpmc,burst-wrap Enables wrap bursting
|
||||
- gpmc,burst-read Enables read page/burst mode
|
||||
- gpmc,burst-write Enables write page/burst mode
|
||||
- gpmc,device-nand Device is NAND
|
||||
- gpmc,device-width Total width of device(s) connected to a GPMC
|
||||
chip-select in bytes. The GPMC supports 8-bit
|
||||
and 16-bit devices and so this property must be
|
||||
1 or 2.
|
||||
- gpmc,mux-add-data Address and data multiplexing configuration.
|
||||
Valid values are 1 for address-address-data
|
||||
multiplexing mode and 2 for address-data
|
||||
multiplexing mode.
|
||||
- gpmc,sync-read Enables synchronous read. Defaults to asynchronous
|
||||
is this is not set.
|
||||
- gpmc,sync-write Enables synchronous writes. Defaults to asynchronous
|
||||
is this is not set.
|
||||
- gpmc,wait-pin Wait-pin used by client. Must be less than
|
||||
"gpmc,num-waitpins".
|
||||
- gpmc,wait-on-read Enables wait monitoring on reads.
|
||||
- gpmc,wait-on-write Enables wait monitoring on writes.
|
||||
|
||||
Example for an AM33xx board:
|
||||
|
||||
|
98
Documentation/devicetree/bindings/mtd/gpmc-nor.txt
Normal file
98
Documentation/devicetree/bindings/mtd/gpmc-nor.txt
Normal file
@ -0,0 +1,98 @@
|
||||
Device tree bindings for NOR flash connect to TI GPMC
|
||||
|
||||
NOR flash connected to the TI GPMC (found on OMAP boards) are represented as
|
||||
child nodes of the GPMC controller with a name of "nor".
|
||||
|
||||
All timing relevant properties as well as generic GPMC child properties are
|
||||
explained in a separate documents. Please refer to
|
||||
Documentation/devicetree/bindings/bus/ti-gpmc.txt
|
||||
|
||||
Required properties:
|
||||
- bank-width: Width of NOR flash in bytes. GPMC supports 8-bit and
|
||||
16-bit devices and so must be either 1 or 2 bytes.
|
||||
- compatible: Documentation/devicetree/bindings/mtd/mtd-physmap.txt
|
||||
- gpmc,cs-on-ns: Chip-select assertion time
|
||||
- gpmc,cs-rd-off-ns: Chip-select de-assertion time for reads
|
||||
- gpmc,cs-wr-off-ns: Chip-select de-assertion time for writes
|
||||
- gpmc,oe-on-ns: Output-enable assertion time
|
||||
- gpmc,oe-off-ns: Output-enable de-assertion time
|
||||
- gpmc,we-on-ns Write-enable assertion time
|
||||
- gpmc,we-off-ns: Write-enable de-assertion time
|
||||
- gpmc,access-ns: Start cycle to first data capture (read access)
|
||||
- gpmc,rd-cycle-ns: Total read cycle time
|
||||
- gpmc,wr-cycle-ns: Total write cycle time
|
||||
- linux,mtd-name: Documentation/devicetree/bindings/mtd/mtd-physmap.txt
|
||||
- reg: Chip-select, base address (relative to chip-select)
|
||||
and size of NOR flash. Note that base address will be
|
||||
typically 0 as this is the start of the chip-select.
|
||||
|
||||
Optional properties:
|
||||
- gpmc,XXX Additional GPMC timings and settings parameters. See
|
||||
Documentation/devicetree/bindings/bus/ti-gpmc.txt
|
||||
|
||||
Optional properties for partiton table parsing:
|
||||
- #address-cells: should be set to 1
|
||||
- #size-cells: should be set to 1
|
||||
|
||||
Example:
|
||||
|
||||
gpmc: gpmc@6e000000 {
|
||||
compatible = "ti,omap3430-gpmc", "simple-bus";
|
||||
ti,hwmods = "gpmc";
|
||||
reg = <0x6e000000 0x1000>;
|
||||
interrupts = <20>;
|
||||
gpmc,num-cs = <8>;
|
||||
gpmc,num-waitpins = <4>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
|
||||
ranges = <0 0 0x10000000 0x08000000>;
|
||||
|
||||
nor@0,0 {
|
||||
compatible = "cfi-flash";
|
||||
linux,mtd-name= "intel,pf48f6000m0y1be";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0 0 0x08000000>;
|
||||
bank-width = <2>;
|
||||
|
||||
gpmc,mux-add-data;
|
||||
gpmc,cs-on-ns = <0>;
|
||||
gpmc,cs-rd-off-ns = <186>;
|
||||
gpmc,cs-wr-off-ns = <186>;
|
||||
gpmc,adv-on-ns = <12>;
|
||||
gpmc,adv-rd-off-ns = <48>;
|
||||
gpmc,adv-wr-off-ns = <48>;
|
||||
gpmc,oe-on-ns = <54>;
|
||||
gpmc,oe-off-ns = <168>;
|
||||
gpmc,we-on-ns = <54>;
|
||||
gpmc,we-off-ns = <168>;
|
||||
gpmc,rd-cycle-ns = <186>;
|
||||
gpmc,wr-cycle-ns = <186>;
|
||||
gpmc,access-ns = <114>;
|
||||
gpmc,page-burst-access-ns = <6>;
|
||||
gpmc,bus-turnaround-ns = <12>;
|
||||
gpmc,cycle2cycle-delay-ns = <18>;
|
||||
gpmc,wr-data-mux-bus-ns = <90>;
|
||||
gpmc,wr-access-ns = <186>;
|
||||
gpmc,cycle2cycle-samecsen;
|
||||
gpmc,cycle2cycle-diffcsen;
|
||||
|
||||
partition@0 {
|
||||
label = "bootloader-nor";
|
||||
reg = <0 0x40000>;
|
||||
};
|
||||
partition@0x40000 {
|
||||
label = "params-nor";
|
||||
reg = <0x40000 0x40000>;
|
||||
};
|
||||
partition@0x80000 {
|
||||
label = "kernel-nor";
|
||||
reg = <0x80000 0x200000>;
|
||||
};
|
||||
partition@0x280000 {
|
||||
label = "filesystem-nor";
|
||||
reg = <0x240000 0x7d80000>;
|
||||
};
|
||||
};
|
||||
};
|
@ -10,6 +10,8 @@ Documentation/devicetree/bindings/bus/ti-gpmc.txt
|
||||
Required properties:
|
||||
|
||||
- reg: The CS line the peripheral is connected to
|
||||
- gpmc,device-width Width of the ONENAND device connected to the GPMC
|
||||
in bytes. Must be 1 or 2.
|
||||
|
||||
Optional properties:
|
||||
|
||||
@ -34,6 +36,7 @@ Example for an OMAP3430 board:
|
||||
|
||||
onenand@0 {
|
||||
reg = <0 0 0>; /* CS0, offset 0 */
|
||||
gpmc,device-width = <2>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
97
Documentation/devicetree/bindings/net/gpmc-eth.txt
Normal file
97
Documentation/devicetree/bindings/net/gpmc-eth.txt
Normal file
@ -0,0 +1,97 @@
|
||||
Device tree bindings for Ethernet chip connected to TI GPMC
|
||||
|
||||
Besides being used to interface with external memory devices, the
|
||||
General-Purpose Memory Controller can be used to connect Pseudo-SRAM devices
|
||||
such as ethernet controllers to processors using the TI GPMC as a data bus.
|
||||
|
||||
Ethernet controllers connected to TI GPMC are represented as child nodes of
|
||||
the GPMC controller with an "ethernet" name.
|
||||
|
||||
All timing relevant properties as well as generic GPMC child properties are
|
||||
explained in a separate documents. Please refer to
|
||||
Documentation/devicetree/bindings/bus/ti-gpmc.txt
|
||||
|
||||
For the properties relevant to the ethernet controller connected to the GPMC
|
||||
refer to the binding documentation of the device. For example, the documentation
|
||||
for the SMSC 911x is Documentation/devicetree/bindings/net/smsc911x.txt
|
||||
|
||||
Child nodes need to specify the GPMC bus address width using the "bank-width"
|
||||
property but is possible that an ethernet controller also has a property to
|
||||
specify the I/O registers address width. Even when the GPMC has a maximum 16-bit
|
||||
address width, it supports devices with 32-bit word registers.
|
||||
For example with an SMSC LAN911x/912x controller connected to the TI GPMC on an
|
||||
OMAP2+ board, "bank-width = <2>;" and "reg-io-width = <4>;".
|
||||
|
||||
Required properties:
|
||||
- bank-width: Address width of the device in bytes. GPMC supports 8-bit
|
||||
and 16-bit devices and so must be either 1 or 2 bytes.
|
||||
- compatible: Compatible string property for the ethernet child device.
|
||||
- gpmc,cs-on: Chip-select assertion time
|
||||
- gpmc,cs-rd-off: Chip-select de-assertion time for reads
|
||||
- gpmc,cs-wr-off: Chip-select de-assertion time for writes
|
||||
- gpmc,oe-on: Output-enable assertion time
|
||||
- gpmc,oe-off Output-enable de-assertion time
|
||||
- gpmc,we-on: Write-enable assertion time
|
||||
- gpmc,we-off: Write-enable de-assertion time
|
||||
- gpmc,access: Start cycle to first data capture (read access)
|
||||
- gpmc,rd-cycle: Total read cycle time
|
||||
- gpmc,wr-cycle: Total write cycle time
|
||||
- reg: Chip-select, base address (relative to chip-select)
|
||||
and size of the memory mapped for the device.
|
||||
Note that base address will be typically 0 as this
|
||||
is the start of the chip-select.
|
||||
|
||||
Optional properties:
|
||||
- gpmc,XXX Additional GPMC timings and settings parameters. See
|
||||
Documentation/devicetree/bindings/bus/ti-gpmc.txt
|
||||
|
||||
Example:
|
||||
|
||||
gpmc: gpmc@6e000000 {
|
||||
compatible = "ti,omap3430-gpmc";
|
||||
ti,hwmods = "gpmc";
|
||||
reg = <0x6e000000 0x1000>;
|
||||
interrupts = <20>;
|
||||
gpmc,num-cs = <8>;
|
||||
gpmc,num-waitpins = <4>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
|
||||
ranges = <5 0 0x2c000000 0x1000000>;
|
||||
|
||||
ethernet@5,0 {
|
||||
compatible = "smsc,lan9221", "smsc,lan9115";
|
||||
reg = <5 0 0xff>;
|
||||
bank-width = <2>;
|
||||
|
||||
gpmc,mux-add-data;
|
||||
gpmc,cs-on = <0>;
|
||||
gpmc,cs-rd-off = <186>;
|
||||
gpmc,cs-wr-off = <186>;
|
||||
gpmc,adv-on = <12>;
|
||||
gpmc,adv-rd-off = <48>;
|
||||
gpmc,adv-wr-off = <48>;
|
||||
gpmc,oe-on = <54>;
|
||||
gpmc,oe-off = <168>;
|
||||
gpmc,we-on = <54>;
|
||||
gpmc,we-off = <168>;
|
||||
gpmc,rd-cycle = <186>;
|
||||
gpmc,wr-cycle = <186>;
|
||||
gpmc,access = <114>;
|
||||
gpmc,page-burst-access = <6>;
|
||||
gpmc,bus-turnaround = <12>;
|
||||
gpmc,cycle2cycle-delay = <18>;
|
||||
gpmc,wr-data-mux-bus = <90>;
|
||||
gpmc,wr-access = <186>;
|
||||
gpmc,cycle2cycle-samecsen;
|
||||
gpmc,cycle2cycle-diffcsen;
|
||||
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <16>;
|
||||
vmmc-supply = <&vddvario>;
|
||||
vmmc_aux-supply = <&vdd33a>;
|
||||
reg-io-width = <4>;
|
||||
|
||||
smsc,save-mac-address;
|
||||
};
|
||||
};
|
@ -74,14 +74,6 @@ static int omap2_nand_gpmc_retime(
|
||||
t.cs_wr_off = gpmc_t->cs_wr_off;
|
||||
t.wr_cycle = 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);
|
||||
gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_WP, 0);
|
||||
err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);
|
||||
if (err)
|
||||
return err;
|
||||
@ -115,14 +107,18 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
|
||||
struct gpmc_timings *gpmc_t)
|
||||
{
|
||||
int err = 0;
|
||||
struct gpmc_settings s;
|
||||
struct device *dev = &gpmc_nand_device.dev;
|
||||
|
||||
memset(&s, 0, sizeof(struct gpmc_settings));
|
||||
|
||||
gpmc_nand_device.dev.platform_data = gpmc_nand_data;
|
||||
|
||||
err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE,
|
||||
(unsigned long *)&gpmc_nand_resource[0].start);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Cannot request GPMC CS\n");
|
||||
dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
|
||||
gpmc_nand_data->cs, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -140,11 +136,31 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
|
||||
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);
|
||||
if (gpmc_nand_data->of_node) {
|
||||
gpmc_read_settings_dt(gpmc_nand_data->of_node, &s);
|
||||
} else {
|
||||
s.device_nand = true;
|
||||
|
||||
/* Enable RD PIN Monitoring Reg */
|
||||
if (gpmc_nand_data->dev_ready) {
|
||||
s.wait_on_read = true;
|
||||
s.wait_on_write = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16)
|
||||
s.device_width = GPMC_DEVWIDTH_16BIT;
|
||||
else
|
||||
s.device_width = GPMC_DEVWIDTH_8BIT;
|
||||
|
||||
err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s);
|
||||
if (err < 0)
|
||||
goto out_free_cs;
|
||||
|
||||
err = gpmc_configure(GPMC_CONFIG_WP, 0);
|
||||
if (err < 0)
|
||||
goto out_free_cs;
|
||||
}
|
||||
|
||||
gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs);
|
||||
|
@ -47,11 +47,23 @@ static struct platform_device gpmc_onenand_device = {
|
||||
.resource = &gpmc_onenand_resource,
|
||||
};
|
||||
|
||||
static struct gpmc_timings omap2_onenand_calc_async_timings(void)
|
||||
static struct gpmc_settings onenand_async = {
|
||||
.device_width = GPMC_DEVWIDTH_16BIT,
|
||||
.mux_add_data = GPMC_MUX_AD,
|
||||
};
|
||||
|
||||
static struct gpmc_settings onenand_sync = {
|
||||
.burst_read = true,
|
||||
.burst_wrap = true,
|
||||
.burst_len = GPMC_BURST_16,
|
||||
.device_width = GPMC_DEVWIDTH_16BIT,
|
||||
.mux_add_data = GPMC_MUX_AD,
|
||||
.wait_pin = 0,
|
||||
};
|
||||
|
||||
static void omap2_onenand_calc_async_timings(struct gpmc_timings *t)
|
||||
{
|
||||
struct gpmc_device_timings dev_t;
|
||||
struct gpmc_timings t;
|
||||
|
||||
const int t_cer = 15;
|
||||
const int t_avdp = 12;
|
||||
const int t_aavdh = 7;
|
||||
@ -64,7 +76,6 @@ static struct gpmc_timings omap2_onenand_calc_async_timings(void)
|
||||
|
||||
memset(&dev_t, 0, sizeof(dev_t));
|
||||
|
||||
dev_t.mux = true;
|
||||
dev_t.t_avdp_r = max_t(int, t_avdp, t_cer) * 1000;
|
||||
dev_t.t_avdp_w = dev_t.t_avdp_r;
|
||||
dev_t.t_aavdh = t_aavdh * 1000;
|
||||
@ -76,19 +87,7 @@ static struct gpmc_timings omap2_onenand_calc_async_timings(void)
|
||||
dev_t.t_wpl = t_wpl * 1000;
|
||||
dev_t.t_wph = t_wph * 1000;
|
||||
|
||||
gpmc_calc_timings(&t, &dev_t);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static int gpmc_set_async_mode(int cs, struct gpmc_timings *t)
|
||||
{
|
||||
/* Configure GPMC for asynchronous read */
|
||||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
|
||||
GPMC_CONFIG1_DEVICESIZE_16 |
|
||||
GPMC_CONFIG1_MUXADDDATA);
|
||||
|
||||
return gpmc_cs_set_timings(cs, t);
|
||||
gpmc_calc_timings(t, &onenand_async, &dev_t);
|
||||
}
|
||||
|
||||
static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
|
||||
@ -158,12 +157,11 @@ static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
|
||||
return freq;
|
||||
}
|
||||
|
||||
static struct gpmc_timings
|
||||
omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
|
||||
int freq)
|
||||
static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t,
|
||||
unsigned int flags,
|
||||
int freq)
|
||||
{
|
||||
struct gpmc_device_timings dev_t;
|
||||
struct gpmc_timings t;
|
||||
const int t_cer = 15;
|
||||
const int t_avdp = 12;
|
||||
const int t_cez = 20; /* max of t_cez, t_oez */
|
||||
@ -172,9 +170,9 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
|
||||
int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
|
||||
int div, gpmc_clk_ns;
|
||||
|
||||
if (cfg->flags & ONENAND_SYNC_READ)
|
||||
if (flags & ONENAND_SYNC_READ)
|
||||
onenand_flags = ONENAND_FLAG_SYNCREAD;
|
||||
else if (cfg->flags & ONENAND_SYNC_READWRITE)
|
||||
else if (flags & ONENAND_SYNC_READWRITE)
|
||||
onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
|
||||
|
||||
switch (freq) {
|
||||
@ -239,10 +237,11 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
|
||||
/* Set synchronous read timings */
|
||||
memset(&dev_t, 0, sizeof(dev_t));
|
||||
|
||||
dev_t.mux = true;
|
||||
dev_t.sync_read = true;
|
||||
if (onenand_flags & ONENAND_FLAG_SYNCREAD)
|
||||
onenand_sync.sync_read = true;
|
||||
if (onenand_flags & ONENAND_FLAG_SYNCWRITE) {
|
||||
dev_t.sync_write = true;
|
||||
onenand_sync.sync_write = true;
|
||||
onenand_sync.burst_write = true;
|
||||
} else {
|
||||
dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000;
|
||||
dev_t.t_wpl = t_wpl * 1000;
|
||||
@ -265,32 +264,7 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
|
||||
dev_t.cyc_aavdh_oe = 1;
|
||||
dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
|
||||
|
||||
gpmc_calc_timings(&t, &dev_t);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t)
|
||||
{
|
||||
unsigned sync_read = onenand_flags & ONENAND_FLAG_SYNCREAD;
|
||||
unsigned sync_write = onenand_flags & ONENAND_FLAG_SYNCWRITE;
|
||||
|
||||
/* 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_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);
|
||||
|
||||
return gpmc_cs_set_timings(cs, t);
|
||||
gpmc_calc_timings(t, &onenand_sync, &dev_t);
|
||||
}
|
||||
|
||||
static int omap2_onenand_setup_async(void __iomem *onenand_base)
|
||||
@ -298,11 +272,19 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
|
||||
struct gpmc_timings t;
|
||||
int ret;
|
||||
|
||||
if (gpmc_onenand_data->of_node)
|
||||
gpmc_read_settings_dt(gpmc_onenand_data->of_node,
|
||||
&onenand_async);
|
||||
|
||||
omap2_onenand_set_async_mode(onenand_base);
|
||||
|
||||
t = omap2_onenand_calc_async_timings();
|
||||
omap2_onenand_calc_async_timings(&t);
|
||||
|
||||
ret = gpmc_set_async_mode(gpmc_onenand_data->cs, &t);
|
||||
ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -322,9 +304,25 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
|
||||
set_onenand_cfg(onenand_base);
|
||||
}
|
||||
|
||||
t = omap2_onenand_calc_sync_timings(gpmc_onenand_data, freq);
|
||||
if (gpmc_onenand_data->of_node) {
|
||||
gpmc_read_settings_dt(gpmc_onenand_data->of_node,
|
||||
&onenand_sync);
|
||||
} else {
|
||||
/*
|
||||
* FIXME: Appears to be legacy code from initial ONENAND commit.
|
||||
* Unclear what boards this is for and if this can be removed.
|
||||
*/
|
||||
if (!cpu_is_omap34xx())
|
||||
onenand_sync.wait_on_read = true;
|
||||
}
|
||||
|
||||
ret = gpmc_set_sync_mode(gpmc_onenand_data->cs, &t);
|
||||
omap2_onenand_calc_sync_timings(&t, gpmc_onenand_data->flags, freq);
|
||||
|
||||
ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_sync);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -359,6 +357,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
|
||||
void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = &gpmc_onenand_device.dev;
|
||||
|
||||
gpmc_onenand_data = _onenand_data;
|
||||
gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
|
||||
@ -366,7 +365,7 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
|
||||
|
||||
if (cpu_is_omap24xx() &&
|
||||
(gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) {
|
||||
printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n");
|
||||
dev_warn(dev, "OneNAND using only SYNC_READ on 24xx\n");
|
||||
gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE;
|
||||
gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
|
||||
}
|
||||
@ -379,7 +378,8 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
|
||||
err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
|
||||
(unsigned long *)&gpmc_onenand_resource.start);
|
||||
if (err < 0) {
|
||||
pr_err("%s: Cannot request GPMC CS\n", __func__);
|
||||
dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
|
||||
gpmc_onenand_data->cs, err);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -387,7 +387,7 @@ void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
|
||||
ONENAND_IO_SIZE - 1;
|
||||
|
||||
if (platform_device_register(&gpmc_onenand_device) < 0) {
|
||||
pr_err("%s: Unable to register OneNAND device\n", __func__);
|
||||
dev_err(dev, "Unable to register OneNAND device\n");
|
||||
gpmc_cs_free(gpmc_onenand_data->cs);
|
||||
return;
|
||||
}
|
||||
|
@ -49,6 +49,10 @@ static struct platform_device gpmc_smc91x_device = {
|
||||
.resource = gpmc_smc91x_resources,
|
||||
};
|
||||
|
||||
static struct gpmc_settings smc91x_settings = {
|
||||
.device_width = GPMC_DEVWIDTH_16BIT,
|
||||
};
|
||||
|
||||
/*
|
||||
* Set the gpmc timings for smc91c96. The timings are taken
|
||||
* from the data sheet available at:
|
||||
@ -67,18 +71,6 @@ static int smc91c96_gpmc_retime(void)
|
||||
const int t7 = 5; /* Figure 12.4 write */
|
||||
const int t8 = 5; /* Figure 12.4 write */
|
||||
const int t20 = 185; /* Figure 12.2 read and 12.4 write */
|
||||
u32 l;
|
||||
|
||||
l = GPMC_CONFIG1_DEVICESIZE_16;
|
||||
if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
|
||||
l |= GPMC_CONFIG1_MUXADDDATA;
|
||||
if (gpmc_cfg->flags & GPMC_READ_MON)
|
||||
l |= GPMC_CONFIG1_WAIT_READ_MON;
|
||||
if (gpmc_cfg->flags & GPMC_WRITE_MON)
|
||||
l |= GPMC_CONFIG1_WAIT_WRITE_MON;
|
||||
if (gpmc_cfg->wait_pin)
|
||||
l |= GPMC_CONFIG1_WAIT_PIN_SEL(gpmc_cfg->wait_pin);
|
||||
gpmc_cs_write_reg(gpmc_cfg->cs, GPMC_CS_CONFIG1, l);
|
||||
|
||||
/*
|
||||
* FIXME: Calculate the address and data bus muxed timings.
|
||||
@ -104,7 +96,7 @@ static int smc91c96_gpmc_retime(void)
|
||||
dev_t.t_cez_w = t4_w * 1000;
|
||||
dev_t.t_wr_cycle = (t20 - t3) * 1000;
|
||||
|
||||
gpmc_calc_timings(&t, &dev_t);
|
||||
gpmc_calc_timings(&t, &smc91x_settings, &dev_t);
|
||||
|
||||
return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
|
||||
}
|
||||
@ -133,6 +125,18 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
|
||||
gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f;
|
||||
gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
|
||||
|
||||
if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
|
||||
smc91x_settings.mux_add_data = GPMC_MUX_AD;
|
||||
if (gpmc_cfg->flags & GPMC_READ_MON)
|
||||
smc91x_settings.wait_on_read = true;
|
||||
if (gpmc_cfg->flags & GPMC_WRITE_MON)
|
||||
smc91x_settings.wait_on_write = true;
|
||||
if (gpmc_cfg->wait_pin)
|
||||
smc91x_settings.wait_pin = gpmc_cfg->wait_pin;
|
||||
ret = gpmc_cs_program_settings(gpmc_cfg->cs, &smc91x_settings);
|
||||
if (ret < 0)
|
||||
goto free1;
|
||||
|
||||
if (gpmc_cfg->retime) {
|
||||
ret = gpmc_cfg->retime();
|
||||
if (ret != 0)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_mtd.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
@ -91,9 +92,7 @@
|
||||
#define GPMC_CS_SIZE 0x30
|
||||
#define GPMC_BCH_SIZE 0x10
|
||||
|
||||
#define GPMC_MEM_START 0x00000000
|
||||
#define GPMC_MEM_END 0x3FFFFFFF
|
||||
#define BOOT_ROM_SPACE 0x100000 /* 1MB */
|
||||
|
||||
#define GPMC_CHUNK_SHIFT 24 /* 16 MB */
|
||||
#define GPMC_SECTION_SHIFT 28 /* 128 MB */
|
||||
@ -107,6 +106,9 @@
|
||||
|
||||
#define GPMC_HAS_WR_ACCESS 0x1
|
||||
#define GPMC_HAS_WR_DATA_MUX_BUS 0x2
|
||||
#define GPMC_HAS_MUX_AAD 0x4
|
||||
|
||||
#define GPMC_NR_WAITPINS 4
|
||||
|
||||
/* XXX: Only NAND irq has been considered,currently these are the only ones used
|
||||
*/
|
||||
@ -153,6 +155,7 @@ static struct resource gpmc_cs_mem[GPMC_CS_NUM];
|
||||
static DEFINE_SPINLOCK(gpmc_mem_lock);
|
||||
/* Define chip-selects as reserved by default until probe completes */
|
||||
static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
|
||||
static unsigned int gpmc_nr_waitpins;
|
||||
static struct device *gpmc_dev;
|
||||
static int gpmc_irq;
|
||||
static resource_size_t phys_base, mem_size;
|
||||
@ -181,7 +184,7 @@ void gpmc_cs_write_reg(int cs, int idx, u32 val)
|
||||
__raw_writel(val, reg_addr);
|
||||
}
|
||||
|
||||
u32 gpmc_cs_read_reg(int cs, int idx)
|
||||
static u32 gpmc_cs_read_reg(int cs, int idx)
|
||||
{
|
||||
void __iomem *reg_addr;
|
||||
|
||||
@ -190,7 +193,7 @@ u32 gpmc_cs_read_reg(int cs, int idx)
|
||||
}
|
||||
|
||||
/* TODO: Add support for gpmc_fck to clock framework and use it */
|
||||
unsigned long gpmc_get_fclk_period(void)
|
||||
static unsigned long gpmc_get_fclk_period(void)
|
||||
{
|
||||
unsigned long rate = clk_get_rate(gpmc_l3_clk);
|
||||
|
||||
@ -205,7 +208,7 @@ unsigned long gpmc_get_fclk_period(void)
|
||||
return rate;
|
||||
}
|
||||
|
||||
unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
|
||||
static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
|
||||
{
|
||||
unsigned long tick_ps;
|
||||
|
||||
@ -215,7 +218,7 @@ unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
|
||||
return (time_ns * 1000 + tick_ps - 1) / tick_ps;
|
||||
}
|
||||
|
||||
unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
|
||||
static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
|
||||
{
|
||||
unsigned long tick_ps;
|
||||
|
||||
@ -230,13 +233,6 @@ unsigned int gpmc_ticks_to_ns(unsigned int ticks)
|
||||
return ticks * gpmc_get_fclk_period() / 1000;
|
||||
}
|
||||
|
||||
unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)
|
||||
{
|
||||
unsigned long ticks = gpmc_ns_to_ticks(time_ns);
|
||||
|
||||
return ticks * gpmc_get_fclk_period() / 1000;
|
||||
}
|
||||
|
||||
static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
|
||||
{
|
||||
return ticks * gpmc_get_fclk_period();
|
||||
@ -405,11 +401,18 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpmc_cs_enable_mem(int cs, u32 base, u32 size)
|
||||
static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
|
||||
{
|
||||
u32 l;
|
||||
u32 mask;
|
||||
|
||||
/*
|
||||
* Ensure that base address is aligned on a
|
||||
* boundary equal to or greater than size.
|
||||
*/
|
||||
if (base & (size - 1))
|
||||
return -EINVAL;
|
||||
|
||||
mask = (1 << GPMC_SECTION_SHIFT) - size;
|
||||
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
|
||||
l &= ~0x3f;
|
||||
@ -418,6 +421,8 @@ static void gpmc_cs_enable_mem(int cs, u32 base, u32 size)
|
||||
l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
|
||||
l |= GPMC_CONFIG7_CSVALID;
|
||||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpmc_cs_disable_mem(int cs)
|
||||
@ -448,22 +453,14 @@ static int gpmc_cs_mem_enabled(int cs)
|
||||
return l & GPMC_CONFIG7_CSVALID;
|
||||
}
|
||||
|
||||
int gpmc_cs_set_reserved(int cs, int reserved)
|
||||
static void 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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpmc_cs_reserved(int cs)
|
||||
static bool gpmc_cs_reserved(int cs)
|
||||
{
|
||||
if (cs > GPMC_CS_NUM)
|
||||
return -ENODEV;
|
||||
|
||||
return gpmc_cs_map & (1 << cs);
|
||||
}
|
||||
|
||||
@ -510,6 +507,39 @@ static int gpmc_cs_delete_mem(int cs)
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpmc_cs_remap - remaps a chip-select physical base address
|
||||
* @cs: chip-select to remap
|
||||
* @base: physical base address to re-map chip-select to
|
||||
*
|
||||
* Re-maps a chip-select to a new physical base address specified by
|
||||
* "base". Returns 0 on success and appropriate negative error code
|
||||
* on failure.
|
||||
*/
|
||||
static int gpmc_cs_remap(int cs, u32 base)
|
||||
{
|
||||
int ret;
|
||||
u32 old_base, size;
|
||||
|
||||
if (cs > GPMC_CS_NUM)
|
||||
return -ENODEV;
|
||||
gpmc_cs_get_memconf(cs, &old_base, &size);
|
||||
if (base == old_base)
|
||||
return 0;
|
||||
gpmc_cs_disable_mem(cs);
|
||||
ret = gpmc_cs_delete_mem(cs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = gpmc_cs_insert_mem(cs, base, size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = gpmc_cs_enable_mem(cs, base, size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
|
||||
{
|
||||
struct resource *res = &gpmc_cs_mem[cs];
|
||||
@ -535,7 +565,12 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
gpmc_cs_enable_mem(cs, res->start, resource_size(res));
|
||||
r = gpmc_cs_enable_mem(cs, res->start, resource_size(res));
|
||||
if (r < 0) {
|
||||
release_resource(res);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*base = res->start;
|
||||
gpmc_cs_set_reserved(cs, 1);
|
||||
out:
|
||||
@ -561,16 +596,14 @@ void gpmc_cs_free(int cs)
|
||||
EXPORT_SYMBOL(gpmc_cs_free);
|
||||
|
||||
/**
|
||||
* gpmc_cs_configure - write request to configure gpmc
|
||||
* @cs: chip select number
|
||||
* gpmc_configure - write request to configure gpmc
|
||||
* @cmd: command type
|
||||
* @wval: value to write
|
||||
* @return status of the operation
|
||||
*/
|
||||
int gpmc_cs_configure(int cs, int cmd, int wval)
|
||||
int gpmc_configure(int cmd, int wval)
|
||||
{
|
||||
int err = 0;
|
||||
u32 regval = 0;
|
||||
u32 regval;
|
||||
|
||||
switch (cmd) {
|
||||
case GPMC_ENABLE_IRQ:
|
||||
@ -590,43 +623,14 @@ int gpmc_cs_configure(int cs, int cmd, int wval)
|
||||
gpmc_write_reg(GPMC_CONFIG, regval);
|
||||
break;
|
||||
|
||||
case GPMC_CONFIG_RDY_BSY:
|
||||
regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
|
||||
if (wval)
|
||||
regval |= WR_RD_PIN_MONITORING;
|
||||
else
|
||||
regval &= ~WR_RD_PIN_MONITORING;
|
||||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
|
||||
break;
|
||||
|
||||
case GPMC_CONFIG_DEV_SIZE:
|
||||
regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
|
||||
|
||||
/* clear 2 target bits */
|
||||
regval &= ~GPMC_CONFIG1_DEVICESIZE(3);
|
||||
|
||||
/* set the proper value */
|
||||
regval |= GPMC_CONFIG1_DEVICESIZE(wval);
|
||||
|
||||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
|
||||
break;
|
||||
|
||||
case GPMC_CONFIG_DEV_TYPE:
|
||||
regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
|
||||
regval |= GPMC_CONFIG1_DEVICETYPE(wval);
|
||||
if (wval == GPMC_DEVICETYPE_NOR)
|
||||
regval |= GPMC_CONFIG1_MUXADDDATA;
|
||||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "gpmc_configure_cs: Not supported\n");
|
||||
err = -EINVAL;
|
||||
pr_err("%s: command not supported\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpmc_cs_configure);
|
||||
EXPORT_SYMBOL(gpmc_configure);
|
||||
|
||||
void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs)
|
||||
{
|
||||
@ -781,16 +785,16 @@ static void gpmc_mem_exit(void)
|
||||
|
||||
}
|
||||
|
||||
static int gpmc_mem_init(void)
|
||||
static void gpmc_mem_init(void)
|
||||
{
|
||||
int cs, rc;
|
||||
unsigned long boot_rom_space = 0;
|
||||
int cs;
|
||||
|
||||
/* never allocate the first page, to facilitate bug detection;
|
||||
* even if we didn't boot from ROM.
|
||||
/*
|
||||
* The first 1MB of GPMC address space is typically mapped to
|
||||
* the internal ROM. Never allocate the first page, to
|
||||
* facilitate bug detection; even if we didn't boot from ROM.
|
||||
*/
|
||||
boot_rom_space = BOOT_ROM_SPACE;
|
||||
gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space;
|
||||
gpmc_mem_root.start = SZ_1M;
|
||||
gpmc_mem_root.end = GPMC_MEM_END;
|
||||
|
||||
/* Reserve all regions that has been set up by bootloader */
|
||||
@ -800,16 +804,12 @@ static int gpmc_mem_init(void)
|
||||
if (!gpmc_cs_mem_enabled(cs))
|
||||
continue;
|
||||
gpmc_cs_get_memconf(cs, &base, &size);
|
||||
rc = gpmc_cs_insert_mem(cs, base, size);
|
||||
if (rc < 0) {
|
||||
while (--cs >= 0)
|
||||
if (gpmc_cs_mem_enabled(cs))
|
||||
gpmc_cs_delete_mem(cs);
|
||||
return rc;
|
||||
if (gpmc_cs_insert_mem(cs, base, size)) {
|
||||
pr_warn("%s: disabling cs %d mapped at 0x%x-0x%x\n",
|
||||
__func__, cs, base, base + size);
|
||||
gpmc_cs_disable_mem(cs);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
|
||||
@ -825,9 +825,9 @@ static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
|
||||
|
||||
/* XXX: can the cycles be avoided ? */
|
||||
static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
|
||||
struct gpmc_device_timings *dev_t)
|
||||
struct gpmc_device_timings *dev_t,
|
||||
bool mux)
|
||||
{
|
||||
bool mux = dev_t->mux;
|
||||
u32 temp;
|
||||
|
||||
/* adv_rd_off */
|
||||
@ -880,9 +880,9 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
|
||||
}
|
||||
|
||||
static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
|
||||
struct gpmc_device_timings *dev_t)
|
||||
struct gpmc_device_timings *dev_t,
|
||||
bool mux)
|
||||
{
|
||||
bool mux = dev_t->mux;
|
||||
u32 temp;
|
||||
|
||||
/* adv_wr_off */
|
||||
@ -942,9 +942,9 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
|
||||
}
|
||||
|
||||
static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
|
||||
struct gpmc_device_timings *dev_t)
|
||||
struct gpmc_device_timings *dev_t,
|
||||
bool mux)
|
||||
{
|
||||
bool mux = dev_t->mux;
|
||||
u32 temp;
|
||||
|
||||
/* adv_rd_off */
|
||||
@ -982,9 +982,9 @@ static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
|
||||
}
|
||||
|
||||
static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
|
||||
struct gpmc_device_timings *dev_t)
|
||||
struct gpmc_device_timings *dev_t,
|
||||
bool mux)
|
||||
{
|
||||
bool mux = dev_t->mux;
|
||||
u32 temp;
|
||||
|
||||
/* adv_wr_off */
|
||||
@ -1054,7 +1054,8 @@ static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
|
||||
}
|
||||
|
||||
static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
|
||||
struct gpmc_device_timings *dev_t)
|
||||
struct gpmc_device_timings *dev_t,
|
||||
bool sync)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
@ -1068,7 +1069,7 @@ static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
|
||||
gpmc_t->cs_on + dev_t->t_ce_avd);
|
||||
gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
|
||||
|
||||
if (dev_t->sync_write || dev_t->sync_read)
|
||||
if (sync)
|
||||
gpmc_calc_sync_common_timings(gpmc_t, dev_t);
|
||||
|
||||
return 0;
|
||||
@ -1103,21 +1104,29 @@ static void gpmc_convert_ps_to_ns(struct gpmc_timings *t)
|
||||
}
|
||||
|
||||
int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
|
||||
struct gpmc_device_timings *dev_t)
|
||||
struct gpmc_settings *gpmc_s,
|
||||
struct gpmc_device_timings *dev_t)
|
||||
{
|
||||
bool mux = false, sync = false;
|
||||
|
||||
if (gpmc_s) {
|
||||
mux = gpmc_s->mux_add_data ? true : false;
|
||||
sync = (gpmc_s->sync_read || gpmc_s->sync_write);
|
||||
}
|
||||
|
||||
memset(gpmc_t, 0, sizeof(*gpmc_t));
|
||||
|
||||
gpmc_calc_common_timings(gpmc_t, dev_t);
|
||||
gpmc_calc_common_timings(gpmc_t, dev_t, sync);
|
||||
|
||||
if (dev_t->sync_read)
|
||||
gpmc_calc_sync_read_timings(gpmc_t, dev_t);
|
||||
if (gpmc_s && gpmc_s->sync_read)
|
||||
gpmc_calc_sync_read_timings(gpmc_t, dev_t, mux);
|
||||
else
|
||||
gpmc_calc_async_read_timings(gpmc_t, dev_t);
|
||||
gpmc_calc_async_read_timings(gpmc_t, dev_t, mux);
|
||||
|
||||
if (dev_t->sync_write)
|
||||
gpmc_calc_sync_write_timings(gpmc_t, dev_t);
|
||||
if (gpmc_s && gpmc_s->sync_write)
|
||||
gpmc_calc_sync_write_timings(gpmc_t, dev_t, mux);
|
||||
else
|
||||
gpmc_calc_async_write_timings(gpmc_t, dev_t);
|
||||
gpmc_calc_async_write_timings(gpmc_t, dev_t, mux);
|
||||
|
||||
/* TODO: remove, see function definition */
|
||||
gpmc_convert_ps_to_ns(gpmc_t);
|
||||
@ -1125,6 +1134,90 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpmc_cs_program_settings - programs non-timing related settings
|
||||
* @cs: GPMC chip-select to program
|
||||
* @p: pointer to GPMC settings structure
|
||||
*
|
||||
* Programs non-timing related settings for a GPMC chip-select, such as
|
||||
* bus-width, burst configuration, etc. Function should be called once
|
||||
* for each chip-select that is being used and must be called before
|
||||
* calling gpmc_cs_set_timings() as timing parameters in the CONFIG1
|
||||
* register will be initialised to zero by this function. Returns 0 on
|
||||
* success and appropriate negative error code on failure.
|
||||
*/
|
||||
int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
|
||||
{
|
||||
u32 config1;
|
||||
|
||||
if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) {
|
||||
pr_err("%s: invalid width %d!", __func__, p->device_width);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Address-data multiplexing not supported for NAND devices */
|
||||
if (p->device_nand && p->mux_add_data) {
|
||||
pr_err("%s: invalid configuration!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((p->mux_add_data > GPMC_MUX_AD) ||
|
||||
((p->mux_add_data == GPMC_MUX_AAD) &&
|
||||
!(gpmc_capability & GPMC_HAS_MUX_AAD))) {
|
||||
pr_err("%s: invalid multiplex configuration!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Page/burst mode supports lengths of 4, 8 and 16 bytes */
|
||||
if (p->burst_read || p->burst_write) {
|
||||
switch (p->burst_len) {
|
||||
case GPMC_BURST_4:
|
||||
case GPMC_BURST_8:
|
||||
case GPMC_BURST_16:
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: invalid page/burst-length (%d)\n",
|
||||
__func__, p->burst_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((p->wait_on_read || p->wait_on_write) &&
|
||||
(p->wait_pin > gpmc_nr_waitpins)) {
|
||||
pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1));
|
||||
|
||||
if (p->sync_read)
|
||||
config1 |= GPMC_CONFIG1_READTYPE_SYNC;
|
||||
if (p->sync_write)
|
||||
config1 |= GPMC_CONFIG1_WRITETYPE_SYNC;
|
||||
if (p->wait_on_read)
|
||||
config1 |= GPMC_CONFIG1_WAIT_READ_MON;
|
||||
if (p->wait_on_write)
|
||||
config1 |= GPMC_CONFIG1_WAIT_WRITE_MON;
|
||||
if (p->wait_on_read || p->wait_on_write)
|
||||
config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin);
|
||||
if (p->device_nand)
|
||||
config1 |= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND);
|
||||
if (p->mux_add_data)
|
||||
config1 |= GPMC_CONFIG1_MUXTYPE(p->mux_add_data);
|
||||
if (p->burst_read)
|
||||
config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP;
|
||||
if (p->burst_write)
|
||||
config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP;
|
||||
if (p->burst_read || p->burst_write) {
|
||||
config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3);
|
||||
config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0;
|
||||
}
|
||||
|
||||
gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id gpmc_dt_ids[] = {
|
||||
{ .compatible = "ti,omap2420-gpmc" },
|
||||
@ -1136,70 +1229,110 @@ static struct of_device_id gpmc_dt_ids[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
|
||||
|
||||
/**
|
||||
* gpmc_read_settings_dt - read gpmc settings from device-tree
|
||||
* @np: pointer to device-tree node for a gpmc child device
|
||||
* @p: pointer to gpmc settings structure
|
||||
*
|
||||
* Reads the GPMC settings for a GPMC child device from device-tree and
|
||||
* stores them in the GPMC settings structure passed. The GPMC settings
|
||||
* structure is initialised to zero by this function and so any
|
||||
* previously stored settings will be cleared.
|
||||
*/
|
||||
void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
|
||||
{
|
||||
memset(p, 0, sizeof(struct gpmc_settings));
|
||||
|
||||
p->sync_read = of_property_read_bool(np, "gpmc,sync-read");
|
||||
p->sync_write = of_property_read_bool(np, "gpmc,sync-write");
|
||||
p->device_nand = of_property_read_bool(np, "gpmc,device-nand");
|
||||
of_property_read_u32(np, "gpmc,device-width", &p->device_width);
|
||||
of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data);
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,burst-length", &p->burst_len)) {
|
||||
p->burst_wrap = of_property_read_bool(np, "gpmc,burst-wrap");
|
||||
p->burst_read = of_property_read_bool(np, "gpmc,burst-read");
|
||||
p->burst_write = of_property_read_bool(np, "gpmc,burst-write");
|
||||
if (!p->burst_read && !p->burst_write)
|
||||
pr_warn("%s: page/burst-length set but not used!\n",
|
||||
__func__);
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,wait-pin", &p->wait_pin)) {
|
||||
p->wait_on_read = of_property_read_bool(np,
|
||||
"gpmc,wait-on-read");
|
||||
p->wait_on_write = of_property_read_bool(np,
|
||||
"gpmc,wait-on-write");
|
||||
if (!p->wait_on_read && !p->wait_on_write)
|
||||
pr_warn("%s: read/write wait monitoring not enabled!\n",
|
||||
__func__);
|
||||
}
|
||||
}
|
||||
|
||||
static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
|
||||
struct gpmc_timings *gpmc_t)
|
||||
{
|
||||
u32 val;
|
||||
struct gpmc_bool_timings *p;
|
||||
|
||||
if (!np || !gpmc_t)
|
||||
return;
|
||||
|
||||
memset(gpmc_t, 0, sizeof(*gpmc_t));
|
||||
|
||||
/* minimum clock period for syncronous mode */
|
||||
if (!of_property_read_u32(np, "gpmc,sync-clk", &val))
|
||||
gpmc_t->sync_clk = val;
|
||||
of_property_read_u32(np, "gpmc,sync-clk-ps", &gpmc_t->sync_clk);
|
||||
|
||||
/* chip select timtings */
|
||||
if (!of_property_read_u32(np, "gpmc,cs-on", &val))
|
||||
gpmc_t->cs_on = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,cs-rd-off", &val))
|
||||
gpmc_t->cs_rd_off = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,cs-wr-off", &val))
|
||||
gpmc_t->cs_wr_off = val;
|
||||
of_property_read_u32(np, "gpmc,cs-on-ns", &gpmc_t->cs_on);
|
||||
of_property_read_u32(np, "gpmc,cs-rd-off-ns", &gpmc_t->cs_rd_off);
|
||||
of_property_read_u32(np, "gpmc,cs-wr-off-ns", &gpmc_t->cs_wr_off);
|
||||
|
||||
/* ADV signal timings */
|
||||
if (!of_property_read_u32(np, "gpmc,adv-on", &val))
|
||||
gpmc_t->adv_on = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,adv-rd-off", &val))
|
||||
gpmc_t->adv_rd_off = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,adv-wr-off", &val))
|
||||
gpmc_t->adv_wr_off = val;
|
||||
of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on);
|
||||
of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off);
|
||||
of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off);
|
||||
|
||||
/* WE signal timings */
|
||||
if (!of_property_read_u32(np, "gpmc,we-on", &val))
|
||||
gpmc_t->we_on = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,we-off", &val))
|
||||
gpmc_t->we_off = val;
|
||||
of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on);
|
||||
of_property_read_u32(np, "gpmc,we-off-ns", &gpmc_t->we_off);
|
||||
|
||||
/* OE signal timings */
|
||||
if (!of_property_read_u32(np, "gpmc,oe-on", &val))
|
||||
gpmc_t->oe_on = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,oe-off", &val))
|
||||
gpmc_t->oe_off = val;
|
||||
of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on);
|
||||
of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off);
|
||||
|
||||
/* access and cycle timings */
|
||||
if (!of_property_read_u32(np, "gpmc,page-burst-access", &val))
|
||||
gpmc_t->page_burst_access = val;
|
||||
of_property_read_u32(np, "gpmc,page-burst-access-ns",
|
||||
&gpmc_t->page_burst_access);
|
||||
of_property_read_u32(np, "gpmc,access-ns", &gpmc_t->access);
|
||||
of_property_read_u32(np, "gpmc,rd-cycle-ns", &gpmc_t->rd_cycle);
|
||||
of_property_read_u32(np, "gpmc,wr-cycle-ns", &gpmc_t->wr_cycle);
|
||||
of_property_read_u32(np, "gpmc,bus-turnaround-ns",
|
||||
&gpmc_t->bus_turnaround);
|
||||
of_property_read_u32(np, "gpmc,cycle2cycle-delay-ns",
|
||||
&gpmc_t->cycle2cycle_delay);
|
||||
of_property_read_u32(np, "gpmc,wait-monitoring-ns",
|
||||
&gpmc_t->wait_monitoring);
|
||||
of_property_read_u32(np, "gpmc,clk-activation-ns",
|
||||
&gpmc_t->clk_activation);
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,access", &val))
|
||||
gpmc_t->access = val;
|
||||
/* only applicable to OMAP3+ */
|
||||
of_property_read_u32(np, "gpmc,wr-access-ns", &gpmc_t->wr_access);
|
||||
of_property_read_u32(np, "gpmc,wr-data-mux-bus-ns",
|
||||
&gpmc_t->wr_data_mux_bus);
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,rd-cycle", &val))
|
||||
gpmc_t->rd_cycle = val;
|
||||
/* bool timing parameters */
|
||||
p = &gpmc_t->bool_timings;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,wr-cycle", &val))
|
||||
gpmc_t->wr_cycle = val;
|
||||
|
||||
/* only for OMAP3430 */
|
||||
if (!of_property_read_u32(np, "gpmc,wr-access", &val))
|
||||
gpmc_t->wr_access = val;
|
||||
|
||||
if (!of_property_read_u32(np, "gpmc,wr-data-mux-bus", &val))
|
||||
gpmc_t->wr_data_mux_bus = val;
|
||||
p->cycle2cyclediffcsen =
|
||||
of_property_read_bool(np, "gpmc,cycle2cycle-diffcsen");
|
||||
p->cycle2cyclesamecsen =
|
||||
of_property_read_bool(np, "gpmc,cycle2cycle-samecsen");
|
||||
p->we_extra_delay = of_property_read_bool(np, "gpmc,we-extra-delay");
|
||||
p->oe_extra_delay = of_property_read_bool(np, "gpmc,oe-extra-delay");
|
||||
p->adv_extra_delay = of_property_read_bool(np, "gpmc,adv-extra-delay");
|
||||
p->cs_extra_delay = of_property_read_bool(np, "gpmc,cs-extra-delay");
|
||||
p->time_para_granularity =
|
||||
of_property_read_bool(np, "gpmc,time-para-granularity");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_NAND
|
||||
@ -1295,6 +1428,81 @@ static int gpmc_probe_onenand_child(struct platform_device *pdev,
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* gpmc_probe_generic_child - configures the gpmc for a child device
|
||||
* @pdev: pointer to gpmc platform device
|
||||
* @child: pointer to device-tree node for child device
|
||||
*
|
||||
* Allocates and configures a GPMC chip-select for a child device.
|
||||
* Returns 0 on success and appropriate negative error code on failure.
|
||||
*/
|
||||
static int gpmc_probe_generic_child(struct platform_device *pdev,
|
||||
struct device_node *child)
|
||||
{
|
||||
struct gpmc_settings gpmc_s;
|
||||
struct gpmc_timings gpmc_t;
|
||||
struct resource res;
|
||||
unsigned long base;
|
||||
int ret, cs;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &cs) < 0) {
|
||||
dev_err(&pdev->dev, "%s has no 'reg' property\n",
|
||||
child->full_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (of_address_to_resource(child, 0, &res) < 0) {
|
||||
dev_err(&pdev->dev, "%s has malformed 'reg' property\n",
|
||||
child->full_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpmc_cs_request(cs, resource_size(&res), &base);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: gpmc_cs_request() will map the CS to an arbitary
|
||||
* location in the gpmc address space. When booting with
|
||||
* device-tree we want the NOR flash to be mapped to the
|
||||
* location specified in the device-tree blob. So remap the
|
||||
* CS to this location. Once DT migration is complete should
|
||||
* just make gpmc_cs_request() map a specific address.
|
||||
*/
|
||||
ret = gpmc_cs_remap(cs, res.start);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot remap GPMC CS %d to 0x%x\n",
|
||||
cs, res.start);
|
||||
goto err;
|
||||
}
|
||||
|
||||
gpmc_read_settings_dt(child, &gpmc_s);
|
||||
|
||||
ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = gpmc_cs_program_settings(cs, &gpmc_s);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
gpmc_read_timings_dt(child, &gpmc_t);
|
||||
gpmc_cs_set_timings(cs, &gpmc_t);
|
||||
|
||||
if (of_platform_device_create(child, NULL, &pdev->dev))
|
||||
return 0;
|
||||
|
||||
dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name);
|
||||
ret = -ENODEV;
|
||||
|
||||
err:
|
||||
gpmc_cs_free(cs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gpmc_probe_dt(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
@ -1305,6 +1513,13 @@ static int gpmc_probe_dt(struct platform_device *pdev)
|
||||
if (!of_id)
|
||||
return 0;
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins",
|
||||
&gpmc_nr_waitpins);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: number of wait pins not found!\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for_each_node_by_name(child, "nand") {
|
||||
ret = gpmc_probe_nand_child(pdev, child);
|
||||
if (ret < 0) {
|
||||
@ -1320,6 +1535,23 @@ static int gpmc_probe_dt(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_node_by_name(child, "nor") {
|
||||
ret = gpmc_probe_generic_child(pdev, child);
|
||||
if (ret < 0) {
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_node_by_name(child, "ethernet") {
|
||||
ret = gpmc_probe_generic_child(pdev, child);
|
||||
if (ret < 0) {
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
@ -1364,18 +1596,27 @@ static int gpmc_probe(struct platform_device *pdev)
|
||||
gpmc_dev = &pdev->dev;
|
||||
|
||||
l = gpmc_read_reg(GPMC_REVISION);
|
||||
|
||||
/*
|
||||
* FIXME: Once device-tree migration is complete the below flags
|
||||
* should be populated based upon the device-tree compatible
|
||||
* string. For now just use the IP revision. OMAP3+ devices have
|
||||
* the wr_access and wr_data_mux_bus register fields. OMAP4+
|
||||
* devices support the addr-addr-data multiplex protocol.
|
||||
*
|
||||
* GPMC IP revisions:
|
||||
* - OMAP24xx = 2.0
|
||||
* - OMAP3xxx = 5.0
|
||||
* - OMAP44xx/54xx/AM335x = 6.0
|
||||
*/
|
||||
if (GPMC_REVISION_MAJOR(l) > 0x4)
|
||||
gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
|
||||
if (GPMC_REVISION_MAJOR(l) > 0x5)
|
||||
gpmc_capability |= GPMC_HAS_MUX_AAD;
|
||||
dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
|
||||
GPMC_REVISION_MINOR(l));
|
||||
|
||||
rc = gpmc_mem_init();
|
||||
if (rc < 0) {
|
||||
clk_disable_unprepare(gpmc_l3_clk);
|
||||
clk_put(gpmc_l3_clk);
|
||||
dev_err(gpmc_dev, "failed to reserve memory\n");
|
||||
return rc;
|
||||
}
|
||||
gpmc_mem_init();
|
||||
|
||||
if (gpmc_setup_irq() < 0)
|
||||
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
|
||||
@ -1383,6 +1624,9 @@ static int gpmc_probe(struct platform_device *pdev)
|
||||
/* Now the GPMC is initialised, unreserve the chip-selects */
|
||||
gpmc_cs_map = 0;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
gpmc_nr_waitpins = GPMC_NR_WAITPINS;
|
||||
|
||||
rc = gpmc_probe_dt(pdev);
|
||||
if (rc < 0) {
|
||||
clk_disable_unprepare(gpmc_l3_clk);
|
||||
|
@ -58,7 +58,7 @@
|
||||
#define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1)
|
||||
#define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10)
|
||||
#define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0)
|
||||
#define GPMC_CONFIG1_MUXADDDATA (1 << 9)
|
||||
#define GPMC_CONFIG1_MUXTYPE(val) ((val & 3) << 8)
|
||||
#define GPMC_CONFIG1_TIME_PARA_GRAN (1 << 4)
|
||||
#define GPMC_CONFIG1_FCLK_DIV(val) (val & 3)
|
||||
#define GPMC_CONFIG1_FCLK_DIV2 (GPMC_CONFIG1_FCLK_DIV(1))
|
||||
@ -73,6 +73,13 @@
|
||||
#define GPMC_IRQ_FIFOEVENTENABLE 0x01
|
||||
#define GPMC_IRQ_COUNT_EVENT 0x02
|
||||
|
||||
#define GPMC_BURST_4 4 /* 4 word burst */
|
||||
#define GPMC_BURST_8 8 /* 8 word burst */
|
||||
#define GPMC_BURST_16 16 /* 16 word burst */
|
||||
#define GPMC_DEVWIDTH_8BIT 1 /* 8-bit device width */
|
||||
#define GPMC_DEVWIDTH_16BIT 2 /* 16-bit device width */
|
||||
#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */
|
||||
#define GPMC_MUX_AD 2 /* Addr-Data multiplex */
|
||||
|
||||
/* bool type time settings */
|
||||
struct gpmc_bool_timings {
|
||||
@ -178,10 +185,6 @@ struct gpmc_device_timings {
|
||||
u8 cyc_wpl; /* write deassertion time in cycles */
|
||||
u32 cyc_iaa; /* initial access time in cycles */
|
||||
|
||||
bool mux; /* address & data muxed */
|
||||
bool sync_write;/* synchronous write */
|
||||
bool sync_read; /* synchronous read */
|
||||
|
||||
/* extra delays */
|
||||
bool ce_xdelay;
|
||||
bool avd_xdelay;
|
||||
@ -189,28 +192,40 @@ struct gpmc_device_timings {
|
||||
bool we_xdelay;
|
||||
};
|
||||
|
||||
struct gpmc_settings {
|
||||
bool burst_wrap; /* enables wrap bursting */
|
||||
bool burst_read; /* enables read page/burst mode */
|
||||
bool burst_write; /* enables write page/burst mode */
|
||||
bool device_nand; /* device is NAND */
|
||||
bool sync_read; /* enables synchronous reads */
|
||||
bool sync_write; /* enables synchronous writes */
|
||||
bool wait_on_read; /* monitor wait on reads */
|
||||
bool wait_on_write; /* monitor wait on writes */
|
||||
u32 burst_len; /* page/burst length */
|
||||
u32 device_width; /* device bus width (8 or 16 bit) */
|
||||
u32 mux_add_data; /* multiplex address & data */
|
||||
u32 wait_pin; /* wait-pin to be used */
|
||||
};
|
||||
|
||||
extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
|
||||
struct gpmc_device_timings *dev_t);
|
||||
struct gpmc_settings *gpmc_s,
|
||||
struct gpmc_device_timings *dev_t);
|
||||
|
||||
extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
|
||||
extern int gpmc_get_client_irq(unsigned irq_config);
|
||||
|
||||
extern unsigned int gpmc_ns_to_ticks(unsigned int time_ns);
|
||||
extern unsigned int gpmc_ps_to_ticks(unsigned int time_ps);
|
||||
extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
|
||||
extern unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns);
|
||||
extern unsigned long gpmc_get_fclk_period(void);
|
||||
|
||||
extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
|
||||
extern u32 gpmc_cs_read_reg(int cs, int idx);
|
||||
extern int gpmc_calc_divider(unsigned int sync_clk);
|
||||
extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
|
||||
extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p);
|
||||
extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
|
||||
extern void gpmc_cs_free(int cs);
|
||||
extern int gpmc_cs_set_reserved(int cs, int reserved);
|
||||
extern int gpmc_cs_reserved(int cs);
|
||||
extern void omap3_gpmc_save_context(void);
|
||||
extern void omap3_gpmc_restore_context(void);
|
||||
extern int gpmc_cs_configure(int cs, int cmd, int wval);
|
||||
extern int gpmc_configure(int cmd, int wval);
|
||||
extern void gpmc_read_settings_dt(struct device_node *np,
|
||||
struct gpmc_settings *p);
|
||||
|
||||
#endif
|
||||
|
@ -8,6 +8,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
@ -26,6 +27,24 @@
|
||||
static u8 async_cs, sync_cs;
|
||||
static unsigned refclk_psec;
|
||||
|
||||
static struct gpmc_settings tusb_async = {
|
||||
.wait_on_read = true,
|
||||
.wait_on_write = true,
|
||||
.device_width = GPMC_DEVWIDTH_16BIT,
|
||||
.mux_add_data = GPMC_MUX_AD,
|
||||
};
|
||||
|
||||
static struct gpmc_settings tusb_sync = {
|
||||
.burst_read = true,
|
||||
.burst_write = true,
|
||||
.sync_read = true,
|
||||
.sync_write = true,
|
||||
.wait_on_read = true,
|
||||
.wait_on_write = true,
|
||||
.burst_len = GPMC_BURST_16,
|
||||
.device_width = GPMC_DEVWIDTH_16BIT,
|
||||
.mux_add_data = GPMC_MUX_AD,
|
||||
};
|
||||
|
||||
/* NOTE: timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
|
||||
|
||||
@ -37,8 +56,6 @@ static int tusb_set_async_mode(unsigned sysclk_ps)
|
||||
|
||||
memset(&dev_t, 0, sizeof(dev_t));
|
||||
|
||||
dev_t.mux = true;
|
||||
|
||||
dev_t.t_ceasu = 8 * 1000;
|
||||
dev_t.t_avdasu = t_acsnh_advnh - 7000;
|
||||
dev_t.t_ce_avd = 1000;
|
||||
@ -52,7 +69,7 @@ static int tusb_set_async_mode(unsigned sysclk_ps)
|
||||
dev_t.t_wpl = 300;
|
||||
dev_t.cyc_aavdh_we = 1;
|
||||
|
||||
gpmc_calc_timings(&t, &dev_t);
|
||||
gpmc_calc_timings(&t, &tusb_async, &dev_t);
|
||||
|
||||
return gpmc_cs_set_timings(async_cs, &t);
|
||||
}
|
||||
@ -65,10 +82,6 @@ static int tusb_set_sync_mode(unsigned sysclk_ps)
|
||||
|
||||
memset(&dev_t, 0, sizeof(dev_t));
|
||||
|
||||
dev_t.mux = true;
|
||||
dev_t.sync_read = true;
|
||||
dev_t.sync_write = true;
|
||||
|
||||
dev_t.clk = 11100;
|
||||
dev_t.t_bacc = 1000;
|
||||
dev_t.t_ces = 1000;
|
||||
@ -84,7 +97,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps)
|
||||
dev_t.cyc_wpl = 6;
|
||||
dev_t.t_ce_rdyz = 7000;
|
||||
|
||||
gpmc_calc_timings(&t, &dev_t);
|
||||
gpmc_calc_timings(&t, &tusb_sync, &dev_t);
|
||||
|
||||
return gpmc_cs_set_timings(sync_cs, &t);
|
||||
}
|
||||
@ -165,18 +178,12 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
|
||||
return status;
|
||||
}
|
||||
tusb_resources[0].end = tusb_resources[0].start + 0x9ff;
|
||||
tusb_async.wait_pin = waitpin;
|
||||
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);
|
||||
|
||||
status = gpmc_cs_program_settings(async_cs, &tusb_async);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
/* SYNC region, primarily for DMA */
|
||||
status = gpmc_cs_request(sync, SZ_16M, (unsigned long *)
|
||||
@ -186,21 +193,12 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
|
||||
return status;
|
||||
}
|
||||
tusb_resources[1].end = tusb_resources[1].start + 0x9ff;
|
||||
tusb_sync.wait_pin = waitpin;
|
||||
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_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 */
|
||||
);
|
||||
|
||||
status = gpmc_cs_program_settings(sync_cs, &tusb_sync);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
/* IRQ */
|
||||
status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq");
|
||||
|
Loading…
Reference in New Issue
Block a user