Skip to content

Commit bc6b1e7

Browse files
zonquetmlind
authored andcommitted
ARM: OMAP: gpmc: add DT bindings for GPMC timings and NAND
This patch adds basic DT bindings for OMAP GPMC. The actual peripherals are instantiated from child nodes within the GPMC node, and the only type of device that is currently supported is NAND. Code was added to parse the generic GPMC timing parameters and some documentation with examples on how to use them. Successfully tested on an AM33xx board. Signed-off-by: Daniel Mack <[email protected]> Acked-by: Grant Likely <[email protected]> [[email protected]: updated to apply] Signed-off-by: Tony Lindgren <[email protected]>
1 parent f50a038 commit bc6b1e7

File tree

3 files changed

+333
-0
lines changed

3 files changed

+333
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
Device tree bindings for OMAP general purpose memory controllers (GPMC)
2+
3+
The actual devices are instantiated from the child nodes of a GPMC node.
4+
5+
Required properties:
6+
7+
- compatible: Should be set to one of the following:
8+
9+
ti,omap2420-gpmc (omap2420)
10+
ti,omap2430-gpmc (omap2430)
11+
ti,omap3430-gpmc (omap3430 & omap3630)
12+
ti,omap4430-gpmc (omap4430 & omap4460 & omap543x)
13+
ti,am3352-gpmc (am335x devices)
14+
15+
- reg: A resource specifier for the register space
16+
(see the example below)
17+
- ti,hwmods: Should be set to "ti,gpmc" until the DT transition is
18+
completed.
19+
- #address-cells: Must be set to 2 to allow memory address translation
20+
- #size-cells: Must be set to 1 to allow CS address passing
21+
- gpmc,num-cs: The maximum number of chip-select lines that controller
22+
can support.
23+
- gpmc,num-waitpins: The maximum number of wait pins that controller can
24+
support.
25+
- ranges: Must be set up to reflect the memory layout with four
26+
integer values for each chip-select line in use:
27+
28+
<cs-number> 0 <physical address of mapping> <size>
29+
30+
Currently, calculated values derived from the contents
31+
of the per-CS register GPMC_CONFIG7 (as set up by the
32+
bootloader) are used for the physical address decoding.
33+
As this will change in the future, filling correct
34+
values here is a requirement.
35+
36+
Timing properties for child nodes. All are optional and default to 0.
37+
38+
- gpmc,sync-clk: Minimum clock period for synchronous mode, in picoseconds
39+
40+
Chip-select signal timings corresponding to GPMC_CONFIG2:
41+
- gpmc,cs-on: Assertion time
42+
- gpmc,cs-rd-off: Read deassertion time
43+
- gpmc,cs-wr-off: Write deassertion time
44+
45+
ADV signal timings corresponding to GPMC_CONFIG3:
46+
- gpmc,adv-on: Assertion time
47+
- gpmc,adv-rd-off: Read deassertion time
48+
- gpmc,adv-wr-off: Write deassertion time
49+
50+
WE signals timings corresponding to GPMC_CONFIG4:
51+
- gpmc,we-on: Assertion time
52+
- gpmc,we-off: Deassertion time
53+
54+
OE signals timings corresponding to GPMC_CONFIG4:
55+
- gpmc,oe-on: Assertion time
56+
- gpmc,oe-off: Deassertion time
57+
58+
Access time and cycle time timings corresponding to GPMC_CONFIG5:
59+
- gpmc,page-burst-access: Multiple access word delay
60+
- gpmc,access: Start-cycle to first data valid delay
61+
- gpmc,rd-cycle: Total read cycle time
62+
- gpmc,wr-cycle: Total write cycle time
63+
64+
The following are only applicable to OMAP3+ and AM335x:
65+
- gpmc,wr-access
66+
- gpmc,wr-data-mux-bus
67+
68+
69+
Example for an AM33xx board:
70+
71+
gpmc: gpmc@50000000 {
72+
compatible = "ti,am3352-gpmc";
73+
ti,hwmods = "gpmc";
74+
reg = <0x50000000 0x2000>;
75+
interrupts = <100>;
76+
77+
gpmc,num-cs = <8>;
78+
gpmc,num-waitpins = <2>;
79+
#address-cells = <2>;
80+
#size-cells = <1>;
81+
ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */
82+
83+
/* child nodes go here */
84+
};
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
Device tree bindings for GPMC connected NANDs
2+
3+
GPMC connected NAND (found on OMAP boards) are represented as child nodes of
4+
the GPMC controller with a name of "nand".
5+
6+
All timing relevant properties as well as generic gpmc child properties are
7+
explained in a separate documents - please refer to
8+
Documentation/devicetree/bindings/bus/ti-gpmc.txt
9+
10+
For NAND specific properties such as ECC modes or bus width, please refer to
11+
Documentation/devicetree/bindings/mtd/nand.txt
12+
13+
14+
Required properties:
15+
16+
- reg: The CS line the peripheral is connected to
17+
18+
Optional properties:
19+
20+
- nand-bus-width: Set this numeric value to 16 if the hardware
21+
is wired that way. If not specified, a bus
22+
width of 8 is assumed.
23+
24+
- ti,nand-ecc-opt: A string setting the ECC layout to use. One of:
25+
26+
"sw" Software method (default)
27+
"hw" Hardware method
28+
"hw-romcode" gpmc hamming mode method & romcode layout
29+
"bch4" 4-bit BCH ecc code
30+
"bch8" 8-bit BCH ecc code
31+
32+
For inline partiton table parsing (optional):
33+
34+
- #address-cells: should be set to 1
35+
- #size-cells: should be set to 1
36+
37+
Example for an AM33xx board:
38+
39+
gpmc: gpmc@50000000 {
40+
compatible = "ti,am3352-gpmc";
41+
ti,hwmods = "gpmc";
42+
reg = <0x50000000 0x1000000>;
43+
interrupts = <100>;
44+
gpmc,num-cs = <8>;
45+
gpmc,num-waitpins = <2>;
46+
#address-cells = <2>;
47+
#size-cells = <1>;
48+
ranges = <0 0 0x08000000 0x2000>; /* CS0: NAND */
49+
50+
nand@0,0 {
51+
reg = <0 0 0>; /* CS0, offset 0 */
52+
nand-bus-width = <16>;
53+
ti,nand-ecc-opt = "bch8";
54+
55+
gpmc,sync-clk = <0>;
56+
gpmc,cs-on = <0>;
57+
gpmc,cs-rd-off = <44>;
58+
gpmc,cs-wr-off = <44>;
59+
gpmc,adv-on = <6>;
60+
gpmc,adv-rd-off = <34>;
61+
gpmc,adv-wr-off = <44>;
62+
gpmc,we-off = <40>;
63+
gpmc,oe-off = <54>;
64+
gpmc,access = <64>;
65+
gpmc,rd-cycle = <82>;
66+
gpmc,wr-cycle = <82>;
67+
gpmc,wr-access = <40>;
68+
gpmc,wr-data-mux-bus = <0>;
69+
70+
#address-cells = <1>;
71+
#size-cells = <1>;
72+
73+
/* partitions go here */
74+
};
75+
};
76+

arch/arm/mach-omap2/gpmc.c

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
#include <linux/module.h>
2626
#include <linux/interrupt.h>
2727
#include <linux/platform_device.h>
28+
#include <linux/of.h>
29+
#include <linux/of_mtd.h>
30+
#include <linux/of_device.h>
31+
#include <linux/mtd/nand.h>
2832

2933
#include <linux/platform_data/mtd-nand-omap2.h>
3034

@@ -34,6 +38,7 @@
3438
#include "common.h"
3539
#include "omap_device.h"
3640
#include "gpmc.h"
41+
#include "gpmc-nand.h"
3742

3843
#define DEVICE_NAME "omap-gpmc"
3944

@@ -1121,6 +1126,165 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
11211126
return 0;
11221127
}
11231128

1129+
#ifdef CONFIG_OF
1130+
static struct of_device_id gpmc_dt_ids[] = {
1131+
{ .compatible = "ti,omap2420-gpmc" },
1132+
{ .compatible = "ti,omap2430-gpmc" },
1133+
{ .compatible = "ti,omap3430-gpmc" }, /* omap3430 & omap3630 */
1134+
{ .compatible = "ti,omap4430-gpmc" }, /* omap4430 & omap4460 & omap543x */
1135+
{ .compatible = "ti,am3352-gpmc" }, /* am335x devices */
1136+
{ }
1137+
};
1138+
MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
1139+
1140+
static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
1141+
struct gpmc_timings *gpmc_t)
1142+
{
1143+
u32 val;
1144+
1145+
memset(gpmc_t, 0, sizeof(*gpmc_t));
1146+
1147+
/* minimum clock period for syncronous mode */
1148+
if (!of_property_read_u32(np, "gpmc,sync-clk", &val))
1149+
gpmc_t->sync_clk = val;
1150+
1151+
/* chip select timtings */
1152+
if (!of_property_read_u32(np, "gpmc,cs-on", &val))
1153+
gpmc_t->cs_on = val;
1154+
1155+
if (!of_property_read_u32(np, "gpmc,cs-rd-off", &val))
1156+
gpmc_t->cs_rd_off = val;
1157+
1158+
if (!of_property_read_u32(np, "gpmc,cs-wr-off", &val))
1159+
gpmc_t->cs_wr_off = val;
1160+
1161+
/* ADV signal timings */
1162+
if (!of_property_read_u32(np, "gpmc,adv-on", &val))
1163+
gpmc_t->adv_on = val;
1164+
1165+
if (!of_property_read_u32(np, "gpmc,adv-rd-off", &val))
1166+
gpmc_t->adv_rd_off = val;
1167+
1168+
if (!of_property_read_u32(np, "gpmc,adv-wr-off", &val))
1169+
gpmc_t->adv_wr_off = val;
1170+
1171+
/* WE signal timings */
1172+
if (!of_property_read_u32(np, "gpmc,we-on", &val))
1173+
gpmc_t->we_on = val;
1174+
1175+
if (!of_property_read_u32(np, "gpmc,we-off", &val))
1176+
gpmc_t->we_off = val;
1177+
1178+
/* OE signal timings */
1179+
if (!of_property_read_u32(np, "gpmc,oe-on", &val))
1180+
gpmc_t->oe_on = val;
1181+
1182+
if (!of_property_read_u32(np, "gpmc,oe-off", &val))
1183+
gpmc_t->oe_off = val;
1184+
1185+
/* access and cycle timings */
1186+
if (!of_property_read_u32(np, "gpmc,page-burst-access", &val))
1187+
gpmc_t->page_burst_access = val;
1188+
1189+
if (!of_property_read_u32(np, "gpmc,access", &val))
1190+
gpmc_t->access = val;
1191+
1192+
if (!of_property_read_u32(np, "gpmc,rd-cycle", &val))
1193+
gpmc_t->rd_cycle = val;
1194+
1195+
if (!of_property_read_u32(np, "gpmc,wr-cycle", &val))
1196+
gpmc_t->wr_cycle = val;
1197+
1198+
/* only for OMAP3430 */
1199+
if (!of_property_read_u32(np, "gpmc,wr-access", &val))
1200+
gpmc_t->wr_access = val;
1201+
1202+
if (!of_property_read_u32(np, "gpmc,wr-data-mux-bus", &val))
1203+
gpmc_t->wr_data_mux_bus = val;
1204+
}
1205+
1206+
#ifdef CONFIG_MTD_NAND
1207+
1208+
static const char * const nand_ecc_opts[] = {
1209+
[OMAP_ECC_HAMMING_CODE_DEFAULT] = "sw",
1210+
[OMAP_ECC_HAMMING_CODE_HW] = "hw",
1211+
[OMAP_ECC_HAMMING_CODE_HW_ROMCODE] = "hw-romcode",
1212+
[OMAP_ECC_BCH4_CODE_HW] = "bch4",
1213+
[OMAP_ECC_BCH8_CODE_HW] = "bch8",
1214+
};
1215+
1216+
static int gpmc_probe_nand_child(struct platform_device *pdev,
1217+
struct device_node *child)
1218+
{
1219+
u32 val;
1220+
const char *s;
1221+
struct gpmc_timings gpmc_t;
1222+
struct omap_nand_platform_data *gpmc_nand_data;
1223+
1224+
if (of_property_read_u32(child, "reg", &val) < 0) {
1225+
dev_err(&pdev->dev, "%s has no 'reg' property\n",
1226+
child->full_name);
1227+
return -ENODEV;
1228+
}
1229+
1230+
gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
1231+
GFP_KERNEL);
1232+
if (!gpmc_nand_data)
1233+
return -ENOMEM;
1234+
1235+
gpmc_nand_data->cs = val;
1236+
gpmc_nand_data->of_node = child;
1237+
1238+
if (!of_property_read_string(child, "ti,nand-ecc-opt", &s))
1239+
for (val = 0; val < ARRAY_SIZE(nand_ecc_opts); val++)
1240+
if (!strcasecmp(s, nand_ecc_opts[val])) {
1241+
gpmc_nand_data->ecc_opt = val;
1242+
break;
1243+
}
1244+
1245+
val = of_get_nand_bus_width(child);
1246+
if (val == 16)
1247+
gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
1248+
1249+
gpmc_read_timings_dt(child, &gpmc_t);
1250+
gpmc_nand_init(gpmc_nand_data, &gpmc_t);
1251+
1252+
return 0;
1253+
}
1254+
#else
1255+
static int gpmc_probe_nand_child(struct platform_device *pdev,
1256+
struct device_node *child)
1257+
{
1258+
return 0;
1259+
}
1260+
#endif
1261+
1262+
static int gpmc_probe_dt(struct platform_device *pdev)
1263+
{
1264+
int ret;
1265+
struct device_node *child;
1266+
const struct of_device_id *of_id =
1267+
of_match_device(gpmc_dt_ids, &pdev->dev);
1268+
1269+
if (!of_id)
1270+
return 0;
1271+
1272+
for_each_node_by_name(child, "nand") {
1273+
ret = gpmc_probe_nand_child(pdev, child);
1274+
of_node_put(child);
1275+
if (ret < 0)
1276+
return ret;
1277+
}
1278+
1279+
return 0;
1280+
}
1281+
#else
1282+
static int gpmc_probe_dt(struct platform_device *pdev)
1283+
{
1284+
return 0;
1285+
}
1286+
#endif
1287+
11241288
static int gpmc_probe(struct platform_device *pdev)
11251289
{
11261290
int rc;
@@ -1174,6 +1338,14 @@ static int gpmc_probe(struct platform_device *pdev)
11741338
if (IS_ERR_VALUE(gpmc_setup_irq()))
11751339
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
11761340

1341+
rc = gpmc_probe_dt(pdev);
1342+
if (rc < 0) {
1343+
clk_disable_unprepare(gpmc_l3_clk);
1344+
clk_put(gpmc_l3_clk);
1345+
dev_err(gpmc_dev, "failed to probe DT parameters\n");
1346+
return rc;
1347+
}
1348+
11771349
return 0;
11781350
}
11791351

@@ -1191,6 +1363,7 @@ static struct platform_driver gpmc_driver = {
11911363
.driver = {
11921364
.name = DEVICE_NAME,
11931365
.owner = THIS_MODULE,
1366+
.of_match_table = of_match_ptr(gpmc_dt_ids),
11941367
},
11951368
};
11961369

0 commit comments

Comments
 (0)