Merge branch 'for-2.6.28' of git://linux-nfs.org/~bfields/linux
[linux-2.6] / arch / arm / mach-orion5x / mpp.c
1 /*
2  * arch/arm/mach-orion5x/mpp.c
3  *
4  * MPP functions for Marvell Orion 5x SoCs
5  *
6  * This file is licensed under the terms of the GNU General Public
7  * License version 2.  This program is licensed "as is" without any
8  * warranty of any kind, whether express or implied.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/mbus.h>
14 #include <linux/io.h>
15 #include <mach/hardware.h>
16 #include "common.h"
17 #include "mpp.h"
18
19 static int is_5181l(void)
20 {
21         u32 dev;
22         u32 rev;
23
24         orion5x_pcie_id(&dev, &rev);
25
26         return !!(dev == MV88F5181_DEV_ID && rev >= MV88F5181L_REV_A0);
27 }
28
29 static int is_5182(void)
30 {
31         u32 dev;
32         u32 rev;
33
34         orion5x_pcie_id(&dev, &rev);
35
36         return !!(dev == MV88F5182_DEV_ID);
37 }
38
39 static int is_5281(void)
40 {
41         u32 dev;
42         u32 rev;
43
44         orion5x_pcie_id(&dev, &rev);
45
46         return !!(dev == MV88F5281_DEV_ID);
47 }
48
49 static int __init determine_type_encoding(int mpp, enum orion5x_mpp_type type)
50 {
51         switch (type) {
52         case MPP_UNUSED:
53         case MPP_GPIO:
54                 if (mpp == 0)
55                         return 3;
56                 if (mpp >= 1 && mpp <= 15)
57                         return 0;
58                 if (mpp >= 16 && mpp <= 19) {
59                         if (is_5182())
60                                 return 5;
61                         if (type == MPP_UNUSED)
62                                 return 0;
63                 }
64                 return -1;
65
66         case MPP_PCIE_RST_OUTn:
67                 if (mpp == 0)
68                         return 0;
69                 return -1;
70
71         case MPP_PCI_ARB:
72                 if (mpp >= 0 && mpp <= 7)
73                         return 2;
74                 return -1;
75
76         case MPP_PCI_PMEn:
77                 if (mpp == 2)
78                         return 3;
79                 return -1;
80
81         case MPP_GIGE:
82                 if (mpp >= 8 && mpp <= 19)
83                         return 1;
84                 return -1;
85
86         case MPP_NAND:
87                 if (is_5182() || is_5281()) {
88                         if (mpp >= 4 && mpp <= 7)
89                                 return 4;
90                         if (mpp >= 12 && mpp <= 17)
91                                 return 4;
92                 }
93                 return -1;
94
95         case MPP_PCI_CLK:
96                 if (is_5181l() && mpp >= 6 && mpp <= 7)
97                         return 5;
98                 return -1;
99
100         case MPP_SATA_LED:
101                 if (is_5182()) {
102                         if (mpp >= 4 && mpp <= 7)
103                                 return 5;
104                         if (mpp >= 12 && mpp <= 15)
105                                 return 5;
106                 }
107                 return -1;
108
109         case MPP_UART:
110                 if (mpp >= 16 && mpp <= 19)
111                         return 0;
112                 return -1;
113         }
114
115         printk(KERN_INFO "unknown MPP type %d\n", type);
116
117         return -1;
118 }
119
120 void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
121 {
122         u32 mpp_0_7_ctrl = readl(MPP_0_7_CTRL);
123         u32 mpp_8_15_ctrl = readl(MPP_8_15_CTRL);
124         u32 mpp_16_19_ctrl = readl(MPP_16_19_CTRL);
125
126         while (mode->mpp >= 0) {
127                 u32 *reg;
128                 int num_type;
129                 int shift;
130
131                 if (mode->mpp >= 0 && mode->mpp <= 7)
132                         reg = &mpp_0_7_ctrl;
133                 else if (mode->mpp >= 8 && mode->mpp <= 15)
134                         reg = &mpp_8_15_ctrl;
135                 else if (mode->mpp >= 16 && mode->mpp <= 19)
136                         reg = &mpp_16_19_ctrl;
137                 else {
138                         printk(KERN_ERR "orion5x_mpp_conf: invalid MPP "
139                                         "(%d)\n", mode->mpp);
140                         continue;
141                 }
142
143                 num_type = determine_type_encoding(mode->mpp, mode->type);
144                 if (num_type < 0) {
145                         printk(KERN_ERR "orion5x_mpp_conf: invalid MPP "
146                                         "combination (%d, %d)\n", mode->mpp,
147                                         mode->type);
148                         continue;
149                 }
150
151                 shift = (mode->mpp & 7) << 2;
152                 *reg &= ~(0xf << shift);
153                 *reg |= (num_type & 0xf) << shift;
154
155                 orion5x_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO));
156
157                 mode++;
158         }
159
160         writel(mpp_0_7_ctrl, MPP_0_7_CTRL);
161         writel(mpp_8_15_ctrl, MPP_8_15_CTRL);
162         writel(mpp_16_19_ctrl, MPP_16_19_CTRL);
163 }