1 /* $NetBSD: exynos_soc.c,v 1.14 2014/06/11 05:54:54 matt Exp $ */ 2 /*- 3 * Copyright (c) 2014 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Reinoud Zandijk. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "opt_exynos.h" 32 33 #define _ARM32_BUS_DMA_PRIVATE 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(1, "$NetBSD: exynos_soc.c,v 1.14 2014/06/11 05:54:54 matt Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/bus.h> 40 #include <sys/cpu.h> 41 #include <sys/device.h> 42 43 #include <prop/proplib.h> 44 45 #include <net/if.h> 46 #include <net/if_ether.h> 47 48 #include <arm/locore.h> 49 50 #include <arm/mainbus/mainbus.h> 51 #include <arm/cortex/mpcore_var.h> 52 53 #include <arm/samsung/exynos_reg.h> 54 #include <arm/samsung/exynos_var.h> 55 #include <arm/samsung/mct_reg.h> 56 #include <arm/samsung/smc.h> 57 58 #include <arm/cortex/pl310_var.h> 59 #include <arm/cortex/pl310_reg.h> 60 61 /* XXXNH */ 62 #include <evbarm/odroid/platform.h> 63 64 bus_space_handle_t exynos_core_bsh; 65 bus_space_handle_t exynos_audiocore_bsh; 66 67 /* these variables are retrieved in start.S and stored in .data */ 68 uint32_t exynos_soc_id = 0; 69 uint32_t exynos_pop_id = 0; 70 71 72 /* 73 * the early serial console 74 */ 75 #ifdef EXYNOS_CONSOLE_EARLY 76 77 #include "opt_sscom.h" 78 #include <arm/samsung/sscom_reg.h> 79 #include <arm/samsung/sscom_var.h> 80 #include <dev/cons.h> 81 82 static volatile uint8_t *uart_base; 83 84 #define CON_REG(a) (*((volatile uint32_t *)(uart_base + (a)))) 85 86 static int 87 exynos_cngetc(dev_t dv) 88 { 89 if ((CON_REG(SSCOM_UTRSTAT) & UTRSTAT_RXREADY) == 0) 90 return -1; 91 92 return CON_REG(SSCOM_URXH); 93 } 94 95 static void 96 exynos_cnputc(dev_t dv, int c) 97 { 98 int timo = 150000; 99 100 while ((CON_REG(SSCOM_UFSTAT) & UFSTAT_TXFULL) && --timo > 0); 101 102 CON_REG(SSCOM_UTXH) = c & 0xff; 103 } 104 105 static struct consdev exynos_earlycons = { 106 .cn_putc = exynos_cnputc, 107 .cn_getc = exynos_cngetc, 108 .cn_pollc = nullcnpollc, 109 }; 110 #endif /* EXYNOS_CONSOLE_EARLY */ 111 112 113 #ifdef ARM_TRUSTZONE_FIRMWARE 114 int 115 exynos_do_idle(void) 116 { 117 exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); 118 119 return 0; 120 } 121 122 123 int 124 exynos_set_cpu_boot_addr(int cpu, vaddr_t boot_addr) 125 { 126 /* XXX we need to map in iRAM space for this XXX */ 127 return 0; 128 } 129 130 131 int 132 exynos_cpu_boot(int cpu) 133 { 134 exynos_smc(SMC_CMD_CPU1BOOT, cpu, 0, 0); 135 136 return 0; 137 } 138 139 140 /* 141 * The latency values used below are `magic' and probably chosen empiricaly. 142 * For the 4210 variant the data latency is lower, a 0x110. This is currently 143 * not enforced. 144 * 145 * The prefetch values are also different for the revision 0 of the 146 * Exynos4412, but why? 147 */ 148 149 int 150 exynos_l2cc_init(void) 151 { 152 const uint32_t tag_latency = 0x110; 153 const uint32_t data_latency = IS_EXYNOS4410_P() ? 0x110 : 0x120; 154 const uint32_t prefetch4412 = /* 0111 0001 0000 0000 0000 0000 0000 0111 */ 155 PREFETCHCTL_DBLLINEF_EN | 156 PREFETCHCTL_INSTRPREF_EN | 157 PREFETCHCTL_DATAPREF_EN | 158 PREFETCHCTL_PREF_DROP_EN | 159 PREFETCHCTL_PREFETCH_OFFSET_7; 160 const uint32_t prefetch4412_r0 = /* 0011 0000 0000 0000 0000 0000 0000 0111 */ 161 PREFETCHCTL_INSTRPREF_EN | 162 PREFETCHCTL_DATAPREF_EN | 163 PREFETCHCTL_PREFETCH_OFFSET_7; 164 const uint32_t aux_val = /* 0111 1100 0100 0111 0000 0000 0000 0001 */ 165 AUXCTL_EARLY_BRESP_EN | 166 AUXCTL_I_PREFETCH | 167 AUXCTL_D_PREFETCH | 168 AUXCTL_NS_INT_ACC_CTL | 169 AUXCTL_NS_INT_LOCK_EN | 170 AUXCTL_SHARED_ATT_OVR | 171 AUXCTL_WAY_SIZE_RSVD7 << 16 | /* why rsvd7 ??? */ 172 AUXCTL_FULL_LINE_WR0; 173 const uint32_t aux_keepmask = /* 1100 0010 0000 0000 1111 1111 1111 1111 */ 174 AUXCTL_RSVD31 | 175 AUXCTL_EARLY_BRESP_EN | 176 AUXCTL_CACHE_REPL_RR | 177 178 AUXCTL_SH_ATTR_INV_ENA| 179 AUXCTL_EXCL_CACHE_CFG | 180 AUXCTL_ST_BUF_DEV_LIM_EN | 181 AUXCTL_HIPRO_SO_DEV_EN | 182 AUXCTL_FULL_LINE_WR0 | 183 0xffff; 184 uint32_t prefetch; 185 186 /* check the bitmaps are the same as the linux implementation uses */ 187 KASSERT(prefetch4412 == 0x71000007); 188 KASSERT(prefetch4412_r0 == 0x30000007); 189 KASSERT(aux_val == 0x7C470001); 190 KASSERT(aux_keepmask == 0xC200FFFF); 191 192 if (IS_EXYNOS4412_R0_P()) 193 prefetch = prefetch4412_r0; 194 else 195 prefetch = prefetch4412; /* newer than >= r1_0 */ 196 ; 197 198 exynos_smc(SMC_CMD_L2X0SETUP1, tag_latency, data_latency, prefetch); 199 exynos_smc(SMC_CMD_L2X0SETUP2, 200 POWERCTL_DYNCLKGATE | POWERCTL_STANDBY, 201 aux_val, aux_keepmask); 202 exynos_smc(SMC_CMD_L2X0INVALL, 0, 0, 0); 203 exynos_smc(SMC_CMD_L2X0CTRL, 1, 0, 0); 204 205 return 0; 206 } 207 #endif /* ARM_TRUSTZONE_FIRMWARE */ 208 209 210 void 211 exynos_bootstrap(vaddr_t iobase, vaddr_t uartbase) 212 { 213 int error; 214 size_t core_size, audiocore_size; 215 size_t audiocore_pbase, audiocore_vbase; 216 217 #ifdef EXYNOS4 218 if (IS_EXYNOS4_P()) { 219 core_size = EXYNOS4_CORE_SIZE; 220 audiocore_size = EXYNOS4_AUDIOCORE_SIZE; 221 audiocore_pbase = EXYNOS4_AUDIOCORE_PBASE; 222 audiocore_vbase = EXYNOS4_AUDIOCORE_VBASE; 223 } 224 #endif 225 226 #ifdef EXYNOS5 227 if (IS_EXYNOS5_P()) { 228 core_size = EXYNOS5_CORE_SIZE; 229 audiocore_size = EXYNOS5_AUDIOCORE_SIZE; 230 audiocore_pbase = EXYNOS5_AUDIOCORE_PBASE; 231 audiocore_vbase = EXYNOS5_AUDIOCORE_VBASE; 232 } 233 #endif 234 235 /* set up early console so we can use printf() and friends */ 236 #ifdef EXYNOS_CONSOLE_EARLY 237 uart_base = (volatile uint8_t *) uartbase; 238 cn_tab = &exynos_earlycons; 239 printf("Exynos early console operational\n\n"); 240 #endif 241 /* map in the exynos io registers */ 242 error = bus_space_map(&exynos_bs_tag, EXYNOS_CORE_PBASE, 243 core_size, 0, &exynos_core_bsh); 244 if (error) 245 panic("%s: failed to map in Exynos SFR registers: %d", 246 __func__, error); 247 KASSERT(exynos_core_bsh == iobase); 248 249 error = bus_space_map(&exynos_bs_tag, audiocore_pbase, 250 audiocore_size, 0, &exynos_audiocore_bsh); 251 if (error) 252 panic("%s: failed to map in Exynos audio SFR registers: %d", 253 __func__, error); 254 KASSERT(exynos_audiocore_bsh == audiocore_vbase); 255 256 /* init bus dma tags */ 257 exynos_dma_bootstrap(physmem * PAGE_SIZE); 258 259 /* gpio bootstrapping delayed */ 260 } 261 262 263 void 264 exynos_device_register(device_t self, void *aux) 265 { 266 if (device_is_a(self, "armperiph") 267 && device_is_a(device_parent(self), "mainbus")) { 268 /* 269 * XXX KLUDGE ALERT XXX 270 * The iot mainbus supplies is completely wrong since it scales 271 * addresses by 2. The simpliest remedy is to replace with our 272 * bus space used for the armcore regisers (which armperiph uses). 273 */ 274 struct mainbus_attach_args * const mb = aux; 275 mb->mb_iot = &exynos_bs_tag; 276 return; 277 } 278 if (device_is_a(self, "armgic") 279 && device_is_a(device_parent(self), "armperiph")) { 280 /* 281 * The Exynos4420 armgic is located at a different location! 282 */ 283 284 extern uint32_t exynos_soc_id; 285 286 switch (EXYNOS_PRODUCT_ID(exynos_soc_id)) { 287 #if defined(EXYNOS5) 288 case 0xe5410: 289 /* offsets not changed on matt's request */ 290 #if 0 291 mpcaa->mpcaa_memh = EXYNOS_CORE_VBASE; 292 mpcaa->mpcaa_off1 = EXYNOS5_GIC_IOP_DISTRIBUTOR_OFFSET; 293 mpcaa->mpcaa_off2 = EXYNOS5_GIC_IOP_CONTROLLER_OFFSET; 294 #endif 295 break; 296 #endif 297 #if defined(EXYNOS4) 298 case 0xe4410: 299 case 0xe4412: { 300 struct mpcore_attach_args * const mpcaa = aux; 301 302 mpcaa->mpcaa_memh = EXYNOS_CORE_VBASE; 303 mpcaa->mpcaa_off1 = EXYNOS4_GIC_DISTRIBUTOR_OFFSET; 304 mpcaa->mpcaa_off2 = EXYNOS4_GIC_CNTR_OFFSET; 305 break; 306 } 307 #endif 308 default: 309 panic("%s: unknown SoC product id %#x", __func__, 310 (u_int)EXYNOS_PRODUCT_ID(exynos_soc_id)); 311 } 312 return; 313 } 314 if (device_is_a(self, "armgtmr") || device_is_a(self, "mct")) { 315 #ifdef EXYNOS5 316 /* 317 * The global timer is dependent on the MCT running. 318 */ 319 bus_size_t o = EXYNOS5_MCT_OFFSET + MCT_G_TCON; 320 uint32_t v = bus_space_read_4(&exynos_bs_tag, exynos_core_bsh, 321 o); 322 v |= G_TCON_START; 323 bus_space_write_4(&exynos_bs_tag, exynos_core_bsh, o, v); 324 #endif 325 /* 326 * The frequencies of the timers are the reference 327 * frequency. 328 */ 329 prop_dictionary_set_uint32(device_properties(self), 330 "frequency", EXYNOS_F_IN_FREQ); 331 return; 332 } 333 334 exyo_device_register(self, aux); 335 } 336 337 338 void 339 exynos_device_register_post_config(device_t self, void *aux) 340 { 341 exyo_device_register_post_config(self, aux); 342 } 343 344