xref: /linux/arch/arm/mach-orion5x/mpp.c (revision 82638844d9a8581bbf33201cc209a14876eca167)
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 <asm/hardware.h>
15 #include <asm/io.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 }
164