Home | History | Annotate | Line # | Download | only in nvidia
soc_tegra124.c revision 1.10
      1  1.10  jmcneill /* $NetBSD: soc_tegra124.c,v 1.10 2015/11/21 22:52:31 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.10  jmcneill __KERNEL_RCSID(0, "$NetBSD: soc_tegra124.c,v 1.10 2015/11/21 22:52:31 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.10  jmcneill #define FUSE_SKU_INFO_REG	0x010
     51  1.10  jmcneill #define FUSE_CPU_SPEEDO_0_REG	0x014
     52  1.10  jmcneill #define FUSE_CPU_IDDQ_REG	0x018
     53  1.10  jmcneill #define FUSE_FT_REV_REG		0x028
     54  1.10  jmcneill #define FUSE_CPU_SPEEDO_1_REG	0x02c
     55  1.10  jmcneill #define FUSE_CPU_SPEEDO_2_REG	0x030
     56  1.10  jmcneill #define FUSE_SOC_SPEEDO_0_REG	0x034
     57  1.10  jmcneill #define FUSE_SOC_SPEEDO_1_REG	0x038
     58  1.10  jmcneill #define FUSE_SOC_SPEEDO_2_REG	0x03c
     59  1.10  jmcneill #define FUSE_SOC_IDDQ_REG	0x040
     60  1.10  jmcneill #define FUSE_GPU_IDDQ_REG	0x128
     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