Gale: Add LED support.
[depthcharge.git] / src / board / gale / board.c
1 /*
2  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3  * Copyright 2014 Google Inc.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but without any warranty; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <config.h>
25 #include <libpayload.h>
26 #include <sysinfo.h>
27 #include <stdio.h>
28 #include <stdint.h>
29
30 #include "base/init_funcs.h"
31 #include "boot/fit.h"
32 #include "boot/ramoops.h"
33 #include "drivers/bus/spi/ipq40xx.h"
34 #include "drivers/bus/i2c/ipq40xx.h"
35 #include "drivers/bus/i2c/ipq40xx_blsp.h"
36 #include "drivers/bus/usb/usb.h"
37 #include "drivers/gpio/gpio.h"
38 #include "drivers/gpio/ipq40xx.h"
39 #include "drivers/gpio/sysinfo.h"
40 #include "drivers/power/power.h"
41 #include "drivers/sound/route.h"
42 #include "drivers/storage/ipq40xx_mmc.h"
43 #include "drivers/storage/mtd/mtd.h"
44 #include "drivers/storage/mtd/nand/ipq_nand.h"
45 #include "drivers/storage/mtd/stream.h"
46 #include "drivers/storage/spi_gpt.h"
47 #include "drivers/tpm/slb9635_i2c.h"
48 #include "drivers/tpm/tpm.h"
49 #include "drivers/video/ww_ring.h"
50 #include "vboot/callbacks/nvstorage_flash.h"
51 #include "vboot/stages.h"
52 #include "vboot/util/flag.h"
53
54 #include "board.h"
55
56 #define MSM_SDC1_BASE           0x7824000
57
58
59 /* Structure describing properties of various Storm based boards. */
60 struct board_descriptor {
61         const char *compat_string; // Match the device tree in FIT image.
62         int calibration_needed;    // Some boards need to populate WiFi
63                                    // calibration data.
64         int use_nand;              // true if NAND, false if eMMC
65 };
66
67 static struct board_descriptor bdescriptor;
68
69 static void fill_board_descriptor(void)
70 {
71         switch(lib_sysinfo.board_id) {
72         default:
73                 /* FIXME: Add valid board IDs */
74                 bdescriptor.compat_string = "google,gale";
75                 bdescriptor.calibration_needed = 1;
76                 break;
77         }
78 }
79
80 static const DtPathMap mac_maps[] = {
81         { 0, "soc/edma@c080000/gmac0/local-mac-address" },
82         { 0, "soc/edma@c080000/gmac1/local-mac-address" },
83         //{ 1, "chosen/bluetooth/local-mac-address" },
84         {}
85 };
86
87 static const DtPathMap calibration_maps[] = {
88         {1, "soc/wifi@a000000/qcom,ath10k-pre-calibration-data",
89          "wifi_base64_calibration0"},
90         {1, "soc/wifi@a800000/qcom,ath10k-pre-calibration-data",
91          "wifi_base64_calibration1"},
92         {1, "soc/qcom,pcie@80000/pcie@0/ath10k@0,0/qcom,ath10k-calibration-data",
93          "wifi_base64_calibration2"},
94         {}
95 };
96
97 static int fix_device_tree(DeviceTreeFixup *fixup, DeviceTree *tree)
98 {
99         int rv;
100
101         //rv = dt_set_mac_addresses(tree, mac_maps);
102
103         //if (bdescriptor.calibration_needed)
104                 rv = dt_set_wifi_calibration(tree, calibration_maps);
105
106         return rv;
107 }
108
109 static DeviceTreeFixup ipq_enet_fixup = {
110         .fixup = fix_device_tree
111 };
112
113 gpio_func_data_t mmc_ap_dk04[] = {
114         {
115                 .gpio = 23,
116                 .func = 1,
117                 .pull = GPIO_PULL_UP,
118                 .drvstr = GPIO_10MA,
119                 .oe = GPIO_OE_DISABLE,
120                 .gpio_vm = GPIO_VM_ENABLE,
121                 .gpio_od_en = GPIO_OD_DISABLE,
122                 .gpio_pu_res = GPIO_PULL_RES2
123         },
124         {
125                 .gpio = 24,
126                 .func = 1,
127                 .pull = GPIO_PULL_UP,
128                 .drvstr = GPIO_10MA,
129                 .oe = GPIO_OE_DISABLE,
130                 .gpio_vm = GPIO_VM_ENABLE,
131                 .gpio_od_en = GPIO_OD_DISABLE,
132                 .gpio_pu_res = GPIO_PULL_RES2
133         },
134         {
135                 .gpio = 25,
136                 .func = 1,
137                 .pull = GPIO_PULL_UP,
138                 .drvstr = GPIO_10MA,
139                 .oe = GPIO_OE_DISABLE,
140                 .gpio_vm = GPIO_VM_ENABLE,
141                 .gpio_od_en = GPIO_OD_DISABLE,
142                 .gpio_pu_res = GPIO_PULL_RES2
143         },
144         {
145                 .gpio = 26,
146                 .func = 1,
147                 .pull = GPIO_PULL_UP,
148                 .drvstr = GPIO_10MA,
149                 .oe = GPIO_OE_DISABLE,
150                 .gpio_vm = GPIO_VM_ENABLE,
151                 .gpio_od_en = GPIO_OD_DISABLE,
152                 .gpio_pu_res = GPIO_PULL_RES2
153         },
154         {
155                 .gpio = 27,
156                 .func = 1,
157                 .pull = GPIO_PULL_UP,
158                 .drvstr = GPIO_16MA,
159                 .oe = GPIO_OE_DISABLE,
160                 .gpio_vm = GPIO_VM_ENABLE,
161                 .gpio_od_en = GPIO_OD_DISABLE,
162                 .gpio_pu_res = GPIO_PULL_RES2
163         },
164         {
165                 .gpio = 28,
166                 .func = 1,
167                 .pull = GPIO_PULL_UP,
168                 .drvstr = GPIO_10MA,
169                 .oe = GPIO_OE_DISABLE,
170                 .gpio_vm = GPIO_VM_ENABLE,
171                 .gpio_od_en = GPIO_OD_DISABLE,
172                 .gpio_pu_res = GPIO_PULL_RES2
173         },
174         {
175                 .gpio = 29,
176                 .func = 1,
177                 .pull = GPIO_PULL_UP,
178                 .drvstr = GPIO_10MA,
179                 .oe = GPIO_OE_DISABLE,
180                 .gpio_vm = GPIO_VM_ENABLE,
181                 .gpio_od_en = GPIO_OD_DISABLE,
182                 .gpio_pu_res = GPIO_PULL_RES2
183         },
184         {
185                 .gpio = 30,
186                 .func = 1,
187                 .pull = GPIO_PULL_UP,
188                 .drvstr = GPIO_10MA,
189                 .oe = GPIO_OE_DISABLE,
190                 .gpio_vm = GPIO_VM_ENABLE,
191                 .gpio_od_en = GPIO_OD_DISABLE,
192                 .gpio_pu_res = GPIO_PULL_RES2
193         },
194         {
195                 .gpio = 31,
196                 .func = 1,
197                 .pull = GPIO_PULL_UP,
198                 .drvstr = GPIO_10MA,
199                 .oe = GPIO_OE_DISABLE,
200                 .gpio_vm = GPIO_VM_ENABLE,
201                 .gpio_od_en = GPIO_OD_DISABLE,
202                 .gpio_pu_res = GPIO_PULL_RES2
203         },
204         {
205                 .gpio = 32,
206                 .func = 1,
207                 .pull = GPIO_NO_PULL,
208                 .drvstr = GPIO_10MA,
209                 .oe = GPIO_OE_DISABLE,
210                 .gpio_vm = GPIO_VM_ENABLE,
211                 .gpio_od_en = GPIO_OD_DISABLE,
212                 .gpio_pu_res = GPIO_PULL_RES2
213         },
214 };
215
216 /* Ipq GPIO access wrapper. */
217 typedef struct
218 {
219         GpioOps gpio_ops;       /* Depthcharge GPIO API wrapper. */
220         gpio_t desc;            /* GPIO description. */
221 } IpqGpio;
222
223 static int get_gpio(struct GpioOps *me)
224 {
225         IpqGpio *gpio = container_of(me, IpqGpio, gpio_ops);
226         return gpio_get_in_value(gpio->desc);
227 }
228
229 static GpioOps *new_gpio_input_from_coreboot(uint32_t port)
230 {
231         IpqGpio *gpio = xzalloc(sizeof(*gpio));
232         gpio->gpio_ops.get = get_gpio;
233         gpio->desc = (gpio_t)port;
234         return &gpio->gpio_ops;
235 }
236
237 static void install_phys_presence_flag(void)
238 {
239         GpioOps *phys_presence = sysinfo_lookup_gpio
240                 ("developer", 1, new_gpio_input_from_coreboot);
241
242         if (!phys_presence) {
243                 printf("%s failed retrieving phys presence GPIO\n", __func__);
244                 return;
245         }
246         flag_install(FLAG_PHYS_PRESENCE, phys_presence);
247 }
248
249 void ipq_configure_gpio(gpio_func_data_t *gpio, uint32_t count)
250 {
251         int i;
252
253         for (i = 0; i < count; i++) {
254                 gpio_tlmm_config(gpio->gpio, gpio->func, gpio->out,
255                                 gpio->pull, gpio->drvstr, gpio->oe,
256                                 gpio->gpio_vm, gpio->gpio_od_en,
257                                 gpio->gpio_pu_res);
258                 gpio++;
259         }
260 }
261
262 void board_mmc_gpio_config(void)
263 {
264         ipq_configure_gpio(mmc_ap_dk04, ARRAY_SIZE(mmc_ap_dk04));
265 }
266
267 #if 0
268 void board_i2s_gpio_config(void)
269 {
270         unsigned i;
271         unsigned char gpio_config_arr[] = {I2S_SYNC, I2S_CLK, I2S_DOUT};
272
273         for (i = 0; i < ARRAY_SIZE(gpio_config_arr); i++) {
274                 gpio_tlmm_config_set(gpio_config_arr[i], GPIO_I2S_FUNC_VAL,
275                                 GPIO_NO_PULL, GPIO_16MA, 1);
276         }
277 }
278
279 void board_dac_gpio_config(void)
280 {
281         gpio_tlmm_config_set(DAC_SDMODE, FUNC_SEL_GPIO, GPIO_NO_PULL,
282                         GPIO_16MA, 1);
283 }
284 #endif
285
286 static void set_ramoops_buffer(void)
287 {
288         uint64_t base, total_size, record_size;
289
290         /*
291          * Hardcoded record and total sizes could be defined through Kconfig.
292          *
293          * The 'total_size' bytes of memory, aligned at 'record_size' boundary
294          * is found at the top of available memory as defined in the coreboot
295          * table and assigned to the ramoops cache.
296          *
297          * This is fairly brittle, as other parts of depthcharge or libpayload
298          * could be using this memory for something. But this is no worse than
299          * hardcoding this area to any particular address.
300          *
301          * A proper solution would be to have coreboot assign this memory and
302          * explicitly describe this in the coreboot memory table.
303          */
304         record_size = 0x20000;
305         total_size = 0x100000;
306         base = 0;
307
308         /* Let's allocate it as high as possible in the available memory */
309         for (int i = 0; i < lib_sysinfo.n_memranges; i++) {
310                 uint64_t new_base, size;
311                 struct memrange *range = lib_sysinfo.memrange + i;
312
313                 size = range->size;
314                 if ((range->type != CB_MEM_RAM) ||
315                     (size < (total_size + record_size)))
316                         continue;
317
318                 /* Record size aligned area is guaranteed to fit. */
319                 new_base = ALIGN_DOWN(range->base + size - total_size,
320                                       record_size);
321                 if (new_base > base)
322                         base = new_base;
323
324         }
325         if (base)
326                 ramoops_buffer(base, total_size, record_size);
327 }
328
329 static uint8_t kb_buffer[4];
330 static int kb_in, kb_out;
331
332 static int dakota_havekey(void)
333 {
334         /*
335          * We want to react to the button press only, i.e. we need to
336          * catch the "unpressed -> pressed" transition.
337          */
338         static uint32_t prev = 1;
339         uint32_t rv = flag_fetch(FLAG_PHYS_PRESENCE);
340
341         if (prev == rv)
342                 return kb_in != kb_out;
343
344         prev = rv;
345         if (!rv)
346                 return kb_in != kb_out;
347
348         if (((kb_in + 1) % sizeof(kb_buffer)) == kb_out) {
349                 printf("%s: keyboard buffer overflow!\n", __func__);
350                 return 0;
351         }
352
353         /* Dev switch was pressed, what's the meaning of it? */
354         if (vboot_in_recovery()) {
355                 /* This must mean ^D, the user wants to switch to dev mode. */
356                 kb_buffer[kb_in++] = 0x4;
357                 kb_in %= sizeof(kb_buffer);
358
359                 if (((kb_in + 1) % sizeof(kb_buffer)) != kb_out)
360                         kb_buffer[kb_in++] = 0xd;
361                 else
362                         /*
363                          * Should never happen, but worse come to worse the
364                          * user will lose the CR and will have to reboot in
365                          * recovery mode again to enter dev mode.
366                          */
367                         printf("%s: keyboard buffer overflow!\n", __func__);
368         } else {
369                 /* This must mean ^U, the user wants to boot from USB. */
370                 kb_buffer[kb_in++] = 0x15;
371         }
372
373         kb_in %= sizeof(kb_buffer);
374
375         return 1;
376 }
377
378 static int dakota_getchar(void)
379 {
380         int storm_char;
381
382         while (!dakota_havekey())
383                 ;
384
385         storm_char = kb_buffer[kb_out++];
386
387         kb_out %= sizeof(kb_buffer);
388
389         return storm_char;
390 }
391
392 static struct console_input_driver dakota_input_driver =
393 {
394         NULL,
395         &dakota_havekey,
396         &dakota_getchar
397 };
398
399 static int board_setup(void)
400 {
401         sysinfo_install_flags(NULL);
402
403         fill_board_descriptor();
404
405         fit_set_compat(bdescriptor.compat_string);
406
407         install_phys_presence_flag();
408
409         console_add_input_driver(&dakota_input_driver);
410
411         power_set_ops(new_ipq40xx_power_ops());
412
413         SpiController *spi = new_spi(0, 0);
414         flash_set_ops(&new_spi_flash(&spi->ops)->ops);
415
416         QcomMmcHost *mmc = new_qcom_mmc_host(1, MSM_SDC1_BASE, 8);
417
418         if (!mmc)
419                 return -1;
420
421         list_insert_after(&mmc->mmc.ctrlr.list_node,
422                                   &fixed_block_dev_controllers);
423
424         UsbHostController *usb_host1 = new_usb_hc(XHCI, 0x8A00000);
425
426         list_insert_after(&usb_host1->list_node, &usb_host_controllers);
427
428 #if (!CONFIG_MOCK_TPM)
429         Ipq40xxI2c *i2c = new_ipq40xx_i2c(BLSP_QUP_ID_2);
430         tpm_set_ops(&new_slb9635_i2c(&i2c->ops, 0x20)->base.ops);
431 #endif
432
433         DisplayOps *ww_ring_ops = new_ww_ring_display
434                 (&new_ipq40xx_i2c (BLSP_QUP_ID_3)->ops, 0x32);
435
436         display_set_ops(ww_ring_ops);
437
438         display_init();
439
440 #if 0
441         Ipq806xSound *sound = new_ipq806x_sound(new_storm_dac_gpio_output(),
442                         48000, 2, 16, 1000);
443         SoundRoute *sound_route = new_sound_route(&sound->ops);
444         sound_set_ops(&sound_route->ops);
445
446 #endif
447         write32(ADSS_AUDIO_TXB_CBCR_REG, 0); /* Disable ADSS clock branch */
448
449         list_insert_after(&ipq_enet_fixup.list_node, &device_tree_fixups);
450
451         set_ramoops_buffer();
452
453         return 0;
454 }
455
456 int board_wan_port_number(void)
457 {
458         if ((lib_sysinfo.board_id == BOARD_ID_PROTO_0) ||
459             (lib_sysinfo.board_id == BOARD_ID_PROTO_0_2))
460                 return 4; /* Storm variants */
461
462         return 1; /* Whirlwind variants, let it be the default. */
463 }
464
465 INIT_FUNC(board_setup);