1 /* Copyright 2013-2014 IBM Corp.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * 	http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 #include <skiboot.h>
19 #include <device.h>
20 #include <lpc.h>
21 #include <console.h>
22 #include <opal.h>
23 #include <interrupts.h>
24 #include <libflash/libflash.h>
25 #include <libflash/libffs.h>
26 #include <libflash/blocklevel.h>
27 #include <sfc-ctrl.h>
28 #include <ec/config.h>
29 #include <ec/gpio.h>
30 
31 /*
32  * EC GPIO mapping
33  */
34 #define RHESUS_RST_UCD90160_N	EC_GPIO_PORT_J, 3
35 #define RHESUS_FM_PWR_CYCLE_N	EC_GPIO_PORT_K, 2
36 #define RHESUS_EN_PWR_ON_SEQ	EC_GPIO_PORT_R, 1
37 #define RHESUS_BOARD_REVISION0	EC_GPIO_PORT_F, 3
38 #define RHESUS_BOARD_REVISION1	EC_GPIO_PORT_F, 2
39 #define RHESUS_BOARD_REVISION2	EC_GPIO_PORT_E, 5
40 #define RHESUS_BOARD_REVISION3	EC_GPIO_PORT_E, 4
41 #define RHESUS_BOARD_REVISION4	EC_GPIO_PORT_E, 1
42 
43 
44 /*
45  * IO accessors for the EC driver
46  */
ec_outb(uint16_t addr,uint8_t data)47 void ec_outb(uint16_t addr, uint8_t data)
48 {
49 	lpc_outb(data, addr);
50 }
51 
ec_inb(uint16_t addr)52 uint8_t ec_inb(uint16_t addr)
53 {
54 	return lpc_inb(addr);
55 }
56 
rhesus_board_revision(void)57 static int rhesus_board_revision(void)
58 {
59     int revision = 0, ret = 0, i = 0;
60 
61     static const struct {
62         EcGpioPort port;
63         uint8_t pin;
64     } revision_gpios[] = {
65         { RHESUS_BOARD_REVISION0 },
66         { RHESUS_BOARD_REVISION1 },
67         { RHESUS_BOARD_REVISION2 },
68         { RHESUS_BOARD_REVISION3 },
69         { RHESUS_BOARD_REVISION4 },
70     };
71     for (i = 0; i < sizeof(revision_gpios) / sizeof(revision_gpios[0]); ++i)
72     {
73         ret = ec_gpio_read(revision_gpios[i].port, revision_gpios[i].pin);
74         if (ret < 0)
75             return ret;
76         revision <<= 1; revision |= ret;
77     }
78 
79     return revision;
80 }
81 
rhesus_reboot(void)82 static int64_t rhesus_reboot(void)
83 {
84     // TODO(rlippert): This should use EC_SYS_RST_N, but there is nothing to
85     // deassert that at the moment.
86     int ret = 0;
87     ret = ec_gpio_set(RHESUS_FM_PWR_CYCLE_N, 0);
88     if (ret < 0) {
89         return ret;
90     }
91 
92     ret = ec_gpio_setup(RHESUS_FM_PWR_CYCLE_N,
93                         EC_GPIO_OUTPUT,
94                         EC_GPIO_PULLUP_DISABLE);
95     if (ret < 0) {
96         return ret;
97     }
98 
99     return 0;
100 }
101 
rhesus_power_down(uint64_t request __unused)102 static int64_t rhesus_power_down(uint64_t request __unused)
103 {
104     int ret = 0;
105     ret = ec_gpio_set(RHESUS_EN_PWR_ON_SEQ, 0);
106     if (ret < 0) {
107         return ret;
108     }
109 
110     ret = ec_gpio_setup(RHESUS_EN_PWR_ON_SEQ,
111                         EC_GPIO_OUTPUT,
112                         EC_GPIO_PULLUP_DISABLE);
113     if (ret < 0) {
114         return ret;
115     }
116 
117     return 0;
118 }
119 
rhesus_pnor_init(void)120 static int rhesus_pnor_init(void)
121 {
122 	struct spi_flash_ctrl *pnor_ctrl;
123 	struct blocklevel_device *bl = NULL;
124 	int rc;
125 
126 	/* Open controller, flash and ffs */
127 	rc = sfc_open(&pnor_ctrl);
128 	if (rc) {
129 		prerror("PLAT: Failed to open PNOR flash controller\n");
130 		goto fail;
131 	}
132 	rc = flash_init(pnor_ctrl, &bl, NULL);
133 	if (rc) {
134 		prerror("PLAT: Failed to open init PNOR driver\n");
135 		goto fail;
136 	}
137 
138 	rc = flash_register(bl);
139 	if (!rc)
140 		return 0;
141 
142  fail:
143 	if (bl)
144 		flash_exit(bl);
145 	if (pnor_ctrl)
146 		sfc_close(pnor_ctrl);
147 
148 	return rc;
149 }
150 
rhesus_init(void)151 static void rhesus_init(void)
152 {
153 	/* Initialize PNOR/NVRAM */
154 	rhesus_pnor_init();
155 
156 	/* Setup UART for direct use by Linux */
157 	uart_set_console_policy(UART_CONSOLE_OS);
158 }
159 
rhesus_dt_fixup_uart(struct dt_node * lpc,bool has_irq)160 static void rhesus_dt_fixup_uart(struct dt_node *lpc, bool has_irq)
161 {
162 	/*
163 	 * The official OF ISA/LPC binding is a bit odd, it prefixes
164 	 * the unit address for IO with "i". It uses 2 cells, the first
165 	 * one indicating IO vs. Memory space (along with bits to
166 	 * represent aliasing).
167 	 *
168 	 * We pickup that binding and add to it "2" as a indication
169 	 * of FW space.
170 	 *
171 	 * TODO: Probe the UART instead if the LPC bus allows for it
172 	 */
173 	struct dt_node *uart;
174 	char namebuf[32];
175 #define UART_IO_BASE	0x3f8
176 #define UART_IO_COUNT	8
177 
178 	snprintf(namebuf, sizeof(namebuf), "serial@i%x", UART_IO_BASE);
179 	uart = dt_new(lpc, namebuf);
180 
181 	dt_add_property_cells(uart, "reg",
182 			      1, /* IO space */
183 			      UART_IO_BASE, UART_IO_COUNT);
184 	dt_add_property_strings(uart, "compatible",
185 				"ns16550",
186 				"pnpPNP,501");
187 	dt_add_property_cells(uart, "clock-frequency", 1843200);
188 	dt_add_property_cells(uart, "current-speed", 115200);
189 
190 	/*
191 	 * This is needed by Linux for some obscure reasons,
192 	 * we'll eventually need to sanitize it but in the meantime
193 	 * let's make sure it's there
194 	 */
195 	dt_add_property_strings(uart, "device_type", "serial");
196 
197 	/* Expose the external interrupt if supported
198 	 */
199 	if (has_irq) {
200 		uint32_t chip_id = dt_get_chip_id(lpc);
201 		uint32_t irq = get_psi_interrupt(chip_id) + P8_IRQ_PSI_EXTERNAL;
202 		dt_add_property_cells(uart, "interrupts", irq, 1);
203 		dt_add_property_cells(uart, "interrupt-parent",
204 				      get_ics_phandle());
205 	}
206 }
207 
208 /*
209  * This adds the legacy RTC device to the device-tree
210  * for Linux to use
211  */
rhesus_dt_fixup_rtc(struct dt_node * lpc)212 static void rhesus_dt_fixup_rtc(struct dt_node *lpc)
213 {
214 	struct dt_node *rtc;
215 
216 	/*
217 	 * Follows the structure expected by the kernel file
218 	 * arch/powerpc/sysdev/rtc_cmos_setup.c
219 	 */
220 	rtc = dt_new_addr(lpc, "rtc", EC_RTC_PORT_BASE);
221 	assert(rtc);
222 	dt_add_property_string(rtc, "compatible", "pnpPNP,b00");
223 	dt_add_property_cells(rtc, "reg",
224 			      1, /* IO space */
225 			      EC_RTC_PORT_BASE,
226 			      /* 1 index/data pair per 128 bytes */
227 			      (EC_RTC_BLOCK_SIZE / 128) * 2);
228 }
229 
rhesus_dt_fixup(bool has_uart_irq)230 static void rhesus_dt_fixup(bool has_uart_irq)
231 {
232 	struct dt_node *n, *primary_lpc = NULL;
233 
234 	/* Find the primary LPC bus */
235 	dt_for_each_compatible(dt_root, n, "ibm,power8-lpc") {
236 		if (!primary_lpc || dt_has_node_property(n, "primary", NULL))
237 			primary_lpc = n;
238 		if (dt_has_node_property(n, "#address-cells", NULL))
239 			break;
240 	}
241 
242 	if (!primary_lpc)
243 		return;
244 
245 	rhesus_dt_fixup_rtc(primary_lpc);
246 	rhesus_dt_fixup_uart(primary_lpc, has_uart_irq);
247 }
248 
rhesus_probe(void)249 static bool rhesus_probe(void)
250 {
251 	const char *model;
252 	int rev;
253 	bool has_uart_irq = false;
254 
255 	if (!dt_node_is_compatible(dt_root, "ibm,powernv"))
256 		return false;
257 
258 	model = dt_prop_get_def(dt_root, "model", NULL);
259 	if (!model || !(strstr(model, "rhesus") || strstr(model, "RHESUS")))
260 		return false;
261 
262 	/* Grab board version from EC */
263 	rev = rhesus_board_revision();
264 	if (rev >= 0) {
265 		printf("Rhesus board rev %d\n", rev);
266 		dt_add_property_cells(dt_root, "revision-id", rev);
267 	} else
268 		prerror("Rhesus board revision not found !\n");
269 
270 	/* Add missing bits of device-tree such as the UART */
271 	rhesus_dt_fixup(has_uart_irq);
272 
273 	/* Setup UART and use it as console */
274 	uart_init();
275 
276 	return true;
277 }
278 
279 DECLARE_PLATFORM(rhesus) = {
280 	.name		= "Rhesus",
281 	.probe		= rhesus_probe,
282 	.init		= rhesus_init,
283 	.cec_power_down	= rhesus_power_down,
284 	.cec_reboot	= rhesus_reboot,
285 };
286