Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2014 Imagination Technologies |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License as |
| 8 | * published by the Free Software Foundation; version 2 of |
| 9 | * the License. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 15 | */ |
| 16 | |
| 17 | #include <arch/io.h> |
| 18 | #include <stdint.h> |
| 19 | #include <soc/clocks.h> |
Ionela Voinescu | 256b1c3 | 2015-01-30 17:05:15 +0000 | [diff] [blame] | 20 | #include <assert.h> |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 21 | #include <boardid.h> |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 22 | |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 23 | #define PADS_FUNCTION_SELECT0_ADDR (0xB8101C00 + 0xC0) |
| 24 | |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 25 | #define GPIO_BIT_EN_ADDR(bank) (0xB8101C00 + 0x200 + (0x24 * (bank))) |
Ionela Voinescu | 256b1c3 | 2015-01-30 17:05:15 +0000 | [diff] [blame] | 26 | #define PAD_DRIVE_STRENGTH_ADDR(bank) (0xB8101C00 + 0x120 + (0x4 * (bank))) |
| 27 | #define MAX_NO_MFIOS 89 |
| 28 | #define PAD_DRIVE_STRENGTH_LENGTH 2 |
| 29 | #define PAD_DRIVE_STRENGTH_MASK 0x3 |
| 30 | |
| 31 | typedef enum { |
| 32 | DRIVE_STRENGTH_2mA = 0, |
| 33 | DRIVE_STRENGTH_4mA = 1, |
| 34 | DRIVE_STRENGTH_8mA = 2, |
| 35 | DRIVE_STRENGTH_12mA = 3 |
| 36 | } drive_strength; |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 37 | |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 38 | /* MFIO definitions for UART1 */ |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 39 | #define UART1_RXD_MFIO 59 |
| 40 | #define UART1_TXD_MFIO 60 |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 41 | |
| 42 | /* MFIO definitions for SPIM */ |
| 43 | #define SPIM1_D0_TXD_MFIO 5 |
| 44 | #define SPIM1_D1_RXD_MFIO 4 |
| 45 | #define SPIM1_MCLK_MFIO 3 |
| 46 | #define SPIM1_D2_MFIO 6 |
| 47 | #define SPIM1_D3_MFIO 7 |
| 48 | #define SPIM1_CS0_MFIO 0 |
| 49 | |
Ionela Voinescu | d99e082 | 2015-03-05 14:13:54 +0000 | [diff] [blame] | 50 | /* MFIO definitions for I2C */ |
| 51 | #define I2C_DATA_MFIO(i) (28 + (2*(i))) |
| 52 | #define I2C_CLK_MFIO(i) (29 + (2*(i))) |
| 53 | #define I2C_DATA_FUNCTION_OFFSET(i) (20 + (2*(i))) |
| 54 | #define I2C_CLK_FUNCTION_OFFSET(i) (21 + (2*(i))) |
| 55 | #define I2C_DATA_FUNCTION_MASK 0x1 |
| 56 | #define I2C_CLK_FUNCTION_MASK 0x1 |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 57 | |
Ionela Voinescu | 256b1c3 | 2015-01-30 17:05:15 +0000 | [diff] [blame] | 58 | static void pad_drive_strength(u32 pad, drive_strength strength) |
| 59 | { |
| 60 | u32 reg, drive_strength_shift; |
| 61 | |
| 62 | assert(pad <= MAX_NO_MFIOS); |
| 63 | assert(!(strength & ~(PAD_DRIVE_STRENGTH_MASK))); |
| 64 | |
| 65 | /* Set drive strength value */ |
| 66 | drive_strength_shift = (pad % 16) * PAD_DRIVE_STRENGTH_LENGTH; |
| 67 | reg = read32(PAD_DRIVE_STRENGTH_ADDR(pad / 16)); |
| 68 | reg &= ~(PAD_DRIVE_STRENGTH_MASK << drive_strength_shift); |
| 69 | reg |= strength << drive_strength_shift; |
| 70 | write32(PAD_DRIVE_STRENGTH_ADDR(pad / 16), reg); |
| 71 | } |
| 72 | |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 73 | static void uart1_mfio_setup(void) |
| 74 | { |
| 75 | u32 reg, mfio_mask; |
| 76 | |
| 77 | /* |
| 78 | * Disable GPIO for UART1 MFIOs |
| 79 | * All UART MFIOs have MFIO/16 = 3, therefore we use GPIO pad 3 |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 80 | * This is the only function (0) of these MFIOs and therfore there |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 81 | * is no need to set up a function number in the corresponding |
| 82 | * function select register. |
| 83 | */ |
| 84 | reg = read32(GPIO_BIT_EN_ADDR(3)); |
| 85 | mfio_mask = 1 << (UART1_RXD_MFIO % 16); |
| 86 | mfio_mask |= 1 << (UART1_TXD_MFIO % 16); |
| 87 | /* Clear relevant bits */ |
| 88 | reg &= ~mfio_mask; |
| 89 | /* |
| 90 | * Set corresponding bits in the upper half word |
| 91 | * in order to be able to modify the chosen pins |
| 92 | */ |
| 93 | reg |= mfio_mask << 16; |
| 94 | write32(GPIO_BIT_EN_ADDR(3), reg); |
| 95 | } |
| 96 | |
| 97 | static void spim1_mfio_setup(void) |
| 98 | { |
| 99 | u32 reg, mfio_mask; |
| 100 | /* |
| 101 | * Disable GPIO for SPIM1 MFIOs |
| 102 | * All SPFI1 MFIOs have MFIO/16 = 0, therefore we use GPIO pad 0 |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 103 | * This is the only function (0) of these MFIOs and therfore there |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 104 | * is no need to set up a function number in the corresponding |
| 105 | * function select register. |
| 106 | */ |
| 107 | reg = read32(GPIO_BIT_EN_ADDR(0)); |
| 108 | |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 109 | /* Disable GPIO for SPIM1 MFIOs */ |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 110 | mfio_mask = 1 << (SPIM1_D0_TXD_MFIO % 16); |
| 111 | mfio_mask |= 1 << (SPIM1_D1_RXD_MFIO % 16); |
| 112 | mfio_mask |= 1 << (SPIM1_MCLK_MFIO % 16); |
| 113 | mfio_mask |= 1 << (SPIM1_D2_MFIO % 16); |
| 114 | mfio_mask |= 1 << (SPIM1_D3_MFIO % 16); |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 115 | mfio_mask |= 1 << (SPIM1_CS0_MFIO % 16); |
| 116 | |
| 117 | /* Clear relevant bits */ |
| 118 | reg &= ~mfio_mask; |
| 119 | /* |
| 120 | * Set corresponding bits in the upper half word |
| 121 | * in order to be able to modify the chosen pins |
| 122 | */ |
| 123 | reg |= mfio_mask << 16; |
| 124 | write32(GPIO_BIT_EN_ADDR(0), reg); |
Ionela Voinescu | 256b1c3 | 2015-01-30 17:05:15 +0000 | [diff] [blame] | 125 | |
| 126 | /* Set drive strength to maximum for these MFIOs */ |
| 127 | pad_drive_strength(SPIM1_CS0_MFIO, DRIVE_STRENGTH_12mA); |
| 128 | pad_drive_strength(SPIM1_D1_RXD_MFIO, DRIVE_STRENGTH_12mA); |
| 129 | pad_drive_strength(SPIM1_D0_TXD_MFIO, DRIVE_STRENGTH_12mA); |
| 130 | pad_drive_strength(SPIM1_D2_MFIO, DRIVE_STRENGTH_12mA); |
| 131 | pad_drive_strength(SPIM1_D3_MFIO, DRIVE_STRENGTH_12mA); |
| 132 | pad_drive_strength(SPIM1_MCLK_MFIO, DRIVE_STRENGTH_12mA); |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 133 | } |
| 134 | |
Ionela Voinescu | d99e082 | 2015-03-05 14:13:54 +0000 | [diff] [blame] | 135 | static void i2c_mfio_setup(int interface) |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 136 | { |
| 137 | u32 reg, mfio_mask; |
| 138 | |
Ionela Voinescu | d99e082 | 2015-03-05 14:13:54 +0000 | [diff] [blame] | 139 | assert(interface < 4); |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 140 | /* |
Ionela Voinescu | d99e082 | 2015-03-05 14:13:54 +0000 | [diff] [blame] | 141 | * Disable GPIO for I2C MFIOs |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 142 | */ |
Ionela Voinescu | d99e082 | 2015-03-05 14:13:54 +0000 | [diff] [blame] | 143 | reg = read32(GPIO_BIT_EN_ADDR(I2C_DATA_MFIO(interface) / 16)); |
| 144 | mfio_mask = 1 << (I2C_DATA_MFIO(interface) % 16); |
| 145 | mfio_mask |= 1 << (I2C_CLK_MFIO(interface) % 16); |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 146 | /* Clear relevant bits */ |
| 147 | reg &= ~mfio_mask; |
| 148 | /* |
| 149 | * Set corresponding bits in the upper half word |
| 150 | * in order to be able to modify the chosen pins |
| 151 | */ |
| 152 | reg |= mfio_mask << 16; |
Ionela Voinescu | d99e082 | 2015-03-05 14:13:54 +0000 | [diff] [blame] | 153 | write32(GPIO_BIT_EN_ADDR(I2C_DATA_MFIO(interface) / 16), reg); |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 154 | |
Ionela Voinescu | d99e082 | 2015-03-05 14:13:54 +0000 | [diff] [blame] | 155 | /* for I2C0 and I2C1: |
| 156 | * Set bits to 0 (clear) which is the primary function |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 157 | * for these MFIOs; those bits will all be set to 1 by |
Ionela Voinescu | d99e082 | 2015-03-05 14:13:54 +0000 | [diff] [blame] | 158 | * default. |
| 159 | * There is no need to do that for I2C2 and I2C3 |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 160 | */ |
Ionela Voinescu | d99e082 | 2015-03-05 14:13:54 +0000 | [diff] [blame] | 161 | if (interface > 1) |
| 162 | return; |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 163 | reg = read32(PADS_FUNCTION_SELECT0_ADDR); |
Ionela Voinescu | d99e082 | 2015-03-05 14:13:54 +0000 | [diff] [blame] | 164 | reg &= ~(I2C_DATA_FUNCTION_MASK << |
| 165 | I2C_DATA_FUNCTION_OFFSET(interface)); |
| 166 | reg &= ~(I2C_CLK_FUNCTION_MASK << |
| 167 | I2C_CLK_FUNCTION_OFFSET(interface)); |
Ionela Voinescu | 1d9515f | 2015-02-17 18:45:28 +0000 | [diff] [blame] | 168 | write32(PADS_FUNCTION_SELECT0_ADDR, reg); |
| 169 | } |
| 170 | |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 171 | static void bootblock_mainboard_init(void) |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 172 | { |
| 173 | int ret; |
| 174 | |
Ionela Voinescu | 90d1235 | 2015-07-15 12:10:05 +0100 | [diff] [blame] | 175 | /* System PLL divided by 2 -> 350 MHz */ |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 176 | /* The same frequency will be the input frequency for the SPFI block */ |
| 177 | system_clk_setup(1); |
Ionela Voinescu | 8b1f23e | 2015-01-26 13:15:12 +0000 | [diff] [blame] | 178 | |
Ionela Voinescu | 0f58d0b | 2015-02-03 00:26:08 +0000 | [diff] [blame] | 179 | /* MIPS CPU dividers: division by 1 -> 546 MHz |
Ionela Voinescu | 8b1f23e | 2015-01-26 13:15:12 +0000 | [diff] [blame] | 180 | * This is set up as we cannot make any assumption about |
| 181 | * the values set or not by the boot ROM code */ |
| 182 | mips_clk_setup(0, 0); |
| 183 | |
Ionela Voinescu | 90d1235 | 2015-07-15 12:10:05 +0100 | [diff] [blame] | 184 | /* Setup system PLL at 700 MHz */ |
| 185 | ret = sys_pll_setup(2, 1, 13, 350); |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 186 | if (ret != CLOCKS_OK) |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 187 | return; |
| 188 | /* Setup MIPS PLL at 546 MHz */ |
| 189 | ret = mips_pll_setup(2, 1, 1, 21); |
| 190 | if (ret != CLOCKS_OK) |
| 191 | return; |
Ionela Voinescu | 8b1f23e | 2015-01-26 13:15:12 +0000 | [diff] [blame] | 192 | |
Ionela Voinescu | 4f3d400 | 2015-11-01 19:55:48 +0000 | [diff] [blame] | 193 | /* |
| 194 | * Move peripheral clock control from RPU to MIPS. |
| 195 | * The RPU gate register is not managed in Linux so disable its default |
| 196 | * values and assign MIPS gate register the default values. |
| 197 | * *Note*: All unused clocks will be gated by Linux |
| 198 | */ |
| 199 | setup_clk_gate_defaults(); |
| 200 | |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 201 | /* Setup SPIM1 MFIOs */ |
| 202 | spim1_mfio_setup(); |
| 203 | /* Setup UART1 clock and MFIOs |
Ionela Voinescu | 90d1235 | 2015-07-15 12:10:05 +0100 | [diff] [blame] | 204 | * System PLL divided by 5 divided by 76 -> 1.8421 Mhz |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 205 | */ |
Ionela Voinescu | 90d1235 | 2015-07-15 12:10:05 +0100 | [diff] [blame] | 206 | uart1_clk_setup(4, 75); |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 207 | uart1_mfio_setup(); |
| 208 | } |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 209 | |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 210 | |
| 211 | static int init_extra_hardware(void) |
| 212 | { |
| 213 | const struct board_hw *hardware; |
| 214 | |
| 215 | /* Obtain information about current board */ |
| 216 | hardware = board_get_hw(); |
| 217 | if (!hardware) { |
| 218 | printk(BIOS_ERR, "%s: Invalid hardware information.\n", |
| 219 | __func__); |
| 220 | return -1; |
| 221 | } |
| 222 | |
| 223 | /* Setup USB clock |
Ionela Voinescu | 90d1235 | 2015-07-15 12:10:05 +0100 | [diff] [blame] | 224 | * System clock divided by 7 -> 50 MHz |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 225 | */ |
Ionela Voinescu | 90d1235 | 2015-07-15 12:10:05 +0100 | [diff] [blame] | 226 | if (usb_clk_setup(6, 2, 7) != CLOCKS_OK) { |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 227 | printk(BIOS_ERR, "%s: Failed to set up USB clock.\n", |
| 228 | __func__); |
| 229 | return -1; |
| 230 | } |
| 231 | |
| 232 | /* Setup I2C clocks and MFIOs |
Ionela Voinescu | 90d1235 | 2015-07-15 12:10:05 +0100 | [diff] [blame] | 233 | * System clock divided by 4 divided by 3 -> 29.1(6) MHz |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 234 | */ |
| 235 | i2c_clk_setup(3, 2, hardware->i2c_interface); |
| 236 | i2c_mfio_setup(hardware->i2c_interface); |
| 237 | |
Ionela Voinescu | 8b1f23e | 2015-01-26 13:15:12 +0000 | [diff] [blame] | 238 | /* Ethernet clocks setup: ENET as clock source */ |
Ionela Voinescu | 90d1235 | 2015-07-15 12:10:05 +0100 | [diff] [blame] | 239 | eth_clk_setup(0, 6); |
| 240 | /* ROM clock setup: system clock divided by 2 -> 175 MHz */ |
Ionela Voinescu | 8b1f23e | 2015-01-26 13:15:12 +0000 | [diff] [blame] | 241 | /* Hash accelerator is driven from the ROM clock */ |
| 242 | rom_clk_setup(1); |
| 243 | |
Ionela Voinescu | 2fdc61a | 2015-03-09 15:31:38 +0000 | [diff] [blame] | 244 | return 0; |
Ionela Voinescu | b3f666b | 2015-01-18 22:37:11 +0000 | [diff] [blame] | 245 | } |