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