2 * Copyright 1993-2003 NVIDIA, Corporation
3 * Copyright 2007-2009 Stuart Bennett
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 #include "nouveau_drv.h"
25 #include "nouveau_reg.h"
28 /****************************************************************************\
30 * The video arbitration routines calculate some "magic" numbers. Fixes *
31 * the snow seen when accessing the framebuffer without it. *
32 * It just works (I hope). *
34 \****************************************************************************/
54 nv04_calc_arb(struct nv_fifo_info
*fifo
, struct nv_sim_state
*arb
)
56 int pagemiss
, cas
, bpp
;
57 int nvclks
, mclks
, crtpagemiss
;
58 int found
, mclk_extra
, mclk_loop
, cbs
, m1
, p1
;
59 int mclk_freq
, pclk_freq
, nvclk_freq
;
60 int us_m
, us_n
, us_p
, crtc_drain_rate
;
61 int cpm_us
, us_crt
, clwm
;
63 pclk_freq
= arb
->pclk_khz
;
64 mclk_freq
= arb
->mclk_khz
;
65 nvclk_freq
= arb
->nvclk_khz
;
66 pagemiss
= arb
->mem_page_miss
;
67 cas
= arb
->mem_latency
;
79 mclk_loop
= mclks
+ mclk_extra
;
80 us_m
= mclk_loop
* 1000 * 1000 / mclk_freq
;
81 us_n
= nvclks
* 1000 * 1000 / nvclk_freq
;
82 us_p
= nvclks
* 1000 * 1000 / pclk_freq
;
84 crtc_drain_rate
= pclk_freq
* bpp
/ 8;
87 cpm_us
= crtpagemiss
* pagemiss
* 1000 * 1000 / mclk_freq
;
88 us_crt
= cpm_us
+ us_m
+ us_n
+ us_p
;
89 clwm
= us_crt
* crtc_drain_rate
/ (1000 * 1000);
92 m1
= clwm
+ cbs
- 512;
93 p1
= m1
* pclk_freq
/ mclk_freq
;
95 if ((p1
< m1
&& m1
> 0) || clwm
> 519) {
108 nv10_calc_arb(struct nv_fifo_info
*fifo
, struct nv_sim_state
*arb
)
110 int fill_rate
, drain_rate
;
111 int pclks
, nvclks
, mclks
, xclks
;
112 int pclk_freq
, nvclk_freq
, mclk_freq
;
113 int fill_lat
, extra_lat
;
114 int max_burst_o
, max_burst_l
;
115 int fifo_len
, min_lwm
, max_lwm
;
116 const int burst_lat
= 80; /* Maximum allowable latency due
117 * to the CRTC FIFO burst. (ns) */
119 pclk_freq
= arb
->pclk_khz
;
120 nvclk_freq
= arb
->nvclk_khz
;
121 mclk_freq
= arb
->mclk_khz
;
123 fill_rate
= mclk_freq
* arb
->memory_width
/ 8; /* kB/s */
124 drain_rate
= pclk_freq
* arb
->bpp
/ 8; /* kB/s */
126 fifo_len
= arb
->two_heads
? 1536 : 1024; /* B */
128 /* Fixed FIFO refill latency. */
130 pclks
= 4; /* lwm detect. */
132 nvclks
= 3 /* lwm -> sync. */
133 + 2 /* fbi bus cycles (1 req + 1 busy) */
134 + 1 /* 2 edge sync. may be very close to edge so
136 + 1 /* fbi_d_rdv_n */
137 + 1 /* Fbi_d_rdata */
138 + 1; /* crtfifo load */
140 mclks
= 1 /* 2 edge sync. may be very close to edge so
143 + 5 /* tiling pipeline */
144 + 2 /* latency fifo */
145 + 2 /* memory request to fbio block */
146 + 7; /* data returned from fbio block */
148 /* Need to accumulate 256 bits for read */
149 mclks
+= (arb
->memory_type
== 0 ? 2 : 1)
150 * arb
->memory_width
/ 32;
152 fill_lat
= mclks
* 1000 * 1000 / mclk_freq
/* minimum mclk latency */
153 + nvclks
* 1000 * 1000 / nvclk_freq
/* nvclk latency */
154 + pclks
* 1000 * 1000 / pclk_freq
; /* pclk latency */
156 /* Conditional FIFO refill latency. */
158 xclks
= 2 * arb
->mem_page_miss
+ mclks
/* Extra latency due to
160 + 2 * arb
->mem_page_miss
/* Extra pagemiss latency. */
161 + (arb
->bpp
== 32 ? 8 : 4); /* Margin of error. */
163 extra_lat
= xclks
* 1000 * 1000 / mclk_freq
;
166 /* Account for another CRTC. */
167 extra_lat
+= fill_lat
+ extra_lat
+ burst_lat
;
171 /* Max burst not leading to overflows. */
172 max_burst_o
= (1 + fifo_len
- extra_lat
* drain_rate
/ (1000 * 1000))
173 * (fill_rate
/ 1000) / ((fill_rate
- drain_rate
) / 1000);
174 fifo
->burst
= min(max_burst_o
, 1024);
176 /* Max burst value with an acceptable latency. */
177 max_burst_l
= burst_lat
* fill_rate
/ (1000 * 1000);
178 fifo
->burst
= min(max_burst_l
, fifo
->burst
);
180 fifo
->burst
= rounddown_pow_of_two(fifo
->burst
);
182 /* FIFO low watermark */
184 min_lwm
= (fill_lat
+ extra_lat
) * drain_rate
/ (1000 * 1000) + 1;
185 max_lwm
= fifo_len
- fifo
->burst
186 + fill_lat
* drain_rate
/ (1000 * 1000)
187 + fifo
->burst
* drain_rate
/ fill_rate
;
189 fifo
->lwm
= min_lwm
+ 10 * (max_lwm
- min_lwm
) / 100; /* Empirical. */
193 nv04_update_arb(struct drm_device
*dev
, int VClk
, int bpp
,
194 int *burst
, int *lwm
)
196 struct nouveau_drm
*drm
= nouveau_drm(dev
);
197 struct nvif_object
*device
= &nouveau_drm(dev
)->client
.device
.object
;
198 struct nv_fifo_info fifo_data
;
199 struct nv_sim_state sim_data
;
200 int MClk
= nouveau_hw_get_clock(dev
, PLL_MEMORY
);
201 int NVClk
= nouveau_hw_get_clock(dev
, PLL_CORE
);
202 uint32_t cfg1
= nvif_rd32(device
, NV04_PFB_CFG1
);
204 sim_data
.pclk_khz
= VClk
;
205 sim_data
.mclk_khz
= MClk
;
206 sim_data
.nvclk_khz
= NVClk
;
208 sim_data
.two_heads
= nv_two_heads(dev
);
209 if ((dev
->pdev
->device
& 0xffff) == 0x01a0 /*CHIPSET_NFORCE*/ ||
210 (dev
->pdev
->device
& 0xffff) == 0x01f0 /*CHIPSET_NFORCE2*/) {
212 int domain
= pci_domain_nr(dev
->pdev
->bus
);
214 pci_read_config_dword(pci_get_domain_bus_and_slot(domain
, 0, 1),
217 sim_data
.memory_type
= (type
>> 12) & 1;
218 sim_data
.memory_width
= 64;
219 sim_data
.mem_latency
= 3;
220 sim_data
.mem_page_miss
= 10;
222 sim_data
.memory_type
= nvif_rd32(device
, NV04_PFB_CFG0
) & 0x1;
223 sim_data
.memory_width
= (nvif_rd32(device
, NV_PEXTDEV_BOOT_0
) & 0x10) ? 128 : 64;
224 sim_data
.mem_latency
= cfg1
& 0xf;
225 sim_data
.mem_page_miss
= ((cfg1
>> 4) & 0xf) + ((cfg1
>> 31) & 0x1);
228 if (drm
->client
.device
.info
.family
== NV_DEVICE_INFO_V0_TNT
)
229 nv04_calc_arb(&fifo_data
, &sim_data
);
231 nv10_calc_arb(&fifo_data
, &sim_data
);
233 *burst
= ilog2(fifo_data
.burst
>> 4);
234 *lwm
= fifo_data
.lwm
>> 3;
238 nv20_update_arb(int *burst
, int *lwm
)
240 unsigned int fifo_size
, burst_size
, graphics_lwm
;
244 graphics_lwm
= fifo_size
- burst_size
;
246 *burst
= ilog2(burst_size
>> 5);
247 *lwm
= graphics_lwm
>> 3;
251 nouveau_calc_arb(struct drm_device
*dev
, int vclk
, int bpp
, int *burst
, int *lwm
)
253 struct nouveau_drm
*drm
= nouveau_drm(dev
);
255 if (drm
->client
.device
.info
.family
< NV_DEVICE_INFO_V0_KELVIN
)
256 nv04_update_arb(dev
, vclk
, bpp
, burst
, lwm
);
257 else if ((dev
->pdev
->device
& 0xfff0) == 0x0240 /*CHIPSET_C51*/ ||
258 (dev
->pdev
->device
& 0xfff0) == 0x03d0 /*CHIPSET_C512*/) {
262 nv20_update_arb(burst
, lwm
);