diff options
Diffstat (limited to 'drivers/memory')
-rw-r--r-- | drivers/memory/mvebu-devbus.c | 107 |
1 files changed, 86 insertions, 21 deletions
diff --git a/drivers/memory/mvebu-devbus.c b/drivers/memory/mvebu-devbus.c index 5dc9c6360943..c8f3dad8a825 100644 --- a/drivers/memory/mvebu-devbus.c +++ b/drivers/memory/mvebu-devbus.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Marvell EBU SoC Device Bus Controller | 2 | * Marvell EBU SoC Device Bus Controller |
3 | * (memory controller for NOR/NAND/SRAM/FPGA devices) | 3 | * (memory controller for NOR/NAND/SRAM/FPGA devices) |
4 | * | 4 | * |
5 | * Copyright (C) 2013 Marvell | 5 | * Copyright (C) 2013-2014 Marvell |
6 | * | 6 | * |
7 | * This program is free software: you can redistribute it and/or modify | 7 | * This program is free software: you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -44,6 +44,34 @@ | |||
44 | #define ARMADA_READ_PARAM_OFFSET 0x0 | 44 | #define ARMADA_READ_PARAM_OFFSET 0x0 |
45 | #define ARMADA_WRITE_PARAM_OFFSET 0x4 | 45 | #define ARMADA_WRITE_PARAM_OFFSET 0x4 |
46 | 46 | ||
47 | #define ORION_RESERVED (0x2 << 30) | ||
48 | #define ORION_BADR_SKEW_SHIFT 28 | ||
49 | #define ORION_WR_HIGH_EXT_BIT BIT(27) | ||
50 | #define ORION_WR_HIGH_EXT_MASK 0x8 | ||
51 | #define ORION_WR_LOW_EXT_BIT BIT(26) | ||
52 | #define ORION_WR_LOW_EXT_MASK 0x8 | ||
53 | #define ORION_ALE_WR_EXT_BIT BIT(25) | ||
54 | #define ORION_ALE_WR_EXT_MASK 0x8 | ||
55 | #define ORION_ACC_NEXT_EXT_BIT BIT(24) | ||
56 | #define ORION_ACC_NEXT_EXT_MASK 0x10 | ||
57 | #define ORION_ACC_FIRST_EXT_BIT BIT(23) | ||
58 | #define ORION_ACC_FIRST_EXT_MASK 0x10 | ||
59 | #define ORION_TURN_OFF_EXT_BIT BIT(22) | ||
60 | #define ORION_TURN_OFF_EXT_MASK 0x8 | ||
61 | #define ORION_DEV_WIDTH_SHIFT 20 | ||
62 | #define ORION_WR_HIGH_SHIFT 17 | ||
63 | #define ORION_WR_HIGH_MASK 0x7 | ||
64 | #define ORION_WR_LOW_SHIFT 14 | ||
65 | #define ORION_WR_LOW_MASK 0x7 | ||
66 | #define ORION_ALE_WR_SHIFT 11 | ||
67 | #define ORION_ALE_WR_MASK 0x7 | ||
68 | #define ORION_ACC_NEXT_SHIFT 7 | ||
69 | #define ORION_ACC_NEXT_MASK 0xF | ||
70 | #define ORION_ACC_FIRST_SHIFT 3 | ||
71 | #define ORION_ACC_FIRST_MASK 0xF | ||
72 | #define ORION_TURN_OFF_SHIFT 0 | ||
73 | #define ORION_TURN_OFF_MASK 0x7 | ||
74 | |||
47 | struct devbus_read_params { | 75 | struct devbus_read_params { |
48 | u32 bus_width; | 76 | u32 bus_width; |
49 | u32 badr_skew; | 77 | u32 badr_skew; |
@@ -96,7 +124,6 @@ static int devbus_get_timing_params(struct devbus *devbus, | |||
96 | { | 124 | { |
97 | int err; | 125 | int err; |
98 | 126 | ||
99 | /* Get read timings */ | ||
100 | err = of_property_read_u32(node, "devbus,bus-width", &r->bus_width); | 127 | err = of_property_read_u32(node, "devbus,bus-width", &r->bus_width); |
101 | if (err < 0) { | 128 | if (err < 0) { |
102 | dev_err(devbus->dev, | 129 | dev_err(devbus->dev, |
@@ -138,24 +165,25 @@ static int devbus_get_timing_params(struct devbus *devbus, | |||
138 | if (err < 0) | 165 | if (err < 0) |
139 | return err; | 166 | return err; |
140 | 167 | ||
141 | err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps", | 168 | if (of_device_is_compatible(devbus->dev->of_node, "marvell,mvebu-devbus")) { |
142 | &r->rd_setup); | 169 | err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps", |
143 | if (err < 0) | 170 | &r->rd_setup); |
144 | return err; | 171 | if (err < 0) |
145 | 172 | return err; | |
146 | err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps", | 173 | |
147 | &r->rd_hold); | 174 | err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps", |
148 | if (err < 0) | 175 | &r->rd_hold); |
149 | return err; | 176 | if (err < 0) |
150 | 177 | return err; | |
151 | /* Get write timings */ | 178 | |
152 | err = of_property_read_u32(node, "devbus,sync-enable", | 179 | err = of_property_read_u32(node, "devbus,sync-enable", |
153 | &w->sync_enable); | 180 | &w->sync_enable); |
154 | if (err < 0) { | 181 | if (err < 0) { |
155 | dev_err(devbus->dev, | 182 | dev_err(devbus->dev, |
156 | "%s has no 'devbus,sync-enable' property\n", | 183 | "%s has no 'devbus,sync-enable' property\n", |
157 | node->full_name); | 184 | node->full_name); |
158 | return err; | 185 | return err; |
186 | } | ||
159 | } | 187 | } |
160 | 188 | ||
161 | err = get_timing_param_ps(devbus, node, "devbus,ale-wr-ps", | 189 | err = get_timing_param_ps(devbus, node, "devbus,ale-wr-ps", |
@@ -176,6 +204,39 @@ static int devbus_get_timing_params(struct devbus *devbus, | |||
176 | return 0; | 204 | return 0; |
177 | } | 205 | } |
178 | 206 | ||
207 | static void devbus_orion_set_timing_params(struct devbus *devbus, | ||
208 | struct device_node *node, | ||
209 | struct devbus_read_params *r, | ||
210 | struct devbus_write_params *w) | ||
211 | { | ||
212 | u32 value; | ||
213 | |||
214 | /* | ||
215 | * The hardware designers found it would be a good idea to | ||
216 | * split most of the values in the register into two fields: | ||
217 | * one containing all the low-order bits, and another one | ||
218 | * containing just the high-order bit. For all of those | ||
219 | * fields, we have to split the value into these two parts. | ||
220 | */ | ||
221 | value = (r->turn_off & ORION_TURN_OFF_MASK) << ORION_TURN_OFF_SHIFT | | ||
222 | (r->acc_first & ORION_ACC_FIRST_MASK) << ORION_ACC_FIRST_SHIFT | | ||
223 | (r->acc_next & ORION_ACC_NEXT_MASK) << ORION_ACC_NEXT_SHIFT | | ||
224 | (w->ale_wr & ORION_ALE_WR_MASK) << ORION_ALE_WR_SHIFT | | ||
225 | (w->wr_low & ORION_WR_LOW_MASK) << ORION_WR_LOW_SHIFT | | ||
226 | (w->wr_high & ORION_WR_HIGH_MASK) << ORION_WR_HIGH_SHIFT | | ||
227 | r->bus_width << ORION_DEV_WIDTH_SHIFT | | ||
228 | ((r->turn_off & ORION_TURN_OFF_EXT_MASK) ? ORION_TURN_OFF_EXT_BIT : 0) | | ||
229 | ((r->acc_first & ORION_ACC_FIRST_EXT_MASK) ? ORION_ACC_FIRST_EXT_BIT : 0) | | ||
230 | ((r->acc_next & ORION_ACC_NEXT_EXT_MASK) ? ORION_ACC_NEXT_EXT_BIT : 0) | | ||
231 | ((w->ale_wr & ORION_ALE_WR_EXT_MASK) ? ORION_ALE_WR_EXT_BIT : 0) | | ||
232 | ((w->wr_low & ORION_WR_LOW_EXT_MASK) ? ORION_WR_LOW_EXT_BIT : 0) | | ||
233 | ((w->wr_high & ORION_WR_HIGH_EXT_MASK) ? ORION_WR_HIGH_EXT_BIT : 0) | | ||
234 | (r->badr_skew << ORION_BADR_SKEW_SHIFT) | | ||
235 | ORION_RESERVED; | ||
236 | |||
237 | writel(value, devbus->base); | ||
238 | } | ||
239 | |||
179 | static void devbus_armada_set_timing_params(struct devbus *devbus, | 240 | static void devbus_armada_set_timing_params(struct devbus *devbus, |
180 | struct device_node *node, | 241 | struct device_node *node, |
181 | struct devbus_read_params *r, | 242 | struct devbus_read_params *r, |
@@ -255,7 +316,10 @@ static int mvebu_devbus_probe(struct platform_device *pdev) | |||
255 | return err; | 316 | return err; |
256 | 317 | ||
257 | /* Set the new timing parameters */ | 318 | /* Set the new timing parameters */ |
258 | devbus_armada_set_timing_params(devbus, node, &r, &w); | 319 | if (of_device_is_compatible(node, "marvell,orion-devbus")) |
320 | devbus_orion_set_timing_params(devbus, node, &r, &w); | ||
321 | else | ||
322 | devbus_armada_set_timing_params(devbus, node, &r, &w); | ||
259 | 323 | ||
260 | /* | 324 | /* |
261 | * We need to create a child device explicitly from here to | 325 | * We need to create a child device explicitly from here to |
@@ -271,6 +335,7 @@ static int mvebu_devbus_probe(struct platform_device *pdev) | |||
271 | 335 | ||
272 | static const struct of_device_id mvebu_devbus_of_match[] = { | 336 | static const struct of_device_id mvebu_devbus_of_match[] = { |
273 | { .compatible = "marvell,mvebu-devbus" }, | 337 | { .compatible = "marvell,mvebu-devbus" }, |
338 | { .compatible = "marvell,orion-devbus" }, | ||
274 | {}, | 339 | {}, |
275 | }; | 340 | }; |
276 | MODULE_DEVICE_TABLE(of, mvebu_devbus_of_match); | 341 | MODULE_DEVICE_TABLE(of, mvebu_devbus_of_match); |