aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2014-01-10 00:51:27 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-13 18:55:19 -0500
commited8f8318d2ef3e5f9e4ddf79349508c116b68d7f (patch)
treefc8309d0c9eb301472c321c3eb339e49ccc72f65
parentfeffe09f510c475df082546815f9e4a573f6a233 (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.h26
-rw-r--r--drivers/usb/chipidea/core.c2
-rw-r--r--drivers/usb/chipidea/host.c1
-rw-r--r--include/linux/usb/chipidea.h1
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 */
168struct ci_hdrc { 169struct 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
207static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci) 209static 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
256static 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
261static inline void imx28_ci_writel(u32 val, volatile void __iomem *addr)
262{
263}
264#endif
265
266static 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