xref: /linux/arch/arm/mach-orion5x/mpp.c (revision ea77f7a2e8561012cf100c530170f12351c3b53e)
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 	for ( ; mode->mpp >= 0; mode++) {
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 
162 	writel(mpp_0_7_ctrl, MPP_0_7_CTRL);
163 	writel(mpp_8_15_ctrl, MPP_8_15_CTRL);
164 	writel(mpp_16_19_ctrl, MPP_16_19_CTRL);
165 }
166