📄 nv_hw.c
字号:
{ int data, pagemiss, width, video_enable, bpp; int nvclks, mclks, pclks, vpagemiss, crtpagemiss; int nvclk_fill; int found, mclk_extra, mclk_loop, cbs, m1; int mclk_freq, pclk_freq, nvclk_freq, mp_enable; int us_m, us_m_min, us_n, us_p, crtc_drain_rate; int vus_m; int vpm_us, us_video, cpm_us, us_crt, clwm; int clwm_rnd_down; int m2us, us_pipe_min, p1clk, p2; int min_mclk_extra; int us_min_mclk_extra; fifo->valid = 1; pclk_freq = arb->pclk_khz; /* freq in KHz */ mclk_freq = arb->mclk_khz; nvclk_freq = arb->nvclk_khz; pagemiss = arb->mem_page_miss; width = arb->memory_width / 64; video_enable = arb->enable_video; bpp = arb->pix_bpp; mp_enable = arb->enable_mp; clwm = 0; cbs = 512; pclks = 4; /* lwm detect. */ nvclks = 3; /* lwm -> sync. */ nvclks += 2; /* fbi bus cycles (1 req + 1 busy) */ /* 2 edge sync. may be very close to edge so just put one. */ mclks = 1; mclks += 1; /* arb_hp_req */ mclks += 5; /* ap_hp_req tiling pipeline */ mclks += 2; /* tc_req latency fifo */ mclks += 2; /* fb_cas_n_ memory request to fbio block */ mclks += 7; /* sm_d_rdv data returned from fbio block */ /* fb.rd.d.Put_gc need to accumulate 256 bits for read */ if (arb->memory_type == 0) if (arb->memory_width == 64) /* 64 bit bus */ mclks += 4; else mclks += 2; else if (arb->memory_width == 64) /* 64 bit bus */ mclks += 2; else mclks += 1; if ((!video_enable) && (arb->memory_width == 128)) { mclk_extra = (bpp == 32) ? 31 : 42; /* Margin of error */ min_mclk_extra = 17; } else { mclk_extra = (bpp == 32) ? 8 : 4; /* Margin of error */ /* mclk_extra = 4; *//* Margin of error */ min_mclk_extra = 18; } /* 2 edge sync. may be very close to edge so just put one. */ nvclks += 1; nvclks += 1; /* fbi_d_rdv_n */ nvclks += 1; /* Fbi_d_rdata */ nvclks += 1; /* crtfifo load */ if (mp_enable) mclks += 4; /* Mp can get in with a burst of 8. */ /* Extra clocks determined by heuristics */ nvclks += 0; pclks += 0; found = 0; while (found != 1) { fifo->valid = 1; found = 1; mclk_loop = mclks + mclk_extra; /* Mclk latency in us */ us_m = mclk_loop * 1000 * 1000 / mclk_freq; /* Minimum Mclk latency in us */ us_m_min = mclks * 1000 * 1000 / mclk_freq; us_min_mclk_extra = min_mclk_extra * 1000 * 1000 / mclk_freq; /* nvclk latency in us */ us_n = nvclks * 1000 * 1000 / nvclk_freq; /* nvclk latency in us */ us_p = pclks * 1000 * 1000 / pclk_freq; us_pipe_min = us_m_min + us_n + us_p; /* Mclk latency in us */ vus_m = mclk_loop * 1000 * 1000 / mclk_freq; if (video_enable) { crtc_drain_rate = pclk_freq * bpp / 8; /* MB/s */ vpagemiss = 1; /* self generating page miss */ vpagemiss += 1; /* One higher priority before */ crtpagemiss = 2; /* self generating page miss */ if (mp_enable) crtpagemiss += 1; /* if MA0 conflict */ vpm_us = (vpagemiss * pagemiss) * 1000 * 1000 / mclk_freq; /* Video has separate read return path */ us_video = vpm_us + vus_m; cpm_us = crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq; /* Wait for video */ us_crt = us_video + cpm_us /* CRT Page miss */ + us_m + us_n + us_p /* other latency */ ; clwm = us_crt * crtc_drain_rate / (1000 * 1000); /* fixed point <= float_point - 1. Fixes that */ clwm++; } else { /* bpp * pclk/8 */ crtc_drain_rate = pclk_freq * bpp / 8; crtpagemiss = 1; /* self generating page miss */ crtpagemiss += 1; /* MA0 page miss */ if (mp_enable) crtpagemiss += 1; /* if MA0 conflict */ cpm_us = crtpagemiss * pagemiss * 1000 * 1000 / mclk_freq; us_crt = cpm_us + us_m + us_n + us_p; clwm = us_crt * crtc_drain_rate / (1000 * 1000); /* fixed point <= float_point - 1. Fixes that */ clwm++; /* Finally, a heuristic check when width == 64 bits */ if (width == 1) { nvclk_fill = nvclk_freq * 8; if (crtc_drain_rate * 100 >= nvclk_fill * 102) /*Large number to fail */ clwm = 0xfff; else if (crtc_drain_rate * 100 >= nvclk_fill * 98) { clwm = 1024; cbs = 512; } } } /* Overfill check: */ clwm_rnd_down = ((int)clwm / 8) * 8; if (clwm_rnd_down < clwm) clwm += 8; m1 = clwm + cbs - 1024; /* Amount of overfill */ m2us = us_pipe_min + us_min_mclk_extra; /* pclk cycles to drain */ p1clk = m2us * pclk_freq / (1000 * 1000); p2 = p1clk * bpp / 8; /* bytes drained. */ if ((p2 < m1) && (m1 > 0)) { fifo->valid = 0; found = 0; if (min_mclk_extra == 0) { if (cbs <= 32) { /* Can't adjust anymore! */ found = 1; } else { /* reduce the burst size */ cbs = cbs / 2; } } else { min_mclk_extra--; } } else { if (clwm > 1023) { /* Have some margin */ fifo->valid = 0; found = 0; if (min_mclk_extra == 0) /* Can't adjust anymore! */ found = 1; else min_mclk_extra--; } } if (clwm < (1024 - cbs + 8)) clwm = 1024 - cbs + 8; data = (int)(clwm); /* printf("CRT LWM: %f bytes, prog: 0x%x, bs: 256\n", clwm, data ); */ fifo->graphics_lwm = data; fifo->graphics_burst_size = cbs; fifo->video_lwm = 1024; fifo->video_burst_size = 512; }}static void nv10UpdateArbitrationSettings(unsigned VClk, unsigned pixelDepth, unsigned *burst, unsigned *lwm, struct nvidia_par *par){ nv10_fifo_info fifo_data; nv10_sim_state sim_data; unsigned int MClk, NVClk, cfg1; nvGetClocks(par, &MClk, &NVClk); cfg1 = NV_RD32(par->PFB, 0x0204); sim_data.pix_bpp = (char)pixelDepth; sim_data.enable_video = 1; sim_data.enable_mp = 0; sim_data.memory_type = (NV_RD32(par->PFB, 0x0200) & 0x01) ? 1 : 0; sim_data.memory_width = (NV_RD32(par->PEXTDEV, 0x0000) & 0x10) ? 128 : 64; sim_data.mem_latency = (char)cfg1 & 0x0F; sim_data.mem_aligned = 1; sim_data.mem_page_miss = (char)(((cfg1 >> 4) & 0x0F) + ((cfg1 >> 31) & 0x01)); sim_data.gr_during_vid = 0; sim_data.pclk_khz = VClk; sim_data.mclk_khz = MClk; sim_data.nvclk_khz = NVClk; nv10CalcArbitration(&fifo_data, &sim_data); if (fifo_data.valid) { int b = fifo_data.graphics_burst_size >> 4; *burst = 0; while (b >>= 1) (*burst)++; *lwm = fifo_data.graphics_lwm >> 3; }}static void nv30UpdateArbitrationSettings ( struct nvidia_par *par, unsigned int *burst, unsigned int *lwm){ unsigned int MClk, NVClk; unsigned int fifo_size, burst_size, graphics_lwm; fifo_size = 2048; burst_size = 512; graphics_lwm = fifo_size - burst_size; nvGetClocks(par, &MClk, &NVClk); *burst = 0; burst_size >>= 5; while(burst_size >>= 1) (*burst)++; *lwm = graphics_lwm >> 3;}static void nForceUpdateArbitrationSettings(unsigned VClk, unsigned pixelDepth, unsigned *burst, unsigned *lwm, struct nvidia_par *par){ nv10_fifo_info fifo_data; nv10_sim_state sim_data; unsigned int M, N, P, pll, MClk, NVClk, memctrl; struct pci_dev *dev; if ((par->Chipset & 0x0FF0) == 0x01A0) { unsigned int uMClkPostDiv; dev = pci_get_bus_and_slot(0, 3); pci_read_config_dword(dev, 0x6C, &uMClkPostDiv); uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf; if (!uMClkPostDiv) uMClkPostDiv = 4; MClk = 400000 / uMClkPostDiv; } else { dev = pci_get_bus_and_slot(0, 5); pci_read_config_dword(dev, 0x4c, &MClk); MClk /= 1000; } pci_dev_put(dev); pll = NV_RD32(par->PRAMDAC0, 0x0500); M = (pll >> 0) & 0xFF; N = (pll >> 8) & 0xFF; P = (pll >> 16) & 0x0F; NVClk = (N * par->CrystalFreqKHz / M) >> P; sim_data.pix_bpp = (char)pixelDepth; sim_data.enable_video = 0; sim_data.enable_mp = 0; dev = pci_get_bus_and_slot(0, 1); pci_read_config_dword(dev, 0x7C, &sim_data.memory_type); pci_dev_put(dev); sim_data.memory_type = (sim_data.memory_type >> 12) & 1; sim_data.memory_width = 64; dev = pci_get_bus_and_slot(0, 3); pci_read_config_dword(dev, 0, &memctrl); pci_dev_put(dev); memctrl >>= 16; if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) { int dimm[3]; dev = pci_get_bus_and_slot(0, 2); pci_read_config_dword(dev, 0x40, &dimm[0]); dimm[0] = (dimm[0] >> 8) & 0x4f; pci_read_config_dword(dev, 0x44, &dimm[1]); dimm[1] = (dimm[1] >> 8) & 0x4f; pci_read_config_dword(dev, 0x48, &dimm[2]); dimm[2] = (dimm[2] >> 8) & 0x4f; if ((dimm[0] + dimm[1]) != dimm[2]) { printk("nvidiafb: your nForce DIMMs are not arranged " "in optimal banks!\n"); } pci_dev_put(dev); } sim_data.mem_latency = 3; sim_data.mem_aligned = 1; sim_data.mem_page_miss = 10; sim_data.gr_during_vid = 0; sim_data.pclk_khz = VClk; sim_data.mclk_khz = MClk; sim_data.nvclk_khz = NVClk; nv10CalcArbitration(&fifo_data, &sim_data); if (fifo_data.valid) { int b = fifo_data.graphics_burst_size >> 4; *burst = 0; while (b >>= 1) (*burst)++; *lwm = fifo_data.graphics_lwm >> 3; }}/****************************************************************************\* ** RIVA Mode State Routines ** *\****************************************************************************//* * Calculate the Video Clock parameters for the PLL. */static void CalcVClock(int clockIn, int *clockOut, u32 * pllOut, struct nvidia_par *par){ unsigned lowM, highM; unsigned DeltaNew, DeltaOld; unsigned VClk, Freq; unsigned M, N, P; DeltaOld = 0xFFFFFFFF; VClk = (unsigned)clockIn; if (par->CrystalFreqKHz == 13500) { lowM = 7; highM = 13; } else { lowM = 8; highM = 14; } for (P = 0; P <= 4; P++) { Freq = VClk << P; if ((Freq >= 128000) && (Freq <= 350000)) { for (M = lowM; M <= highM; M++) { N = ((VClk << P) * M) / par->CrystalFreqKHz; if (N <= 255) { Freq = ((par->CrystalFreqKHz * N) / M) >> P; if (Freq > VClk) DeltaNew = Freq - VClk; else DeltaNew = VClk - Freq; if (DeltaNew < DeltaOld) { *pllOut = (P << 16) | (N << 8) | M; *clockOut = Freq; DeltaOld = DeltaNew; } } } } }}static void CalcVClock2Stage(int clockIn, int *clockOut, u32 * pllOut, u32 * pllBOut, struct nvidia_par *par){ unsigned DeltaNew, DeltaOld; unsigned VClk, Freq; unsigned M, N, P; DeltaOld = 0xFFFFFFFF; *pllBOut = 0x80000401; /* fixed at x4 for now */ VClk = (unsigned)clockIn; for (P = 0; P <= 6; P++) { Freq = VClk << P; if ((Freq >= 400000) && (Freq <= 1000000)) { for (M = 1; M <= 13; M++) { N = ((VClk << P) * M) / (par->CrystalFreqKHz << 2); if ((N >= 5) && (N <= 255)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -