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