Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [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. |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 14 | */ |
| 15 | |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 16 | #include <arch/io.h> |
| 17 | #include <cbfs.h> |
Julius Werner | 96195ee | 2014-10-20 13:25:21 -0700 | [diff] [blame] | 18 | #include <console/console.h> |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 19 | #include <soc/addressmap.h> |
Furquan Shaikh | 68a672c | 2014-09-20 15:07:52 -0700 | [diff] [blame] | 20 | #include <soc/clock.h> |
Julius Werner | 96195ee | 2014-10-20 13:25:21 -0700 | [diff] [blame] | 21 | #include <soc/clk_rst.h> |
| 22 | #include <soc/ccplex.h> |
Aaron Durbin | 4058d7b | 2014-08-22 10:24:27 -0500 | [diff] [blame] | 23 | #include <soc/cpu.h> |
Julius Werner | 96195ee | 2014-10-20 13:25:21 -0700 | [diff] [blame] | 24 | #include <soc/flow.h> |
| 25 | #include <soc/mc.h> |
| 26 | #include <soc/pmc.h> |
| 27 | #include <soc/power.h> |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 28 | #include <soc/romstage.h> |
Julius Werner | 96195ee | 2014-10-20 13:25:21 -0700 | [diff] [blame] | 29 | #include <string.h> |
| 30 | #include <timer.h> |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 31 | |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 32 | #define PMC_REGS (void *)(uintptr_t)(TEGRA_PMC_BASE) |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 33 | #define MTS_FILE_NAME "mts" |
| 34 | |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 35 | static int ccplex_start(void) |
| 36 | { |
Aaron Durbin | b9894ef | 2014-09-23 16:33:21 -0500 | [diff] [blame] | 37 | struct stopwatch sw; |
| 38 | const long timeout_ms = 1500; |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 39 | const uint32_t handshake_mask = 1; |
| 40 | const uint32_t cxreset1_mask = 1 << 21; |
| 41 | uint32_t reg; |
| 42 | struct tegra_pmc_regs * const pmc = PMC_REGS; |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 43 | |
| 44 | /* Set the handshake bit to be knocked down. */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 45 | write32(&pmc->scratch118, handshake_mask); |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 46 | |
| 47 | /* Assert nCXRSET[1] */ |
Furquan Shaikh | ba16725 | 2014-09-22 14:58:05 -0700 | [diff] [blame] | 48 | reg = read32(CLK_RST_REG(rst_cpu_cmplx_set)); |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 49 | reg |= cxreset1_mask; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 50 | write32(CLK_RST_REG(rst_cpu_cmplx_set), reg); |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 51 | |
Aaron Durbin | b9894ef | 2014-09-23 16:33:21 -0500 | [diff] [blame] | 52 | stopwatch_init_msecs_expire(&sw, timeout_ms); |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 53 | while (1) { |
| 54 | reg = read32(&pmc->scratch118); |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 55 | |
| 56 | /* Wait for the bit to be knocked down. */ |
| 57 | if ((reg & handshake_mask) != handshake_mask) |
| 58 | break; |
| 59 | |
Aaron Durbin | b9894ef | 2014-09-23 16:33:21 -0500 | [diff] [blame] | 60 | if (stopwatch_expired(&sw)) { |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 61 | printk(BIOS_DEBUG, "MTS handshake timeout.\n"); |
| 62 | return -1; |
| 63 | } |
| 64 | } |
| 65 | |
Aaron Durbin | 4f9150b | 2014-09-24 09:13:14 -0500 | [diff] [blame] | 66 | printk(BIOS_DEBUG, "MTS handshake took %ld usecs.\n", |
Aaron Durbin | b9894ef | 2014-09-23 16:33:21 -0500 | [diff] [blame] | 67 | stopwatch_duration_usecs(&sw)); |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 68 | |
| 69 | return 0; |
| 70 | } |
| 71 | |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 72 | int ccplex_load_mts(void) |
| 73 | { |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 74 | ssize_t nread; |
Aaron Durbin | 4f9150b | 2014-09-24 09:13:14 -0500 | [diff] [blame] | 75 | struct stopwatch sw; |
Aaron Durbin | 37a5d15 | 2015-09-17 16:09:30 -0500 | [diff] [blame] | 76 | struct cbfsf mts_file; |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 77 | struct region_device fh; |
Aaron Durbin | 4f9150b | 2014-09-24 09:13:14 -0500 | [diff] [blame] | 78 | |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 79 | /* |
| 80 | * MTS location is hard coded to this magic address. The hardware will |
| 81 | * take the MTS from this location and place it in the final resting |
| 82 | * place in the carveout region. |
| 83 | */ |
| 84 | void * const mts = (void *)(uintptr_t)MTS_LOAD_ADDRESS; |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 85 | |
Aaron Durbin | 4f9150b | 2014-09-24 09:13:14 -0500 | [diff] [blame] | 86 | stopwatch_init(&sw); |
Aaron Durbin | 37a5d15 | 2015-09-17 16:09:30 -0500 | [diff] [blame] | 87 | if (cbfs_boot_locate(&mts_file, MTS_FILE_NAME, NULL)) { |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 88 | printk(BIOS_DEBUG, "MTS file not found: %s\n", MTS_FILE_NAME); |
| 89 | return -1; |
| 90 | } |
| 91 | |
Aaron Durbin | 37a5d15 | 2015-09-17 16:09:30 -0500 | [diff] [blame] | 92 | cbfs_file_data(&fh, &mts_file); |
| 93 | |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 94 | /* Read MTS file into the carveout region. */ |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 95 | nread = rdev_readat(&fh, mts, 0, region_device_sz(&fh)); |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 96 | |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 97 | if (nread != region_device_sz(&fh)) { |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 98 | printk(BIOS_DEBUG, "MTS bytes read (%zu) != file length(%u)!\n", |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 99 | nread, region_device_sz(&fh)); |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 100 | return -1; |
| 101 | } |
| 102 | |
Aaron Durbin | 4f9150b | 2014-09-24 09:13:14 -0500 | [diff] [blame] | 103 | printk(BIOS_DEBUG, "MTS: %zu bytes loaded @ %p in %ld usecs.\n", |
| 104 | nread, mts, stopwatch_duration_usecs(&sw)); |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 105 | |
Aaron Durbin | d2907c1 | 2014-07-01 13:51:21 -0500 | [diff] [blame] | 106 | return ccplex_start(); |
Aaron Durbin | 3aca2cd | 2014-06-30 16:37:13 -0500 | [diff] [blame] | 107 | } |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 108 | |
| 109 | static void enable_cpu_clocks(void) |
| 110 | { |
Furquan Shaikh | 68a672c | 2014-09-20 15:07:52 -0700 | [diff] [blame] | 111 | clock_enable(CLK_ENB_CPU, 0, 0, SET_CLK_ENB_CPUG_ENABLE | |
| 112 | SET_CLK_ENB_CPULP_ENABLE, 0, 0); |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | static void enable_cpu_power_partitions(void) |
| 116 | { |
| 117 | /* Bring up fast cluster, non-CPU, CPU0, and CPU1 partitions. */ |
| 118 | power_ungate_partition(POWER_PARTID_CRAIL); |
| 119 | power_ungate_partition(POWER_PARTID_C0NC); |
| 120 | power_ungate_partition(POWER_PARTID_CE0); |
| 121 | power_ungate_partition(POWER_PARTID_CE1); |
| 122 | } |
| 123 | |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 124 | static void request_ram_repair(void) |
| 125 | { |
| 126 | struct flow_ctlr * const flow = (void *)(uintptr_t)TEGRA_FLOW_BASE; |
| 127 | const uint32_t req = 1 << 0; |
| 128 | const uint32_t sts = 1 << 1; |
| 129 | uint32_t reg; |
Aaron Durbin | b9894ef | 2014-09-23 16:33:21 -0500 | [diff] [blame] | 130 | struct stopwatch sw; |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 131 | |
| 132 | printk(BIOS_DEBUG, "Requesting RAM repair.\n"); |
| 133 | |
Yen Lin | 9b99d7b | 2015-01-07 17:04:15 -0800 | [diff] [blame] | 134 | stopwatch_init(&sw); |
| 135 | |
| 136 | /* Perform cluster 0 ram repair */ |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 137 | reg = read32(&flow->ram_repair); |
| 138 | reg |= req; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 139 | write32(&flow->ram_repair, reg); |
Aaron Durbin | b9894ef | 2014-09-23 16:33:21 -0500 | [diff] [blame] | 140 | while ((read32(&flow->ram_repair) & sts) != sts) |
| 141 | ; |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 142 | |
Yen Lin | 9b99d7b | 2015-01-07 17:04:15 -0800 | [diff] [blame] | 143 | /* Perform cluster 1 ram repair */ |
| 144 | reg = read32(&flow->ram_repair_cluster1); |
| 145 | reg |= req; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 146 | write32(&flow->ram_repair_cluster1, reg); |
Yen Lin | 9b99d7b | 2015-01-07 17:04:15 -0800 | [diff] [blame] | 147 | while ((read32(&flow->ram_repair_cluster1) & sts) != sts) |
| 148 | ; |
| 149 | |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 150 | printk(BIOS_DEBUG, "RAM repair complete in %ld usecs.\n", |
Aaron Durbin | b9894ef | 2014-09-23 16:33:21 -0500 | [diff] [blame] | 151 | stopwatch_duration_usecs(&sw)); |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | void ccplex_cpu_prepare(void) |
| 155 | { |
| 156 | enable_cpu_clocks(); |
| 157 | enable_cpu_power_partitions(); |
| 158 | |
| 159 | mainboard_configure_pmc(); |
| 160 | mainboard_enable_vdd_cpu(); |
| 161 | |
| 162 | request_ram_repair(); |
| 163 | } |
| 164 | |
Aaron Durbin | 4058d7b | 2014-08-22 10:24:27 -0500 | [diff] [blame] | 165 | static void start_common_clocks(void) |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 166 | { |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 167 | /* Clear fast CPU partition reset. */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 168 | write32(CLK_RST_REG(rst_cpug_cmplx_clr), CRC_RST_CPUG_CLR_NONCPU); |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 169 | |
Aaron Durbin | 4058d7b | 2014-08-22 10:24:27 -0500 | [diff] [blame] | 170 | /* Clear reset of L2 and CoreSight components. */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 171 | write32(CLK_RST_REG(rst_cpug_cmplx_clr), |
| 172 | CRC_RST_CPUG_CLR_L2 | CRC_RST_CPUG_CLR_PDBG); |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 173 | } |
| 174 | |
| 175 | void ccplex_cpu_start(void *entry_addr) |
| 176 | { |
Aaron Durbin | 4058d7b | 2014-08-22 10:24:27 -0500 | [diff] [blame] | 177 | /* Enable common clocks for the shared resources between the cores. */ |
| 178 | start_common_clocks(); |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 179 | |
Aaron Durbin | 4058d7b | 2014-08-22 10:24:27 -0500 | [diff] [blame] | 180 | start_cpu(0, entry_addr); |
Aaron Durbin | 5626d8f | 2014-07-10 12:50:27 -0500 | [diff] [blame] | 181 | } |