Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright 2014 Google Inc. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 14 | */ |
| 15 | |
| 16 | #include <arch/io.h> |
Julius Werner | f0d21ff3 | 2014-10-20 13:24:14 -0700 | [diff] [blame] | 17 | #include <boot/coreboot_tables.h> |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 18 | #include <device/device.h> |
David Hendricks | f6e17c0 | 2014-03-20 18:43:45 -0700 | [diff] [blame] | 19 | #include <elog.h> |
Julius Werner | eaa9c45 | 2014-09-24 15:40:49 -0700 | [diff] [blame] | 20 | #include <gpio.h> |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 21 | #include <soc/addressmap.h> |
Julius Werner | f0d21ff3 | 2014-10-20 13:24:14 -0700 | [diff] [blame] | 22 | #include <soc/clk_rst.h> |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 23 | #include <soc/clock.h> |
Julius Werner | f0d21ff3 | 2014-10-20 13:24:14 -0700 | [diff] [blame] | 24 | #include <soc/mc.h> |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 25 | #include <soc/nvidia/tegra/i2c.h> |
Julius Werner | f0d21ff3 | 2014-10-20 13:24:14 -0700 | [diff] [blame] | 26 | #include <soc/pmc.h> |
| 27 | #include <soc/spi.h> |
Furquan Shaikh | 2296774 | 2014-08-06 09:53:55 -0700 | [diff] [blame] | 28 | #include <soc/nvidia/tegra/usb.h> |
Julius Werner | ec5e5e0 | 2014-08-20 15:29:56 -0700 | [diff] [blame] | 29 | #include <symbols.h> |
David Hendricks | d72d8aa | 2014-05-13 20:32:14 -0700 | [diff] [blame] | 30 | #include <vendorcode/google/chromeos/chromeos.h> |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 31 | |
| 32 | static struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE; |
| 33 | |
| 34 | static void set_clock_sources(void) |
| 35 | { |
Gabe Black | 41c9260 | 2014-03-05 22:07:41 -0800 | [diff] [blame] | 36 | /* |
| 37 | * The max98090 codec and the temperature sensor are on I2C1. These |
| 38 | * can both run at 400 KHz, but the kernel sets the bus to 100 KHz. |
| 39 | */ |
| 40 | clock_configure_i2c_scl_freq(i2c1, PLLP, 100); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 41 | |
| 42 | /* |
| 43 | * MMC3 and MMC4: Set base clock frequency for SD Clock to Tegra MMC's |
| 44 | * maximum speed (48MHz) so we can change SDCLK by second stage divisor |
| 45 | * in payloads, without touching base clock. |
| 46 | */ |
| 47 | clock_configure_source(sdmmc3, PLLP, 48000); |
| 48 | clock_configure_source(sdmmc4, PLLP, 48000); |
| 49 | |
| 50 | /* External peripheral 1: audio codec (max98090) using 12MHz CLK1. |
| 51 | * Note the source id of CLK_M for EXTPERIPH1 is 3. */ |
| 52 | clock_configure_irregular_source(extperiph1, CLK_M, 12000, 3); |
| 53 | |
| 54 | /* |
Daisuke Nojiri | e7cb1bc | 2014-03-28 09:21:37 -0700 | [diff] [blame] | 55 | * We need 1.5MHz. So, we use CLK_M. CLK_DIVIDER macro returns a divisor |
| 56 | * (0xe) a little bit off from the ideal value (0xd) but it's good |
| 57 | * enough for beeps. The source id of CLK_M for I2S is 6. |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 58 | */ |
Daisuke Nojiri | e7cb1bc | 2014-03-28 09:21:37 -0700 | [diff] [blame] | 59 | clock_configure_irregular_source(i2s1, CLK_M, 1500, 6); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 60 | |
| 61 | /* Note source id of PLLP for HOST1x is 4. */ |
| 62 | clock_configure_irregular_source(host1x, PLLP, 408000, 4); |
| 63 | |
| 64 | /* Use PLLD_OUT0 as clock source for disp1 */ |
| 65 | clrsetbits_le32(&clk_rst->clk_src_disp1, |
| 66 | CLK_SOURCE_MASK | CLK_DIVISOR_MASK, |
| 67 | 2 /*PLLD_OUT0 */ << CLK_SOURCE_SHIFT); |
| 68 | |
| 69 | } |
| 70 | |
| 71 | static void setup_pinmux(void) |
| 72 | { |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 73 | // I2C1 clock. |
| 74 | pinmux_set_config(PINMUX_GEN1_I2C_SCL_INDEX, |
| 75 | PINMUX_GEN1_I2C_SCL_FUNC_I2C1 | PINMUX_INPUT_ENABLE); |
| 76 | // I2C1 data. |
| 77 | pinmux_set_config(PINMUX_GEN1_I2C_SDA_INDEX, |
| 78 | PINMUX_GEN1_I2C_SDA_FUNC_I2C1 | PINMUX_INPUT_ENABLE); |
| 79 | // I2C2 clock. |
| 80 | pinmux_set_config(PINMUX_GEN2_I2C_SCL_INDEX, |
Ken Chang | a859aa3 | 2014-05-22 10:54:16 +0800 | [diff] [blame] | 81 | PINMUX_GEN2_I2C_SCL_FUNC_I2C2 | PINMUX_INPUT_ENABLE | |
| 82 | PINMUX_OPEN_DRAIN); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 83 | // I2C2 data. |
| 84 | pinmux_set_config(PINMUX_GEN2_I2C_SDA_INDEX, |
Ken Chang | a859aa3 | 2014-05-22 10:54:16 +0800 | [diff] [blame] | 85 | PINMUX_GEN2_I2C_SDA_FUNC_I2C2 | PINMUX_INPUT_ENABLE | |
| 86 | PINMUX_OPEN_DRAIN); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 87 | // I2C4 (DDC) clock. |
| 88 | pinmux_set_config(PINMUX_DDC_SCL_INDEX, |
| 89 | PINMUX_DDC_SCL_FUNC_I2C4 | PINMUX_INPUT_ENABLE); |
| 90 | // I2C4 (DDC) data. |
| 91 | pinmux_set_config(PINMUX_DDC_SDA_INDEX, |
| 92 | PINMUX_DDC_SDA_FUNC_I2C4 | PINMUX_INPUT_ENABLE); |
| 93 | |
| 94 | // TODO(hungte) Revice pinmux setup, make nice little SoC functions for |
| 95 | // every single logical thing instead of dumping a wall of code below. |
| 96 | uint32_t pin_up = PINMUX_PULL_UP | PINMUX_INPUT_ENABLE, |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 97 | pin_down = PINMUX_PULL_DOWN | PINMUX_INPUT_ENABLE, |
| 98 | pin_none = PINMUX_PULL_NONE | PINMUX_INPUT_ENABLE; |
| 99 | |
Hung-Te Lin | 6a16f69 | 2014-04-24 21:07:05 +0800 | [diff] [blame] | 100 | // MMC3 (sdcard reader) |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 101 | pinmux_set_config(PINMUX_SDMMC3_CLK_INDEX, |
| 102 | PINMUX_SDMMC3_CLK_FUNC_SDMMC3 | pin_none); |
| 103 | pinmux_set_config(PINMUX_SDMMC3_CMD_INDEX, |
| 104 | PINMUX_SDMMC3_CMD_FUNC_SDMMC3 | pin_up); |
| 105 | pinmux_set_config(PINMUX_SDMMC3_DAT0_INDEX, |
| 106 | PINMUX_SDMMC3_DAT0_FUNC_SDMMC3 | pin_up); |
| 107 | pinmux_set_config(PINMUX_SDMMC3_DAT1_INDEX, |
| 108 | PINMUX_SDMMC3_DAT1_FUNC_SDMMC3 | pin_up); |
| 109 | pinmux_set_config(PINMUX_SDMMC3_DAT2_INDEX, |
| 110 | PINMUX_SDMMC3_DAT2_FUNC_SDMMC3 | pin_up); |
| 111 | pinmux_set_config(PINMUX_SDMMC3_DAT3_INDEX, |
| 112 | PINMUX_SDMMC3_DAT3_FUNC_SDMMC3 | pin_up); |
| 113 | pinmux_set_config(PINMUX_SDMMC3_CLK_LB_IN_INDEX, |
Ken Chang | 41359bd | 2014-04-21 17:54:28 +0800 | [diff] [blame] | 114 | PINMUX_SDMMC3_CLK_LB_IN_FUNC_SDMMC3 | pin_up); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 115 | pinmux_set_config(PINMUX_SDMMC3_CLK_LB_OUT_INDEX, |
| 116 | PINMUX_SDMMC3_CLK_LB_OUT_FUNC_SDMMC3 | pin_down); |
| 117 | |
| 118 | // MMC3 Card Detect pin. |
| 119 | gpio_input_pullup(GPIO(V2)); |
Hung-Te Lin | 6a16f69 | 2014-04-24 21:07:05 +0800 | [diff] [blame] | 120 | // Disable SD card reader power so it can be reset even on warm boot. |
| 121 | // Payloads must enable power before accessing SD card slots. |
| 122 | gpio_output(GPIO(R0), 0); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 123 | |
Hung-Te Lin | 6a16f69 | 2014-04-24 21:07:05 +0800 | [diff] [blame] | 124 | // MMC4 (eMMC) |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 125 | pinmux_set_config(PINMUX_SDMMC4_CLK_INDEX, |
| 126 | PINMUX_SDMMC4_CLK_FUNC_SDMMC4 | pin_none); |
| 127 | pinmux_set_config(PINMUX_SDMMC4_CMD_INDEX, |
| 128 | PINMUX_SDMMC4_CMD_FUNC_SDMMC4 | pin_up); |
| 129 | pinmux_set_config(PINMUX_SDMMC4_DAT0_INDEX, |
| 130 | PINMUX_SDMMC4_DAT0_FUNC_SDMMC4 | pin_up); |
| 131 | pinmux_set_config(PINMUX_SDMMC4_DAT1_INDEX, |
| 132 | PINMUX_SDMMC4_DAT1_FUNC_SDMMC4 | pin_up); |
| 133 | pinmux_set_config(PINMUX_SDMMC4_DAT2_INDEX, |
| 134 | PINMUX_SDMMC4_DAT2_FUNC_SDMMC4 | pin_up); |
| 135 | pinmux_set_config(PINMUX_SDMMC4_DAT3_INDEX, |
| 136 | PINMUX_SDMMC4_DAT3_FUNC_SDMMC4 | pin_up); |
| 137 | pinmux_set_config(PINMUX_SDMMC4_DAT4_INDEX, |
| 138 | PINMUX_SDMMC4_DAT4_FUNC_SDMMC4 | pin_up); |
| 139 | pinmux_set_config(PINMUX_SDMMC4_DAT5_INDEX, |
| 140 | PINMUX_SDMMC4_DAT5_FUNC_SDMMC4 | pin_up); |
| 141 | pinmux_set_config(PINMUX_SDMMC4_DAT6_INDEX, |
| 142 | PINMUX_SDMMC4_DAT6_FUNC_SDMMC4 | pin_up); |
| 143 | pinmux_set_config(PINMUX_SDMMC4_DAT7_INDEX, |
| 144 | PINMUX_SDMMC4_DAT7_FUNC_SDMMC4 | pin_up); |
| 145 | |
| 146 | /* We pull the USB VBUS signals up but keep them as inputs since the |
| 147 | * voltage source likes to drive them low on overcurrent conditions */ |
| 148 | gpio_input_pullup(GPIO(N4)); /* USB VBUS EN0 */ |
| 149 | gpio_input_pullup(GPIO(N5)); /* USB VBUS EN1 */ |
| 150 | |
| 151 | /* Clock output 1 (for external peripheral) */ |
| 152 | pinmux_set_config(PINMUX_DAP_MCLK1_INDEX, |
| 153 | PINMUX_DAP_MCLK1_FUNC_EXTPERIPH1 | PINMUX_PULL_NONE); |
| 154 | |
| 155 | /* I2S1 */ |
| 156 | pinmux_set_config(PINMUX_DAP2_DIN_INDEX, |
Ken Chang | 41359bd | 2014-04-21 17:54:28 +0800 | [diff] [blame] | 157 | PINMUX_DAP2_DIN_FUNC_I2S1 | PINMUX_INPUT_ENABLE); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 158 | pinmux_set_config(PINMUX_DAP2_DOUT_INDEX, |
| 159 | PINMUX_DAP2_DOUT_FUNC_I2S1 | PINMUX_INPUT_ENABLE); |
| 160 | pinmux_set_config(PINMUX_DAP2_FS_INDEX, |
| 161 | PINMUX_DAP2_FS_FUNC_I2S1 | PINMUX_INPUT_ENABLE); |
| 162 | pinmux_set_config(PINMUX_DAP2_SCLK_INDEX, |
| 163 | PINMUX_DAP2_SCLK_FUNC_I2S1 | PINMUX_INPUT_ENABLE); |
Gabe Black | 372a5bbd | 2014-02-14 22:25:01 -0800 | [diff] [blame] | 164 | |
| 165 | /* PWM1 */ |
| 166 | pinmux_set_config(PINMUX_GPIO_PH1_INDEX, |
| 167 | PINMUX_GPIO_PH1_FUNC_PWM1 | PINMUX_PULL_NONE); |
Ken Chang | 41359bd | 2014-04-21 17:54:28 +0800 | [diff] [blame] | 168 | |
| 169 | /* DP HPD */ |
| 170 | pinmux_set_config(PINMUX_DP_HPD_INDEX, |
| 171 | PINMUX_DP_HPD_FUNC_DP | PINMUX_INPUT_ENABLE); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | static void setup_kernel_info(void) |
| 175 | { |
| 176 | // Setup required information for Linux kernel. |
| 177 | |
| 178 | // pmc.odmdata: [18:19]: console type, [15:17]: UART id. |
| 179 | // TODO(hungte) This should be done by filling BCT values, or derived |
| 180 | // from CONFIG_CONSOLE_SERIAL_UART[A-E]. Right now we simply copy the |
| 181 | // value defined in BCT. |
| 182 | struct tegra_pmc_regs *pmc = (void*)TEGRA_PMC_BASE; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 183 | write32(&pmc->odmdata, 0x80080000); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 184 | |
| 185 | // Not strictly info, but kernel graphics driver needs this region locked down |
| 186 | struct tegra_mc_regs *mc = (void *)TEGRA_MC_BASE; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 187 | write32(&mc->video_protect_bom, 0); |
| 188 | write32(&mc->video_protect_size_mb, 0); |
| 189 | write32(&mc->video_protect_reg_ctrl, 1); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 190 | } |
| 191 | |
| 192 | static void setup_ec_spi(void) |
| 193 | { |
Gabe Black | 967058f | 2014-03-21 21:32:12 -0700 | [diff] [blame] | 194 | tegra_spi_init(CONFIG_EC_GOOGLE_CHROMEEC_SPI_BUS); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 195 | } |
| 196 | |
| 197 | static void mainboard_init(device_t dev) |
| 198 | { |
| 199 | set_clock_sources(); |
| 200 | |
| 201 | clock_external_output(1); /* For external MAX98090 audio codec. */ |
| 202 | |
| 203 | /* |
| 204 | * Confirmed by NVIDIA hardware team, we need to take ALL audio devices |
| 205 | * conntected to AHUB (AUDIO, APBIF, I2S, DAM, AMX, ADX, SPDIF, AFC) out |
| 206 | * of reset and clock-enabled, otherwise reading AHUB devices (In our |
| 207 | * case, I2S/APBIF/AUDIO<XBAR>) will hang. |
| 208 | */ |
| 209 | clock_enable_clear_reset(CLK_L_GPIO | CLK_L_I2C1 | CLK_L_SDMMC4 | |
| 210 | CLK_L_I2S0 | CLK_L_I2S1 | CLK_L_I2S2 | |
| 211 | CLK_L_SPDIF | CLK_L_USBD | CLK_L_DISP1 | |
Gabe Black | 372a5bbd | 2014-02-14 22:25:01 -0800 | [diff] [blame] | 212 | CLK_L_HOST1X | CLK_L_PWM, |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 213 | |
Gabe Black | 4a12cfe | 2014-03-24 21:24:24 -0700 | [diff] [blame] | 214 | CLK_H_EMC | CLK_H_I2C2 | CLK_H_PMC | |
| 215 | CLK_H_MEM | CLK_H_USB3, |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 216 | |
Gabe Black | 4a12cfe | 2014-03-24 21:24:24 -0700 | [diff] [blame] | 217 | CLK_U_CSITE | CLK_U_SDMMC3, |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 218 | |
| 219 | CLK_V_I2C4 | CLK_V_EXTPERIPH1 | CLK_V_APBIF | |
| 220 | CLK_V_AUDIO | CLK_V_I2S3 | CLK_V_I2S4 | |
| 221 | CLK_V_DAM0 | CLK_V_DAM1 | CLK_V_DAM2, |
| 222 | |
| 223 | CLK_W_DVFS | CLK_W_AMX0 | CLK_W_ADX0, |
| 224 | |
| 225 | CLK_X_DPAUX | CLK_X_SOR0 | CLK_X_AMX1 | |
| 226 | CLK_X_ADX1 | CLK_X_AFC0 | CLK_X_AFC1 | |
| 227 | CLK_X_AFC2 | CLK_X_AFC3 | CLK_X_AFC4 | |
| 228 | CLK_X_AFC5); |
| 229 | |
Furquan Shaikh | 2296774 | 2014-08-06 09:53:55 -0700 | [diff] [blame] | 230 | usb_setup_utmip((void*)TEGRA_USBD_BASE); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 231 | /* USB2 is the camera, we don't need it in firmware */ |
Furquan Shaikh | 2296774 | 2014-08-06 09:53:55 -0700 | [diff] [blame] | 232 | usb_setup_utmip((void*)TEGRA_USB3_BASE); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 233 | |
| 234 | setup_pinmux(); |
| 235 | |
| 236 | i2c_init(0); |
| 237 | i2c_init(1); |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 238 | i2c_init(3); |
| 239 | |
| 240 | setup_kernel_info(); |
| 241 | clock_init_arm_generic_timer(); |
| 242 | setup_ec_spi(); |
David Hendricks | f6e17c0 | 2014-03-20 18:43:45 -0700 | [diff] [blame] | 243 | #if CONFIG_ELOG |
| 244 | elog_init(); |
David Hendricks | d72d8aa | 2014-05-13 20:32:14 -0700 | [diff] [blame] | 245 | elog_add_boot_reason(); |
David Hendricks | f6e17c0 | 2014-03-20 18:43:45 -0700 | [diff] [blame] | 246 | #endif |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 247 | } |
| 248 | |
| 249 | static void mainboard_enable(device_t dev) |
| 250 | { |
| 251 | dev->ops->init = &mainboard_init; |
| 252 | } |
| 253 | |
| 254 | struct chip_operations mainboard_ops = { |
| 255 | .name = "nyan_big", |
| 256 | .enable_dev = mainboard_enable, |
| 257 | }; |
| 258 | |
| 259 | void lb_board(struct lb_header *header) |
| 260 | { |
| 261 | struct lb_range *dma; |
| 262 | |
| 263 | dma = (struct lb_range *)lb_new_record(header); |
| 264 | dma->tag = LB_TAB_DMA; |
| 265 | dma->size = sizeof(*dma); |
Julius Werner | ec5e5e0 | 2014-08-20 15:29:56 -0700 | [diff] [blame] | 266 | dma->range_start = (uintptr_t)_dma_coherent; |
| 267 | dma->range_size = _dma_coherent_size; |
Gabe Black | 5c8d3d2 | 2014-01-17 22:11:35 -0800 | [diff] [blame] | 268 | } |