Home | History | Annotate | Line # | Download | only in fb
      1 /*	$NetBSD: nouveau_nvkm_subdev_fb_ramnv40.c,v 1.3 2021/12/18 23:45:39 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2013 Red Hat Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: Ben Skeggs
     25  */
     26 #include <sys/cdefs.h>
     27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_fb_ramnv40.c,v 1.3 2021/12/18 23:45:39 riastradh Exp $");
     28 
     29 #include "ramnv40.h"
     30 
     31 #include <subdev/bios.h>
     32 #include <subdev/bios/bit.h>
     33 #include <subdev/bios/init.h>
     34 #include <subdev/bios/pll.h>
     35 #include <subdev/clk/pll.h>
     36 #include <subdev/timer.h>
     37 
     38 static int
     39 nv40_ram_calc(struct nvkm_ram *base, u32 freq)
     40 {
     41 	struct nv40_ram *ram = nv40_ram(base);
     42 	struct nvkm_subdev *subdev = &ram->base.fb->subdev;
     43 	struct nvkm_bios *bios = subdev->device->bios;
     44 	struct nvbios_pll pll;
     45 	int N1, M1, N2, M2;
     46 	int log2P, ret;
     47 
     48 	ret = nvbios_pll_parse(bios, 0x04, &pll);
     49 	if (ret) {
     50 		nvkm_error(subdev, "mclk pll data not found\n");
     51 		return ret;
     52 	}
     53 
     54 	ret = nv04_pll_calc(subdev, &pll, freq, &N1, &M1, &N2, &M2, &log2P);
     55 	if (ret < 0)
     56 		return ret;
     57 
     58 	ram->ctrl  = 0x80000000 | (log2P << 16);
     59 	ram->ctrl |= min(pll.bias_p + log2P, (int)pll.max_p) << 20;
     60 	if (N2 == M2) {
     61 		ram->ctrl |= 0x00000100;
     62 		ram->coef  = (N1 << 8) | M1;
     63 	} else {
     64 		ram->ctrl |= 0x40000000;
     65 		ram->coef  = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
     66 	}
     67 
     68 	return 0;
     69 }
     70 
     71 static int
     72 nv40_ram_prog(struct nvkm_ram *base)
     73 {
     74 	struct nv40_ram *ram = nv40_ram(base);
     75 	struct nvkm_subdev *subdev = &ram->base.fb->subdev;
     76 	struct nvkm_device *device = subdev->device;
     77 	struct nvkm_bios *bios = device->bios;
     78 	struct bit_entry M;
     79 	u32 crtc_mask = 0;
     80 	u8  sr1[2];
     81 	int i;
     82 
     83 	/* determine which CRTCs are active, fetch VGA_SR1 for each */
     84 	for (i = 0; i < 2; i++) {
     85 		u32 vbl = nvkm_rd32(device, 0x600808 + (i * 0x2000));
     86 		u32 cnt = 0;
     87 		do {
     88 			if (vbl != nvkm_rd32(device, 0x600808 + (i * 0x2000))) {
     89 				nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
     90 				sr1[i] = nvkm_rd08(device, 0x0c03c5 + (i * 0x2000));
     91 				if (!(sr1[i] & 0x20))
     92 					crtc_mask |= (1 << i);
     93 				break;
     94 			}
     95 			udelay(1);
     96 		} while (cnt++ < 32);
     97 	}
     98 
     99 	/* wait for vblank start on active crtcs, disable memory access */
    100 	for (i = 0; i < 2; i++) {
    101 		if (!(crtc_mask & (1 << i)))
    102 			continue;
    103 
    104 		nvkm_msec(device, 2000,
    105 			u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000));
    106 			if (!(tmp & 0x00010000))
    107 				break;
    108 		);
    109 
    110 		nvkm_msec(device, 2000,
    111 			u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000));
    112 			if ( (tmp & 0x00010000))
    113 				break;
    114 		);
    115 
    116 		nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
    117 		nvkm_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
    118 	}
    119 
    120 	/* prepare ram for reclocking */
    121 	nvkm_wr32(device, 0x1002d4, 0x00000001); /* precharge */
    122 	nvkm_wr32(device, 0x1002d0, 0x00000001); /* refresh */
    123 	nvkm_wr32(device, 0x1002d0, 0x00000001); /* refresh */
    124 	nvkm_mask(device, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
    125 	nvkm_wr32(device, 0x1002dc, 0x00000001); /* enable self-refresh */
    126 
    127 	/* change the PLL of each memory partition */
    128 	nvkm_mask(device, 0x00c040, 0x0000c000, 0x00000000);
    129 	switch (device->chipset) {
    130 	case 0x40:
    131 	case 0x45:
    132 	case 0x41:
    133 	case 0x42:
    134 	case 0x47:
    135 		nvkm_mask(device, 0x004044, 0xc0771100, ram->ctrl);
    136 		nvkm_mask(device, 0x00402c, 0xc0771100, ram->ctrl);
    137 		nvkm_wr32(device, 0x004048, ram->coef);
    138 		nvkm_wr32(device, 0x004030, ram->coef);
    139 		/* fall through */
    140 	case 0x43:
    141 	case 0x49:
    142 	case 0x4b:
    143 		nvkm_mask(device, 0x004038, 0xc0771100, ram->ctrl);
    144 		nvkm_wr32(device, 0x00403c, ram->coef);
    145 		/* fall through */
    146 	default:
    147 		nvkm_mask(device, 0x004020, 0xc0771100, ram->ctrl);
    148 		nvkm_wr32(device, 0x004024, ram->coef);
    149 		break;
    150 	}
    151 	udelay(100);
    152 	nvkm_mask(device, 0x00c040, 0x0000c000, 0x0000c000);
    153 
    154 	/* re-enable normal operation of memory controller */
    155 	nvkm_wr32(device, 0x1002dc, 0x00000000);
    156 	nvkm_mask(device, 0x100210, 0x80000000, 0x80000000);
    157 	udelay(100);
    158 
    159 	/* execute memory reset script from vbios */
    160 	if (!bit_entry(bios, 'M', &M))
    161 		nvbios_init(subdev, nvbios_rd16(bios, M.offset + 0x00));
    162 
    163 	/* make sure we're in vblank (hopefully the same one as before), and
    164 	 * then re-enable crtc memory access
    165 	 */
    166 	for (i = 0; i < 2; i++) {
    167 		if (!(crtc_mask & (1 << i)))
    168 			continue;
    169 
    170 		nvkm_msec(device, 2000,
    171 			u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000));
    172 			if ( (tmp & 0x00010000))
    173 				break;
    174 		);
    175 
    176 		nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
    177 		nvkm_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i]);
    178 	}
    179 
    180 	return 0;
    181 }
    182 
    183 static void
    184 nv40_ram_tidy(struct nvkm_ram *base)
    185 {
    186 }
    187 
    188 static const struct nvkm_ram_func
    189 nv40_ram_func = {
    190 	.calc = nv40_ram_calc,
    191 	.prog = nv40_ram_prog,
    192 	.tidy = nv40_ram_tidy,
    193 };
    194 
    195 int
    196 nv40_ram_new_(struct nvkm_fb *fb, enum nvkm_ram_type type, u64 size,
    197 	      struct nvkm_ram **pram)
    198 {
    199 	struct nv40_ram *ram;
    200 	if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL)))
    201 		return -ENOMEM;
    202 	*pram = &ram->base;
    203 	return nvkm_ram_ctor(&nv40_ram_func, fb, type, size, &ram->base);
    204 }
    205 
    206 int
    207 nv40_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
    208 {
    209 	struct nvkm_device *device = fb->subdev.device;
    210 	u32 pbus1218 = nvkm_rd32(device, 0x001218);
    211 	u32     size = nvkm_rd32(device, 0x10020c) & 0xff000000;
    212 	enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN;
    213 	int ret;
    214 
    215 	switch (pbus1218 & 0x00000300) {
    216 	case 0x00000000: type = NVKM_RAM_TYPE_SDRAM; break;
    217 	case 0x00000100: type = NVKM_RAM_TYPE_DDR1 ; break;
    218 	case 0x00000200: type = NVKM_RAM_TYPE_GDDR3; break;
    219 	case 0x00000300: type = NVKM_RAM_TYPE_DDR2 ; break;
    220 	}
    221 
    222 	ret = nv40_ram_new_(fb, type, size, pram);
    223 	if (ret)
    224 		return ret;
    225 
    226 	(*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1;
    227 	return 0;
    228 }
    229