Home | History | Annotate | Line # | Download | only in nvidia
soc_tegra124.c revision 1.10
      1 /* $NetBSD: soc_tegra124.c,v 1.10 2015/11/21 22:52:31 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2015 Jared D. McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include "opt_tegra.h"
     30 #include "opt_multiprocessor.h"
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: soc_tegra124.c,v 1.10 2015/11/21 22:52:31 jmcneill Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/bus.h>
     37 #include <sys/cpu.h>
     38 #include <sys/device.h>
     39 
     40 #include <uvm/uvm_extern.h>
     41 
     42 #include <arm/cpufunc.h>
     43 
     44 #include <arm/nvidia/tegra_reg.h>
     45 #include <arm/nvidia/tegra_pmcreg.h>
     46 #include <arm/nvidia/tegra_var.h>
     47 
     48 #define EVP_RESET_VECTOR_0_REG	0x100
     49 
     50 #define FUSE_SKU_INFO_REG	0x010
     51 #define FUSE_CPU_SPEEDO_0_REG	0x014
     52 #define FUSE_CPU_IDDQ_REG	0x018
     53 #define FUSE_FT_REV_REG		0x028
     54 #define FUSE_CPU_SPEEDO_1_REG	0x02c
     55 #define FUSE_CPU_SPEEDO_2_REG	0x030
     56 #define FUSE_SOC_SPEEDO_0_REG	0x034
     57 #define FUSE_SOC_SPEEDO_1_REG	0x038
     58 #define FUSE_SOC_SPEEDO_2_REG	0x03c
     59 #define FUSE_SOC_IDDQ_REG	0x040
     60 #define FUSE_GPU_IDDQ_REG	0x128
     61 
     62 static void	tegra124_speedo_init(void);
     63 static int	tegra124_speedo_init_ids(uint32_t);
     64 static bool	tegra124_speedo_rate_ok(u_int);
     65 
     66 static u_int	tegra124_cpufreq_set_rate(u_int);
     67 static u_int	tegra124_cpufreq_get_rate(void);
     68 static size_t	tegra124_cpufreq_get_available(u_int *, size_t);
     69 
     70 static const struct tegra_cpufreq_func tegra124_cpufreq_func = {
     71 	.set_rate = tegra124_cpufreq_set_rate,
     72 	.get_rate = tegra124_cpufreq_get_rate,
     73 	.get_available = tegra124_cpufreq_get_available,
     74 };
     75 
     76 static struct tegra124_cpufreq_rate {
     77 	u_int rate;
     78 	u_int divm;
     79 	u_int divn;
     80 	u_int divp;
     81 } tegra124_cpufreq_rates[] = {
     82 	{ 2292, 1, 191, 0 },
     83 	{ 2100, 1, 175, 0 },
     84 	{ 1896, 1, 158, 0 },
     85 	{ 1692, 1, 141, 0 },
     86 	{ 1500, 1, 125, 0 },
     87 	{ 1296, 1, 108, 0 },
     88 	{ 1092, 1, 91, 0 },
     89 	{ 900, 1, 75, 0 },
     90 	{ 696, 1, 58, 0 }
     91 };
     92 
     93 static const u_int tegra124_cpufreq_max[] = {
     94 	2014,
     95 	2320,
     96 	2116,
     97 	2524
     98 };
     99 
    100 static struct tegra124_speedo {
    101 	u_int cpu_speedo_id;
    102 	u_int soc_speedo_id;
    103 	u_int gpu_speedo_id;
    104 } tegra124_speedo = {
    105 	.cpu_speedo_id = 0,
    106 	.soc_speedo_id = 0,
    107 	.gpu_speedo_id = 0
    108 };
    109 
    110 void
    111 tegra124_cpuinit(void)
    112 {
    113 	tegra_car_periph_i2c_enable(4, 20400000);
    114 
    115 	/* Set VDD_CPU voltage to 1.4V */
    116 	const u_int target_mv = 1400;
    117 	const u_int sd0_vsel = (target_mv - 600) / 10;
    118 	tegra_i2c_dvc_write(0x40, (sd0_vsel << 8) | 00, 2);
    119 	delay(10000);
    120 
    121 	tegra124_speedo_init();
    122 
    123 	tegra_cpufreq_register(&tegra124_cpufreq_func);
    124 }
    125 
    126 static void
    127 tegra124_speedo_init(void)
    128 {
    129 	uint32_t sku_id;
    130 
    131 	sku_id = tegra_fuse_read(FUSE_SKU_INFO_REG);
    132 	tegra124_speedo_init_ids(sku_id);
    133 }
    134 
    135 static int
    136 tegra124_speedo_init_ids(uint32_t sku_id)
    137 {
    138 	int threshold = 0;
    139 
    140 	switch (sku_id) {
    141 	case 0x00:
    142 	case 0x0f:
    143 	case 0x23:
    144 		break;	/* use default */
    145 	case 0x83:
    146 		tegra124_speedo.cpu_speedo_id = 2;
    147 		break;
    148 	case 0x1f:
    149 	case 0x87:
    150 	case 0x27:
    151 		tegra124_speedo.cpu_speedo_id = 2;
    152 		tegra124_speedo.soc_speedo_id = 0;
    153 		tegra124_speedo.gpu_speedo_id = 1;
    154 		break;
    155 	case 0x81:
    156 	case 0x21:
    157 	case 0x07:
    158 		tegra124_speedo.cpu_speedo_id = 1;
    159 		tegra124_speedo.soc_speedo_id = 1;
    160 		tegra124_speedo.gpu_speedo_id = 1;
    161 		threshold = 1;
    162 		break;
    163 	case 0x49:
    164 	case 0x4a:
    165 	case 0x48:
    166 		tegra124_speedo.cpu_speedo_id = 4;
    167 		tegra124_speedo.soc_speedo_id = 2;
    168 		tegra124_speedo.gpu_speedo_id = 3;
    169 		threshold = 1;
    170 		break;
    171 	default:
    172 		aprint_error("tegra124: unknown SKU ID %#x\n", sku_id);
    173 		break;	/* use default */
    174 	}
    175 
    176 	return threshold;
    177 }
    178 
    179 static bool
    180 tegra124_speedo_rate_ok(u_int rate)
    181 {
    182 	u_int tbl = 0;
    183 
    184 	if (tegra124_speedo.cpu_speedo_id < __arraycount(tegra124_cpufreq_max))
    185 		tbl = tegra124_speedo.cpu_speedo_id;
    186 
    187 	return rate <= tegra124_cpufreq_max[tbl];
    188 }
    189 
    190 
    191 static u_int
    192 tegra124_cpufreq_set_rate(u_int rate)
    193 {
    194 	const u_int nrates = __arraycount(tegra124_cpufreq_rates);
    195 	const struct tegra124_cpufreq_rate *r = NULL;
    196 
    197 	if (tegra124_speedo_rate_ok(rate) == false)
    198 		return EINVAL;
    199 
    200 	for (int i = 0; i < nrates; i++) {
    201 		if (tegra124_cpufreq_rates[i].rate == rate) {
    202 			r = &tegra124_cpufreq_rates[i];
    203 			break;
    204 		}
    205 	}
    206 	if (r == NULL)
    207 		return EINVAL;
    208 
    209 	tegra_car_pllx_set_rate(r->divm, r->divn, r->divp);
    210 
    211 	return 0;
    212 }
    213 
    214 static u_int
    215 tegra124_cpufreq_get_rate(void)
    216 {
    217 	return tegra_car_pllx_rate() / 1000000;
    218 }
    219 
    220 static size_t
    221 tegra124_cpufreq_get_available(u_int *pavail, size_t maxavail)
    222 {
    223 	const u_int nrates = __arraycount(tegra124_cpufreq_rates);
    224 	u_int n, cnt;
    225 
    226 	KASSERT(nrates <= maxavail);
    227 
    228 	for (n = 0, cnt = 0; n < nrates; n++) {
    229 		if (tegra124_speedo_rate_ok(tegra124_cpufreq_rates[n].rate)) {
    230 			pavail[cnt++] = tegra124_cpufreq_rates[n].rate;
    231 		}
    232 	}
    233 
    234 	return cnt;
    235 }
    236 
    237 void
    238 tegra124_mpinit(void)
    239 {
    240 #if defined(MULTIPROCESSOR)
    241 	extern void cortex_mpstart(void);
    242 	bus_space_tag_t bst = &armv7_generic_bs_tag;
    243 	bus_space_handle_t bsh;
    244 
    245 	bus_space_subregion(bst, tegra_ppsb_bsh,
    246 	    TEGRA_EVP_OFFSET, TEGRA_EVP_SIZE, &bsh);
    247 
    248 	arm_cpu_max = 1 + __SHIFTOUT(armreg_l2ctrl_read(), L2CTRL_NUMCPU);
    249 	KASSERT(arm_cpu_max == 4);
    250 
    251 	bus_space_write_4(bst, bsh, EVP_RESET_VECTOR_0_REG, (uint32_t)cortex_mpstart);
    252 	bus_space_barrier(bst, bsh, EVP_RESET_VECTOR_0_REG, 4,
    253 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
    254 	uint32_t started = 0;
    255 
    256 	tegra_pmc_power(PMC_PARTID_CPU1, true); started |= __BIT(1);
    257 	tegra_pmc_power(PMC_PARTID_CPU2, true); started |= __BIT(2);
    258 	tegra_pmc_power(PMC_PARTID_CPU3, true); started |= __BIT(3);
    259 
    260 	for (u_int i = 0x10000000; i > 0; i--) {
    261 		arm_dmb();
    262 		if (arm_cpu_hatched == started)
    263 			break;
    264 	}
    265 #endif
    266 }
    267