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