diff options
author | Peter Chen <peter.chen@freescale.com> | 2014-01-10 00:51:27 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-01-13 18:55:19 -0500 |
commit | ed8f8318d2ef3e5f9e4ddf79349508c116b68d7f (patch) | |
tree | fc8309d0c9eb301472c321c3eb339e49ccc72f65 | |
parent | feffe09f510c475df082546815f9e4a573f6a233 (diff) |
usb: chipidea: add freescale imx28 special write register method
According to Freescale imx28 Errata, "ENGR119653 USB: ARM to USB
register error issue", All USB register write operations must
use the ARM SWP instruction. So, we implement special hw_write
and hw_test_and_clear for imx28.
Discussion for it at below:
http://marc.info/?l=linux-usb&m=137996395529294&w=2
This patch is needed for stable tree 3.11+.
Cc: stable@vger.kernel.org
Cc: robert.hodaszi@digi.com
Signed-off-by: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Tested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/chipidea/ci.h | 26 | ||||
-rw-r--r-- | drivers/usb/chipidea/core.c | 2 | ||||
-rw-r--r-- | drivers/usb/chipidea/host.c | 1 | ||||
-rw-r--r-- | include/linux/usb/chipidea.h | 1 |
4 files changed, 28 insertions, 2 deletions
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index a71dc1c89aa2..88b80f7728e4 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h | |||
@@ -164,6 +164,7 @@ struct hw_bank { | |||
164 | * @id_event: indicates there is an id event, and handled at ci_otg_work | 164 | * @id_event: indicates there is an id event, and handled at ci_otg_work |
165 | * @b_sess_valid_event: indicates there is a vbus event, and handled | 165 | * @b_sess_valid_event: indicates there is a vbus event, and handled |
166 | * at ci_otg_work | 166 | * at ci_otg_work |
167 | * @imx28_write_fix: Freescale imx28 needs swp instruction for writing | ||
167 | */ | 168 | */ |
168 | struct ci_hdrc { | 169 | struct ci_hdrc { |
169 | struct device *dev; | 170 | struct device *dev; |
@@ -202,6 +203,7 @@ struct ci_hdrc { | |||
202 | struct dentry *debugfs; | 203 | struct dentry *debugfs; |
203 | bool id_event; | 204 | bool id_event; |
204 | bool b_sess_valid_event; | 205 | bool b_sess_valid_event; |
206 | bool imx28_write_fix; | ||
205 | }; | 207 | }; |
206 | 208 | ||
207 | static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci) | 209 | static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci) |
@@ -250,6 +252,26 @@ static inline u32 hw_read(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask) | |||
250 | return ioread32(ci->hw_bank.regmap[reg]) & mask; | 252 | return ioread32(ci->hw_bank.regmap[reg]) & mask; |
251 | } | 253 | } |
252 | 254 | ||
255 | #ifdef CONFIG_SOC_IMX28 | ||
256 | static inline void imx28_ci_writel(u32 val, volatile void __iomem *addr) | ||
257 | { | ||
258 | __asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr)); | ||
259 | } | ||
260 | #else | ||
261 | static inline void imx28_ci_writel(u32 val, volatile void __iomem *addr) | ||
262 | { | ||
263 | } | ||
264 | #endif | ||
265 | |||
266 | static inline void __hw_write(struct ci_hdrc *ci, u32 val, | ||
267 | void __iomem *addr) | ||
268 | { | ||
269 | if (ci->imx28_write_fix) | ||
270 | imx28_ci_writel(val, addr); | ||
271 | else | ||
272 | iowrite32(val, addr); | ||
273 | } | ||
274 | |||
253 | /** | 275 | /** |
254 | * hw_write: writes to a hw register | 276 | * hw_write: writes to a hw register |
255 | * @reg: register index | 277 | * @reg: register index |
@@ -263,7 +285,7 @@ static inline void hw_write(struct ci_hdrc *ci, enum ci_hw_regs reg, | |||
263 | data = (ioread32(ci->hw_bank.regmap[reg]) & ~mask) | 285 | data = (ioread32(ci->hw_bank.regmap[reg]) & ~mask) |
264 | | (data & mask); | 286 | | (data & mask); |
265 | 287 | ||
266 | iowrite32(data, ci->hw_bank.regmap[reg]); | 288 | __hw_write(ci, data, ci->hw_bank.regmap[reg]); |
267 | } | 289 | } |
268 | 290 | ||
269 | /** | 291 | /** |
@@ -278,7 +300,7 @@ static inline u32 hw_test_and_clear(struct ci_hdrc *ci, enum ci_hw_regs reg, | |||
278 | { | 300 | { |
279 | u32 val = ioread32(ci->hw_bank.regmap[reg]) & mask; | 301 | u32 val = ioread32(ci->hw_bank.regmap[reg]) & mask; |
280 | 302 | ||
281 | iowrite32(val, ci->hw_bank.regmap[reg]); | 303 | __hw_write(ci, val, ci->hw_bank.regmap[reg]); |
282 | return val; | 304 | return val; |
283 | } | 305 | } |
284 | 306 | ||
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 458d8e412505..0ead0b4a11e1 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c | |||
@@ -548,6 +548,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) | |||
548 | 548 | ||
549 | ci->dev = dev; | 549 | ci->dev = dev; |
550 | ci->platdata = dev->platform_data; | 550 | ci->platdata = dev->platform_data; |
551 | ci->imx28_write_fix = !!(ci->platdata->flags & | ||
552 | CI_HDRC_IMX28_WRITE_FIX); | ||
551 | 553 | ||
552 | ret = hw_device_init(ci, base); | 554 | ret = hw_device_init(ci, base); |
553 | if (ret < 0) { | 555 | if (ret < 0) { |
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 526cd77563d8..a8ac6c16dac9 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c | |||
@@ -65,6 +65,7 @@ static int host_start(struct ci_hdrc *ci) | |||
65 | ehci->caps = ci->hw_bank.cap; | 65 | ehci->caps = ci->hw_bank.cap; |
66 | ehci->has_hostpc = ci->hw_bank.lpm; | 66 | ehci->has_hostpc = ci->hw_bank.lpm; |
67 | ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; | 67 | ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; |
68 | ehci->imx28_write_fix = ci->imx28_write_fix; | ||
68 | 69 | ||
69 | if (ci->platdata->reg_vbus) { | 70 | if (ci->platdata->reg_vbus) { |
70 | ret = regulator_enable(ci->platdata->reg_vbus); | 71 | ret = regulator_enable(ci->platdata->reg_vbus); |
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 7d399671a566..708bd119627f 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h | |||
@@ -24,6 +24,7 @@ struct ci_hdrc_platform_data { | |||
24 | * but otg is not supported (no register otgsc). | 24 | * but otg is not supported (no register otgsc). |
25 | */ | 25 | */ |
26 | #define CI_HDRC_DUAL_ROLE_NOT_OTG BIT(4) | 26 | #define CI_HDRC_DUAL_ROLE_NOT_OTG BIT(4) |
27 | #define CI_HDRC_IMX28_WRITE_FIX BIT(5) | ||
27 | enum usb_dr_mode dr_mode; | 28 | enum usb_dr_mode dr_mode; |
28 | #define CI_HDRC_CONTROLLER_RESET_EVENT 0 | 29 | #define CI_HDRC_CONTROLLER_RESET_EVENT 0 |
29 | #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 | 30 | #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 |