Home | History | Annotate | Line # | Download | only in nvidia
soc_tegra124.c revision 1.12
      1  1.12  jmcneill /* $NetBSD: soc_tegra124.c,v 1.12 2015/12/22 22:10:36 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.12  jmcneill __KERNEL_RCSID(0, "$NetBSD: soc_tegra124.c,v 1.12 2015/12/22 22:10:36 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.12  jmcneill #include <dev/clk/clk.h>
     43  1.12  jmcneill #include <dev/i2c/i2cvar.h>
     44  1.12  jmcneill #include <dev/fdt/fdtvar.h>
     45  1.12  jmcneill 
     46   1.1  jmcneill #include <arm/cpufunc.h>
     47   1.1  jmcneill 
     48   1.1  jmcneill #include <arm/nvidia/tegra_reg.h>
     49   1.2  jmcneill #include <arm/nvidia/tegra_pmcreg.h>
     50   1.1  jmcneill #include <arm/nvidia/tegra_var.h>
     51   1.1  jmcneill 
     52   1.2  jmcneill #define EVP_RESET_VECTOR_0_REG	0x100
     53   1.2  jmcneill 
     54  1.10  jmcneill #define FUSE_SKU_INFO_REG	0x010
     55  1.10  jmcneill #define FUSE_CPU_SPEEDO_0_REG	0x014
     56  1.10  jmcneill #define FUSE_CPU_IDDQ_REG	0x018
     57  1.10  jmcneill #define FUSE_FT_REV_REG		0x028
     58  1.10  jmcneill #define FUSE_CPU_SPEEDO_1_REG	0x02c
     59  1.10  jmcneill #define FUSE_CPU_SPEEDO_2_REG	0x030
     60  1.10  jmcneill #define FUSE_SOC_SPEEDO_0_REG	0x034
     61  1.10  jmcneill #define FUSE_SOC_SPEEDO_1_REG	0x038
     62  1.10  jmcneill #define FUSE_SOC_SPEEDO_2_REG	0x03c
     63  1.10  jmcneill #define FUSE_SOC_IDDQ_REG	0x040
     64  1.10  jmcneill #define FUSE_GPU_IDDQ_REG	0x128
     65   1.9  jmcneill 
     66   1.9  jmcneill static void	tegra124_speedo_init(void);
     67   1.9  jmcneill static int	tegra124_speedo_init_ids(uint32_t);
     68   1.9  jmcneill static bool	tegra124_speedo_rate_ok(u_int);
     69   1.9  jmcneill 
     70   1.3  jmcneill static u_int	tegra124_cpufreq_set_rate(u_int);
     71   1.3  jmcneill static u_int	tegra124_cpufreq_get_rate(void);
     72   1.3  jmcneill static size_t	tegra124_cpufreq_get_available(u_int *, size_t);
     73   1.3  jmcneill 
     74   1.3  jmcneill static const struct tegra_cpufreq_func tegra124_cpufreq_func = {
     75   1.3  jmcneill 	.set_rate = tegra124_cpufreq_set_rate,
     76   1.3  jmcneill 	.get_rate = tegra124_cpufreq_get_rate,
     77   1.3  jmcneill 	.get_available = tegra124_cpufreq_get_available,
     78   1.3  jmcneill };
     79   1.3  jmcneill 
     80   1.3  jmcneill static struct tegra124_cpufreq_rate {
     81   1.3  jmcneill 	u_int rate;
     82   1.3  jmcneill 	u_int divm;
     83   1.3  jmcneill 	u_int divn;
     84   1.3  jmcneill 	u_int divp;
     85   1.3  jmcneill } tegra124_cpufreq_rates[] = {
     86  1.11  jmcneill 	{ 2316, 1, 193, 0 },
     87   1.3  jmcneill 	{ 2100, 1, 175, 0 },
     88   1.3  jmcneill 	{ 1896, 1, 158, 0 },
     89   1.3  jmcneill 	{ 1692, 1, 141, 0 },
     90   1.3  jmcneill 	{ 1500, 1, 125, 0 },
     91   1.3  jmcneill 	{ 1296, 1, 108, 0 },
     92   1.3  jmcneill 	{ 1092, 1, 91, 0 },
     93   1.3  jmcneill 	{ 900, 1, 75, 0 },
     94   1.3  jmcneill 	{ 696, 1, 58, 0 }
     95   1.3  jmcneill };
     96   1.3  jmcneill 
     97   1.9  jmcneill static const u_int tegra124_cpufreq_max[] = {
     98   1.9  jmcneill 	2014,
     99   1.9  jmcneill 	2320,
    100   1.9  jmcneill 	2116,
    101   1.9  jmcneill 	2524
    102   1.9  jmcneill };
    103   1.9  jmcneill 
    104   1.9  jmcneill static struct tegra124_speedo {
    105   1.9  jmcneill 	u_int cpu_speedo_id;
    106   1.9  jmcneill 	u_int soc_speedo_id;
    107   1.9  jmcneill 	u_int gpu_speedo_id;
    108   1.9  jmcneill } tegra124_speedo = {
    109   1.9  jmcneill 	.cpu_speedo_id = 0,
    110   1.9  jmcneill 	.soc_speedo_id = 0,
    111   1.9  jmcneill 	.gpu_speedo_id = 0
    112   1.9  jmcneill };
    113   1.9  jmcneill 
    114  1.12  jmcneill static struct clk *tegra124_clk_pllx = NULL;
    115  1.12  jmcneill 
    116   1.3  jmcneill void
    117   1.3  jmcneill tegra124_cpuinit(void)
    118   1.3  jmcneill {
    119  1.12  jmcneill 	const int node = OF_finddevice("/i2c@0,7000d000");
    120  1.12  jmcneill 	if (node == -1) {
    121  1.12  jmcneill 		aprint_error("cpufreq: ERROR: couldn't find i2c@0,7000d000\n");
    122  1.12  jmcneill 		return;
    123  1.12  jmcneill 	}
    124  1.12  jmcneill 	i2c_tag_t ic = fdtbus_get_i2c_tag(node);
    125   1.7  jmcneill 
    126   1.5  jmcneill 	/* Set VDD_CPU voltage to 1.4V */
    127   1.7  jmcneill 	const u_int target_mv = 1400;
    128   1.7  jmcneill 	const u_int sd0_vsel = (target_mv - 600) / 10;
    129  1.12  jmcneill 	uint8_t data[2] = { 0x00, sd0_vsel };
    130  1.12  jmcneill 
    131  1.12  jmcneill 	iic_acquire_bus(ic, I2C_F_POLL);
    132  1.12  jmcneill 	const int error = iic_exec(ic, I2C_OP_WRITE_WITH_STOP, 0x40,
    133  1.12  jmcneill 	    NULL, 0, data, sizeof(data), I2C_F_POLL);
    134  1.12  jmcneill 	iic_release_bus(ic, I2C_F_POLL);
    135  1.12  jmcneill 	if (error) {
    136  1.12  jmcneill 		aprint_error("cpufreq: ERROR: couldn't set VDD_CPU: %d\n",
    137  1.12  jmcneill 		    error);
    138  1.12  jmcneill 		return;
    139  1.12  jmcneill 	}
    140   1.5  jmcneill 	delay(10000);
    141   1.5  jmcneill 
    142   1.9  jmcneill 	tegra124_speedo_init();
    143   1.9  jmcneill 
    144  1.12  jmcneill 	tegra124_clk_pllx = clk_get("pll_x");
    145  1.12  jmcneill 	if (tegra124_clk_pllx == NULL) {
    146  1.12  jmcneill 		aprint_error("cpufreq: ERROR: couldn't find pll_x\n");
    147  1.12  jmcneill 		return;
    148  1.12  jmcneill 	}
    149  1.12  jmcneill 
    150   1.3  jmcneill 	tegra_cpufreq_register(&tegra124_cpufreq_func);
    151   1.3  jmcneill }
    152   1.3  jmcneill 
    153   1.9  jmcneill static void
    154   1.9  jmcneill tegra124_speedo_init(void)
    155   1.9  jmcneill {
    156   1.9  jmcneill 	uint32_t sku_id;
    157   1.9  jmcneill 
    158   1.9  jmcneill 	sku_id = tegra_fuse_read(FUSE_SKU_INFO_REG);
    159   1.9  jmcneill 	tegra124_speedo_init_ids(sku_id);
    160   1.9  jmcneill }
    161   1.9  jmcneill 
    162   1.9  jmcneill static int
    163   1.9  jmcneill tegra124_speedo_init_ids(uint32_t sku_id)
    164   1.9  jmcneill {
    165   1.9  jmcneill 	int threshold = 0;
    166   1.9  jmcneill 
    167   1.9  jmcneill 	switch (sku_id) {
    168   1.9  jmcneill 	case 0x00:
    169   1.9  jmcneill 	case 0x0f:
    170   1.9  jmcneill 	case 0x23:
    171   1.9  jmcneill 		break;	/* use default */
    172   1.9  jmcneill 	case 0x83:
    173   1.9  jmcneill 		tegra124_speedo.cpu_speedo_id = 2;
    174   1.9  jmcneill 		break;
    175   1.9  jmcneill 	case 0x1f:
    176   1.9  jmcneill 	case 0x87:
    177   1.9  jmcneill 	case 0x27:
    178   1.9  jmcneill 		tegra124_speedo.cpu_speedo_id = 2;
    179   1.9  jmcneill 		tegra124_speedo.soc_speedo_id = 0;
    180   1.9  jmcneill 		tegra124_speedo.gpu_speedo_id = 1;
    181   1.9  jmcneill 		break;
    182   1.9  jmcneill 	case 0x81:
    183   1.9  jmcneill 	case 0x21:
    184   1.9  jmcneill 	case 0x07:
    185   1.9  jmcneill 		tegra124_speedo.cpu_speedo_id = 1;
    186   1.9  jmcneill 		tegra124_speedo.soc_speedo_id = 1;
    187   1.9  jmcneill 		tegra124_speedo.gpu_speedo_id = 1;
    188   1.9  jmcneill 		threshold = 1;
    189   1.9  jmcneill 		break;
    190   1.9  jmcneill 	case 0x49:
    191   1.9  jmcneill 	case 0x4a:
    192   1.9  jmcneill 	case 0x48:
    193   1.9  jmcneill 		tegra124_speedo.cpu_speedo_id = 4;
    194   1.9  jmcneill 		tegra124_speedo.soc_speedo_id = 2;
    195   1.9  jmcneill 		tegra124_speedo.gpu_speedo_id = 3;
    196   1.9  jmcneill 		threshold = 1;
    197   1.9  jmcneill 		break;
    198   1.9  jmcneill 	default:
    199   1.9  jmcneill 		aprint_error("tegra124: unknown SKU ID %#x\n", sku_id);
    200   1.9  jmcneill 		break;	/* use default */
    201   1.9  jmcneill 	}
    202   1.9  jmcneill 
    203   1.9  jmcneill 	return threshold;
    204   1.9  jmcneill }
    205   1.9  jmcneill 
    206   1.9  jmcneill static bool
    207   1.9  jmcneill tegra124_speedo_rate_ok(u_int rate)
    208   1.9  jmcneill {
    209   1.9  jmcneill 	u_int tbl = 0;
    210   1.9  jmcneill 
    211   1.9  jmcneill 	if (tegra124_speedo.cpu_speedo_id < __arraycount(tegra124_cpufreq_max))
    212   1.9  jmcneill 		tbl = tegra124_speedo.cpu_speedo_id;
    213   1.9  jmcneill 
    214   1.9  jmcneill 	return rate <= tegra124_cpufreq_max[tbl];
    215   1.9  jmcneill }
    216   1.9  jmcneill 
    217   1.9  jmcneill 
    218   1.3  jmcneill static u_int
    219   1.3  jmcneill tegra124_cpufreq_set_rate(u_int rate)
    220   1.3  jmcneill {
    221   1.3  jmcneill 	const u_int nrates = __arraycount(tegra124_cpufreq_rates);
    222   1.3  jmcneill 	const struct tegra124_cpufreq_rate *r = NULL;
    223   1.3  jmcneill 
    224   1.9  jmcneill 	if (tegra124_speedo_rate_ok(rate) == false)
    225   1.9  jmcneill 		return EINVAL;
    226   1.9  jmcneill 
    227   1.3  jmcneill 	for (int i = 0; i < nrates; i++) {
    228   1.3  jmcneill 		if (tegra124_cpufreq_rates[i].rate == rate) {
    229   1.3  jmcneill 			r = &tegra124_cpufreq_rates[i];
    230   1.3  jmcneill 			break;
    231   1.3  jmcneill 		}
    232   1.3  jmcneill 	}
    233   1.3  jmcneill 	if (r == NULL)
    234   1.3  jmcneill 		return EINVAL;
    235   1.3  jmcneill 
    236  1.12  jmcneill 	return clk_set_rate(tegra124_clk_pllx, r->rate * 1000000);
    237   1.3  jmcneill }
    238   1.3  jmcneill 
    239   1.3  jmcneill static u_int
    240   1.3  jmcneill tegra124_cpufreq_get_rate(void)
    241   1.3  jmcneill {
    242  1.12  jmcneill 	return clk_get_rate(tegra124_clk_pllx) / 1000000;
    243   1.3  jmcneill }
    244   1.3  jmcneill 
    245   1.3  jmcneill static size_t
    246   1.3  jmcneill tegra124_cpufreq_get_available(u_int *pavail, size_t maxavail)
    247   1.3  jmcneill {
    248   1.3  jmcneill 	const u_int nrates = __arraycount(tegra124_cpufreq_rates);
    249   1.9  jmcneill 	u_int n, cnt;
    250   1.3  jmcneill 
    251   1.3  jmcneill 	KASSERT(nrates <= maxavail);
    252   1.3  jmcneill 
    253   1.9  jmcneill 	for (n = 0, cnt = 0; n < nrates; n++) {
    254   1.9  jmcneill 		if (tegra124_speedo_rate_ok(tegra124_cpufreq_rates[n].rate)) {
    255   1.9  jmcneill 			pavail[cnt++] = tegra124_cpufreq_rates[n].rate;
    256   1.9  jmcneill 		}
    257   1.3  jmcneill 	}
    258   1.3  jmcneill 
    259   1.9  jmcneill 	return cnt;
    260   1.3  jmcneill }
    261   1.3  jmcneill 
    262   1.1  jmcneill void
    263   1.1  jmcneill tegra124_mpinit(void)
    264   1.1  jmcneill {
    265   1.1  jmcneill #if defined(MULTIPROCESSOR)
    266   1.1  jmcneill 	extern void cortex_mpstart(void);
    267   1.2  jmcneill 	bus_space_tag_t bst = &armv7_generic_bs_tag;
    268   1.2  jmcneill 	bus_space_handle_t bsh;
    269   1.2  jmcneill 
    270   1.2  jmcneill 	bus_space_subregion(bst, tegra_ppsb_bsh,
    271   1.2  jmcneill 	    TEGRA_EVP_OFFSET, TEGRA_EVP_SIZE, &bsh);
    272   1.1  jmcneill 
    273   1.1  jmcneill 	arm_cpu_max = 1 + __SHIFTOUT(armreg_l2ctrl_read(), L2CTRL_NUMCPU);
    274   1.2  jmcneill 	KASSERT(arm_cpu_max == 4);
    275   1.1  jmcneill 
    276   1.2  jmcneill 	bus_space_write_4(bst, bsh, EVP_RESET_VECTOR_0_REG, (uint32_t)cortex_mpstart);
    277   1.2  jmcneill 	bus_space_barrier(bst, bsh, EVP_RESET_VECTOR_0_REG, 4,
    278   1.2  jmcneill 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
    279   1.4      matt 	uint32_t started = 0;
    280   1.2  jmcneill 
    281   1.4      matt 	tegra_pmc_power(PMC_PARTID_CPU1, true); started |= __BIT(1);
    282   1.4      matt 	tegra_pmc_power(PMC_PARTID_CPU2, true); started |= __BIT(2);
    283   1.4      matt 	tegra_pmc_power(PMC_PARTID_CPU3, true); started |= __BIT(3);
    284   1.2  jmcneill 
    285   1.4      matt 	for (u_int i = 0x10000000; i > 0; i--) {
    286   1.6     skrll 		arm_dmb();
    287   1.4      matt 		if (arm_cpu_hatched == started)
    288   1.2  jmcneill 			break;
    289   1.2  jmcneill 	}
    290   1.1  jmcneill #endif
    291   1.1  jmcneill }
    292