refresh 973-cpmac_handle_mvswitch.patch
[oweals/openwrt.git] / target / linux / ar7 / patches-2.6.32 / 160-vlynq_try_remote_first.patch
1 Index: linux-2.6.32.26/drivers/vlynq/vlynq.c
2 ===================================================================
3 --- linux-2.6.32.26.orig/drivers/vlynq/vlynq.c  2010-11-22 10:48:20.000000000 -0800
4 +++ linux-2.6.32.26/drivers/vlynq/vlynq.c       2010-11-28 02:56:51.972405343 -0800
5 @@ -103,6 +103,12 @@
6  }
7  #endif
8  
9 +u32 __vlynq_rev_reg(struct vlynq_regs *regs)
10 +{
11 +       return readl(&regs->revision);
12 +}
13 +EXPORT_SYMBOL(__vlynq_rev_reg);
14 +
15  /* Check the VLYNQ link status with a given device */
16  static int vlynq_linked(struct vlynq_device *dev)
17  {
18 @@ -117,20 +123,40 @@
19         return 0;
20  }
21  
22 +static volatile int vlynq_delay_value_new = 0;
23 +
24 +static void vlynq_delay_wait(u32 count)
25 +{
26 +       /* Code adopted from original vlynq driver */
27 +       int i = 0;
28 +       volatile int *ptr = &vlynq_delay_value_new;
29 +       *ptr = 0;
30 +
31 +       /* We are assuming that the each cycle takes about
32 +        * 23 assembly instructions. */
33 +       for(i = 0; i < (count + 23)/23; i++)
34 +               *ptr = *ptr + 1;
35 +}
36 +
37  static void vlynq_reset(struct vlynq_device *dev)
38  {
39 +       u32 rtm = readl(&dev->local->revision);
40 +
41 +       rtm = rtm < 0x00010205 || readl(&dev->local->status) & 0x800 == 0 ?
42 +                       0 : 0x600000;
43 +
44         writel(readl(&dev->local->control) | VLYNQ_CTRL_RESET,
45                         &dev->local->control);
46  
47         /* Wait for the devices to finish resetting */
48 -       msleep(5);
49 +       vlynq_delay_wait(0xffffff);
50  
51         /* Remove reset bit */
52 -       writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET,
53 +       writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET | rtm,
54                         &dev->local->control);
55  
56         /* Give some time for the devices to settle */
57 -       msleep(5);
58 +       vlynq_delay_wait(0xffffff);
59  }
60  
61  static void vlynq_irq_unmask(unsigned int irq)
62 @@ -379,6 +405,61 @@
63  }
64  EXPORT_SYMBOL(vlynq_unregister_driver);
65  
66 +enum vlynq_clk_src {
67 +       vlynq_clk_external,
68 +       vlynq_clk_local,
69 +       vlynq_clk_remote,
70 +       vlynq_clk_invalid,
71 +};
72 +
73 +static int __vlynq_set_clocks(struct vlynq_device *dev,
74 +                               enum vlynq_clk_src clk_dir,
75 +                               int lclk_div, int rclk_div)
76 +{
77 +       u32 reg;
78 +
79 +       if (clk_dir == vlynq_clk_invalid) {
80 +               printk(KERN_ERR "%s: attempt to set invalid clocking\n",
81 +                               dev_name(&dev->dev));
82 +               return -EINVAL;
83 +       }
84 +
85 +       reg = readl(&dev->local->control);
86 +       if (readl(&dev->local->revision) < 0x00010205) {
87 +               if (clk_dir & vlynq_clk_local)
88 +                       reg |= VLYNQ_CTRL_CLOCK_INT;
89 +               else
90 +                       reg &= ~VLYNQ_CTRL_CLOCK_INT;
91 +       }
92 +       reg &= ~VLYNQ_CTRL_CLOCK_MASK;
93 +       reg |= VLYNQ_CTRL_CLOCK_DIV(lclk_div);
94 +       writel(reg, &dev->local->control);
95 +
96 +       if (!vlynq_linked(dev))
97 +               return -ENODEV;
98 +
99 +       printk(KERN_INFO "%s: local VLYNQ protocol rev. is 0x%08x\n",
100 +                       dev_name(&dev->dev), readl(&dev->local->revision));
101 +       printk(KERN_INFO "%s: remote VLYNQ protocol rev. is 0x%08x\n",
102 +                       dev_name(&dev->dev), readl(&dev->remote->revision));
103 +
104 +       reg = readl(&dev->remote->control);
105 +       if (readl(&dev->remote->revision) < 0x00010205) {
106 +               if (clk_dir & vlynq_clk_remote)
107 +                       reg |= VLYNQ_CTRL_CLOCK_INT;
108 +               else
109 +                       reg &= ~VLYNQ_CTRL_CLOCK_INT;
110 +       }
111 +       reg &= ~VLYNQ_CTRL_CLOCK_MASK;
112 +       reg |= VLYNQ_CTRL_CLOCK_DIV(rclk_div);
113 +       writel(reg, &dev->remote->control);
114 +
115 +       if (!vlynq_linked(dev))
116 +               return -ENODEV;
117 +
118 +       return 0;
119 +}
120 +
121  /*
122   * A VLYNQ remote device can clock the VLYNQ bus master
123   * using a dedicated clock line. In that case, both the
124 @@ -392,29 +473,17 @@
125         int i;
126  
127         vlynq_reset(dev);
128 -       for (i = dev->dev_id ? vlynq_rdiv2 : vlynq_rdiv8; dev->dev_id ?
129 -                       i <= vlynq_rdiv8 : i >= vlynq_rdiv2;
130 -               dev->dev_id ? i++ : i--) {
131 +       for (i = dev->dev_id ? 0 : 7; dev->dev_id ? i <= 7 : i >= 0;
132 +                       dev->dev_id ? i++ : i--) {
133  
134                 if (!vlynq_linked(dev))
135                         break;
136  
137 -               writel((readl(&dev->remote->control) &
138 -                               ~VLYNQ_CTRL_CLOCK_MASK) |
139 -                               VLYNQ_CTRL_CLOCK_INT |
140 -                               VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
141 -                               &dev->remote->control);
142 -               writel((readl(&dev->local->control)
143 -                               & ~(VLYNQ_CTRL_CLOCK_INT |
144 -                               VLYNQ_CTRL_CLOCK_MASK)) |
145 -                               VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
146 -                               &dev->local->control);
147 -
148 -               if (vlynq_linked(dev)) {
149 -                       printk(KERN_DEBUG
150 -                               "%s: using remote clock divisor %d\n",
151 -                               dev_name(&dev->dev), i - vlynq_rdiv1 + 1);
152 -                       dev->divisor = i;
153 +               if (!__vlynq_set_clocks(dev, vlynq_clk_remote, i, i)) {
154 +                       printk(KERN_INFO
155 +                                       "%s: using remote clock divisor %d\n",
156 +                                       dev_name(&dev->dev), i + 1);
157 +                       dev->divisor = i + vlynq_rdiv1;
158                         return 0;
159                 } else {
160                         vlynq_reset(dev);
161 @@ -437,21 +506,14 @@
162  
163         vlynq_reset(dev);
164  
165 -       for (i = dev->dev_id ? vlynq_ldiv2 : vlynq_ldiv8; dev->dev_id ?
166 -                       i <= vlynq_ldiv8 : i >= vlynq_ldiv2;
167 -               dev->dev_id ? i++ : i--) {
168 -
169 -               writel((readl(&dev->local->control) &
170 -                               ~VLYNQ_CTRL_CLOCK_MASK) |
171 -                               VLYNQ_CTRL_CLOCK_INT |
172 -                               VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1),
173 -                               &dev->local->control);
174 -
175 -               if (vlynq_linked(dev)) {
176 -                       printk(KERN_DEBUG
177 -                               "%s: using local clock divisor %d\n",
178 -                               dev_name(&dev->dev), i - vlynq_ldiv1 + 1);
179 -                       dev->divisor = i;
180 +       for (i = dev->dev_id ? 0 : 7; dev->dev_id ? i <= 7 : i >= 0;
181 +                       dev->dev_id ? i++ : i--) {
182 +
183 +               if (!__vlynq_set_clocks(dev, vlynq_clk_local, i, 0)) {
184 +                       printk(KERN_INFO
185 +                                       "%s: using local clock divisor %d\n",
186 +                                       dev_name(&dev->dev), i + 1);
187 +                       dev->divisor = i + vlynq_ldiv1;
188                         return 0;
189                 } else {
190                         vlynq_reset(dev);
191 @@ -473,18 +535,10 @@
192         if (!vlynq_linked(dev))
193                 return -ENODEV;
194  
195 -       writel((readl(&dev->remote->control) &
196 -                       ~VLYNQ_CTRL_CLOCK_INT),
197 -                       &dev->remote->control);
198 -
199 -       writel((readl(&dev->local->control) &
200 -                       ~VLYNQ_CTRL_CLOCK_INT),
201 -                       &dev->local->control);
202 -
203 -       if (vlynq_linked(dev)) {
204 -               printk(KERN_DEBUG "%s: using external clock\n",
205 -                       dev_name(&dev->dev));
206 -                       dev->divisor = vlynq_div_external;
207 +       if (!__vlynq_set_clocks(dev, vlynq_clk_external, 0, 0)) {
208 +               printk(KERN_INFO "%s: using external clock\n",
209 +                               dev_name(&dev->dev));
210 +                               dev->divisor = vlynq_div_external;
211                 return 0;
212         }
213  
214 @@ -507,18 +561,9 @@
215                  * generation negotiated by hardware.
216                  * Check which device is generating clocks and perform setup
217                  * accordingly */
218 -               if (vlynq_linked(dev) && readl(&dev->remote->control) &
219 -                  VLYNQ_CTRL_CLOCK_INT) {
220 -                       if (!__vlynq_try_remote(dev) ||
221 -                               !__vlynq_try_local(dev)  ||
222 -                               !__vlynq_try_external(dev))
223 -                               return 0;
224 -               } else {
225 -                       if (!__vlynq_try_external(dev) ||
226 -                               !__vlynq_try_local(dev)    ||
227 -                               !__vlynq_try_remote(dev))
228 -                               return 0;
229 -               }
230 +               if (!__vlynq_try_remote(dev) || !__vlynq_try_local(dev) ||
231 +                                               !__vlynq_try_external(dev))
232 +                       return 0;
233                 break;
234         case vlynq_ldiv1:
235         case vlynq_ldiv2:
236 @@ -528,15 +573,12 @@
237         case vlynq_ldiv6:
238         case vlynq_ldiv7:
239         case vlynq_ldiv8:
240 -               writel(VLYNQ_CTRL_CLOCK_INT |
241 -                       VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
242 -                       vlynq_ldiv1), &dev->local->control);
243 -               writel(0, &dev->remote->control);
244 -               if (vlynq_linked(dev)) {
245 -                       printk(KERN_DEBUG
246 -                               "%s: using local clock divisor %d\n",
247 -                               dev_name(&dev->dev),
248 -                               dev->divisor - vlynq_ldiv1 + 1);
249 +               if (!__vlynq_set_clocks(dev, vlynq_clk_local, dev->divisor -
250 +                               vlynq_ldiv1, 0)) {
251 +                       printk(KERN_INFO
252 +                                       "%s: using local clock divisor %d\n",
253 +                                       dev_name(&dev->dev),
254 +                                       dev->divisor - vlynq_ldiv1 + 1);
255                         return 0;
256                 }
257                 break;
258 @@ -548,15 +590,12 @@
259         case vlynq_rdiv6:
260         case vlynq_rdiv7:
261         case vlynq_rdiv8:
262 -               writel(0, &dev->local->control);
263 -               writel(VLYNQ_CTRL_CLOCK_INT |
264 -                       VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
265 -                       vlynq_rdiv1), &dev->remote->control);
266 -               if (vlynq_linked(dev)) {
267 -                       printk(KERN_DEBUG
268 -                               "%s: using remote clock divisor %d\n",
269 -                               dev_name(&dev->dev),
270 -                               dev->divisor - vlynq_rdiv1 + 1);
271 +               if (!__vlynq_set_clocks(dev, vlynq_clk_remote, 0,
272 +                               dev->divisor - vlynq_rdiv1)) {
273 +                       printk(KERN_INFO
274 +                                       "%s: using remote clock divisor %d\n",
275 +                                       dev_name(&dev->dev),
276 +                                       dev->divisor - vlynq_rdiv1 + 1);
277                         return 0;
278                 }
279                 break;
280 @@ -732,13 +771,12 @@
281         platform_set_drvdata(pdev, dev);
282  
283         printk(KERN_INFO "%s: regs 0x%p, irq %d, mem 0x%p\n",
284 -              dev_name(&dev->dev), (void *)dev->regs_start, dev->irq,
285 -              (void *)dev->mem_start);
286 +                       dev_name(&dev->dev), (void *)dev->regs_start,
287 +                       dev->irq, (void *)dev->mem_start);
288  
289         dev->dev_id = 0;
290         dev->divisor = vlynq_div_auto;
291 -       result = __vlynq_enable_device(dev);
292 -       if (result == 0) {
293 +       if (!__vlynq_enable_device(dev)) {
294                 dev->dev_id = readl(&dev->remote->chip);
295                 ((struct plat_vlynq_ops *)(dev->dev.platform_data))->off(dev);
296         }
297 Index: linux-2.6.32.26/include/linux/vlynq.h
298 ===================================================================
299 --- linux-2.6.32.26.orig/include/linux/vlynq.h  2010-11-22 10:48:20.000000000 -0800
300 +++ linux-2.6.32.26/include/linux/vlynq.h       2010-11-27 12:08:39.312438011 -0800
301 @@ -98,6 +98,7 @@
302  
303  extern struct bus_type vlynq_bus_type;
304  
305 +extern u32 __vlynq_rev_reg(struct vlynq_regs *regs);
306  extern int __vlynq_register_driver(struct vlynq_driver *driver,
307                                    struct module *owner);
308