From 9fbc144aa639dc35001cec6292cd625f6063c697 Mon Sep 17 00:00:00 2001 From: Thomas Makin Date: Sat, 9 Aug 2025 23:15:40 -0500 Subject: [PATCH] nouveau: add tegra210b01 support --- .../gpu/drm/nouveau/include/nvkm/subdev/clk.h | 1 + .../drm/nouveau/include/nvkm/subdev/volt.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 26 +++ .../gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c | 219 ++++++++++++++++++ .../gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c | 96 ++++++++ 5 files changed, 343 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h index 6a09d397c651..8af77b967164 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h @@ -134,5 +134,6 @@ int gf100_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct int gk104_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_clk **); int gk20a_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_clk **); int gm20b_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_clk **); +int gm20b_b01_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_clk **); int gp10b_clk_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_clk **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h index 0be86d5f0158..d520a017a1de 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h @@ -42,4 +42,5 @@ int gf117_volt_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct int gk104_volt_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_volt **); int gk20a_volt_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_volt **); int gm20b_volt_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_volt **); +int gm20b_b01_volt_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_volt **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 38ba1541b7d9..3b8b0d706204 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2072,6 +2072,31 @@ nv12b_chipset = { .sw = { 0x00000001, gf100_sw_new }, }; +static const struct nvkm_device_chip +nv12e_chipset = { + .name = "GM20B", + .acr = { 0x00000001, gm20b_acr_new }, + .bar = { 0x00000001, gm20b_bar_new }, + .bus = { 0x00000001, gf100_bus_new }, + .clk = { 0x00000001, gm20b_b01_clk_new }, + .fb = { 0x00000001, gm20b_fb_new }, + .fuse = { 0x00000001, gm107_fuse_new }, + .imem = { 0x00000001, gk20a_instmem_new }, + .ltc = { 0x00000001, gm200_ltc_new }, + .mc = { 0x00000001, gk20a_mc_new }, + .mmu = { 0x00000001, gm20b_mmu_new }, + .pmu = { 0x00000001, gm20b_pmu_new }, + .privring = { 0x00000001, gk20a_privring_new }, + .timer = { 0x00000001, gk20a_timer_new }, + .top = { 0x00000001, gk104_top_new }, + .volt = { 0x00000001, gm20b_b01_volt_new }, + .ce = { 0x00000004, gm200_ce_new }, + .dma = { 0x00000001, gf119_dma_new }, + .fifo = { 0x00000001, gm200_fifo_new }, + .gr = { 0x00000001, gm20b_gr_new }, + .sw = { 0x00000001, gf100_sw_new }, +}; + static const struct nvkm_device_chip nv130_chipset = { .name = "GP100", @@ -3225,6 +3250,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, case 0x124: device->chip = &nv124_chipset; break; case 0x126: device->chip = &nv126_chipset; break; case 0x12b: device->chip = &nv12b_chipset; break; + case 0x12e: device->chip = &nv12e_chipset; break; case 0x130: device->chip = &nv130_chipset; break; case 0x132: device->chip = &nv132_chipset; break; case 0x134: device->chip = &nv134_chipset; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c index fa8ca53acbd1..7c6e9dba09f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c @@ -717,6 +717,112 @@ gm20b_pstates[] = { }, }; +static struct nvkm_pstate +gm20b_b01_pstates[] = { + { + .base = { + .domain[nv_clk_src_gpc] = 76800, + .voltage = 0, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 153600, + .voltage = 1, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 230400, + .voltage = 2, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 307200, + .voltage = 3, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 384000, + .voltage = 4, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 460800, + .voltage = 5, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 537600, + .voltage = 6, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 614400, + .voltage = 7, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 691200, + .voltage = 8, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 768000, + .voltage = 9, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 844800, + .voltage = 10, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 921600, + .voltage = 11, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 998400, + .voltage = 12, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 1075200, + .voltage = 13, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 1152000, + .voltage = 14, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 1228800, + .voltage = 15, + }, + }, + { + .base = { + .domain[nv_clk_src_gpc] = 1267200, + .voltage = 16, + }, + }, +}; + static void gm20b_clk_fini(struct nvkm_clk *base) { @@ -912,6 +1018,41 @@ gm20b_clk = { }, }; +static const struct nvkm_clk_func +gm20b_b01_clk = { + .init = gm20b_clk_init, + .fini = gk20a_clk_fini, + .read = gk20a_clk_read, + .calc = gk20a_clk_calc, + .prog = gk20a_clk_prog, + .tidy = gk20a_clk_tidy, + .pstates = gm20b_b01_pstates, + .nr_pstates = ARRAY_SIZE(gm20b_b01_pstates), + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV }, + { nv_clk_src_max }, + }, +}; + +static const struct nvkm_clk_func +gm20b_b01_hiopt_clk_speedo = { + .init = gm20b_clk_init, + .fini = gk20a_clk_fini, + .read = gk20a_clk_read, + .calc = gk20a_clk_calc, + .prog = gk20a_clk_prog, + .tidy = gk20a_clk_tidy, + .pstates = gm20b_pstates, + /* HIOPT speedo only supports 16 voltages */ + .nr_pstates = ARRAY_SIZE(gm20b_pstates) - 1, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV }, + { nv_clk_src_max }, + }, +}; + static int gm20b_clk_new_speedo0(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_clk **pclk) @@ -930,6 +1071,24 @@ gm20b_clk_new_speedo0(struct nvkm_device *device, enum nvkm_subdev_type type, in return ret; } +static int +gm20b_b01_clk_new_hiopt(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_clk **pclk) +{ + struct gk20a_clk *clk; + int ret; + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) + return -ENOMEM; + *pclk = &clk->base; + + ret = gk20a_clk_ctor(device, type, inst, &gm20b_b01_hiopt_clk_speedo, &gm20b_pllg_params, clk); + clk->pl_to_div = pl_to_div; + clk->div_to_pl = div_to_pl; + return ret; +} + /* FUSE register */ #define FUSE_RESERVED_CALIB0 0x204 #define FUSE_RESERVED_CALIB0_INTERCEPT_FRAC_SHIFT 0 @@ -1074,3 +1233,63 @@ gm20b_clk_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, return 0; } + +int +gm20b_b01_clk_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_clk **pclk) +{ + struct nvkm_device_tegra *tdev = device->func->tegra(device); + struct gm20b_clk *clk; + struct nvkm_subdev *subdev; + struct gk20a_clk_pllg_params *clk_params; + int ret; + + /* Speedo 0 GPUs cannot use noise-aware PLL */ + if (tdev->gpu_speedo_id == 0) + return gm20b_b01_clk_new_hiopt(device, type, inst, pclk); + + /* Speedo >= 1, use NAPLL */ + clk = kzalloc(sizeof(*clk) + sizeof(*clk_params), GFP_KERNEL); + if (!clk) + return -ENOMEM; + *pclk = &clk->base.base; + subdev = &clk->base.base.subdev; + + /* duplicate the clock parameters since we will patch them below */ + clk_params = (void *) (clk + 1); + *clk_params = gm20b_pllg_params; + ret = gk20a_clk_ctor(device, type, inst, &gm20b_b01_clk, clk_params, &clk->base); + if (ret) + return ret; + + /* + * NAPLL can only work with max_u, clamp the m range so + * gk20a_pllg_calc_mnp always uses it + */ + clk_params->max_m = clk_params->min_m = DIV_ROUND_UP(clk_params->max_u, + (clk->base.parent_rate / KHZ)); + if (clk_params->max_m == 0) { + nvkm_warn(subdev, "cannot use NAPLL, using legacy clock...\n"); + kfree(clk); + return gm20b_b01_clk_new_hiopt(device, type, inst, pclk); + } + + clk->base.pl_to_div = pl_to_div; + clk->base.div_to_pl = div_to_pl; + + clk->dvfs_params = &gm20b_dvfs_params; + + ret = gm20b_clk_init_fused_params(clk); + /* + * we will calibrate during init - should never happen on + * prod parts + */ + if (ret) + nvkm_warn(subdev, "no fused calibration parameters\n"); + + ret = gm20b_clk_init_safe_fmax(clk); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c index c2e9694d333f..38430ca9f591 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c @@ -91,3 +91,99 @@ gm20b_volt_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, return gk20a_volt_ctor(device, type, inst, gm20b_cvb_coef, ARRAY_SIZE(gm20b_cvb_coef), vmin, volt); } + +static const struct cvb_coef gm20b_b01_na_cvb_slt_coef[] = { + /* KHz, c0, c1, c2, c3, c4, c5 */ + /* 76800 */ { 590000, 0, 0, 0, 0, 0 }, + /* 153600 */ { 590000, 0, 0, 0, 0, 0 }, + /* 230400 */ { 590000, 0, 0, 0, 0, 0 }, + /* 307200 */ { 590000, 0, 0, 0, 0, 0 }, + /* 384000 */ { 590000, 0, 0, 0, 0, 0 }, + /* 460800 */ { 795089, -11096, -163, 298, -10421, 162}, + /* 537600 */ { 795089, -11096, -163, 298, -10421, 162 }, + /* 614400 */ { 820606, -6285, -452, 238, -6182, 81 }, + /* 691200 */ { 846289, -4565, -552, 119, -3958, -2 }, + /* 768000 */ { 888720, -5110, -584, 0, -2849, 39 }, + /* 844800 */ { 936634, -6089, -602, -60, -99, -93 }, + /* 921600 */ { 982562, -7373, -614, -179, 1797, -13 }, + /* 998400 */ { 1090179, -14125, -497, -179, 3518, 9 }, + /* 1075200 */ { 1155798, -13465, -648, 0, 1077, 40 }, + /* 1152000 */ { 1198568, -10904, -830, 0, 1469, 110 }, + /* 1228800 */ { 1269988, -12707, -859, 0, 3722, 313 }, + /* 1267200 */ { 1308155, -13694, -867, 0, 3681, 559 }, +}; + +static const struct cvb_coef gm20b_b01_na_cvb_coef[] = { + /* KHz, c0, c1, c2, c3, c4, c5 */ + /* 76800 */ { 610000, 0, 0, 0, 0, 0 }, + /* 153600 */ { 610000, 0, 0, 0, 0, 0 }, + /* 230400 */ { 610000, 0, 0, 0, 0, 0 }, + /* 307200 */ { 610000, 0, 0, 0, 0, 0 }, + /* 384000 */ { 610000, 0, 0, 0, 0, 0 }, + /* 460800 */ { 610000, 0, 0, 0, 0, 0 }, + /* 537600 */ { 801688, -10900, -163, 298, -10599, 162 }, + /* 614400 */ { 824214, -5743, -452, 238, -6325, 81 }, + /* 691200 */ { 848830, -3903, -552, 119, -4030, -2 }, + /* 768000 */ { 891575, -4409, -584, 0, -2849, 39 }, + /* 844800 */ { 940071, -5367, -602, -60, -63, -93 }, + /* 921600 */ { 986765, -6637, -614, -179, 1905, -13 }, + /* 998400 */ { 1098475, -13529, -497, -179, 3626, 9 }, + /* 1075200 */ { 1163644, -12688, -648, 0, 1077, 40 }, + /* 1152000 */ { 1204812, -9908, -830, 0, 1469, 110 }, + /* 1228800 */ { 1277303, -11675, -859, 0, 3722, 313 }, + /* 1267200 */ { 1335531, -12567, -867, 0, 3681, 559 }, +}; + +static const struct cvb_coef gm20b_b01_na_cvb_hiopt_coef[] = { + /* KHz, c0, c1, c2, c3, c4, c5 */ + /* 76800 */ { 590000, 0, 0, 0, 0, 0 }, + /* 153600 */ { 590000, 0, 0, 0, 0, 0 }, + /* 230400 */ { 590000, 0, 0, 0, 0, 0 }, + /* 307200 */ { 590000, 0, 0, 0, 0, 0 }, + /* 384000 */ { 590000, 0, 0, 0, 0, 0 }, + /* 460800 */ { 590000, 0, 0, 0, 0, 0 }, + /* 537600 */ { 590000, 0, 0, 0, 0, 0 }, + /* 614400 */ { 590000, 0, 0, 0, 0, 0 }, + /* 691200 */ { 838712, -7304, -552, 1785, -56250, -450 }, + /* 768000 */ { 880210, -7955, -584, 0, -42735, 8775 }, + /* 844800 */ { 926398, -8892, -602, -900, -5760, -20925 }, + /* 921600 */ { 970060, -10108, -614, -2685, 22620, -2925 }, + /* 998400 */ { 1065665, -16075, -497, -2685, 48195, 2025 }, + /* 1075200 */ { 1132576, -16093, -648, 0, 16155, 9000 }, + /* 1152000 */ { 1180029, -14534, -830, 0, 22035, 24750 }, + /* 1228800 */ { 1248293, -16383, -859, 0, 55830, 70425 }, +}; + +int +gm20b_b01_volt_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, + struct nvkm_volt **pvolt) +{ + struct nvkm_device_tegra *tdev = device->func->tegra(device); + struct gk20a_volt *volt; + u32 vmin; + + if (tdev->gpu_speedo_id >= ARRAY_SIZE(speedo_to_vmin)) { + nvdev_error(device, "unsupported speedo %d\n", + tdev->gpu_speedo_id); + return -EINVAL; + } + + volt = kzalloc(sizeof(*volt), GFP_KERNEL); + if (!volt) + return -ENOMEM; + *pvolt = &volt->base; + + vmin = speedo_to_vmin[tdev->gpu_speedo_id]; + + switch (tdev->gpu_speedo_id) { + case 3: /* HIOPT table */ + return gk20a_volt_ctor(device, type, inst, gm20b_b01_na_cvb_hiopt_coef, + ARRAY_SIZE(gm20b_b01_na_cvb_hiopt_coef), vmin, volt); + case 2: /* SLT table */ + return gk20a_volt_ctor(device, type, inst, gm20b_b01_na_cvb_slt_coef, + ARRAY_SIZE(gm20b_b01_na_cvb_slt_coef), vmin, volt); + default: + return gk20a_volt_ctor(device, type, inst, gm20b_b01_na_cvb_coef, + ARRAY_SIZE(gm20b_b01_na_cvb_coef), vmin, volt); + } +}