Commit 9506140f authored by Ben Skeggs's avatar Ben Skeggs

drm/g94-/disp: calculate some dp audio constants

NVIDIA appear to have tweaked the algorithm from GF110, this implements
the previous algorithm for them still.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 3eee8646
...@@ -1630,7 +1630,7 @@ nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head) ...@@ -1630,7 +1630,7 @@ nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
} }
static void static void
nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head,
struct dcb_output *outp, u32 pclk) struct dcb_output *outp, u32 pclk)
{ {
const int link = !(outp->sorconf.link & 1); const int link = !(outp->sorconf.link & 1);
...@@ -1639,24 +1639,36 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, ...@@ -1639,24 +1639,36 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
const u32 loff = (link * 0x080) + soff; const u32 loff = (link * 0x080) + soff;
const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8)); const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
const u32 symbol = 100000; const u32 symbol = 100000;
u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x0000f0000; const s32 vactive = nv_rd32(priv, 0x610af8 + (head * 0x540)) & 0xffff;
const s32 vblanke = nv_rd32(priv, 0x610ae8 + (head * 0x540)) & 0xffff;
const s32 vblanks = nv_rd32(priv, 0x610af0 + (head * 0x540)) & 0xffff;
u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
u32 clksor = nv_rd32(priv, 0x614300 + soff); u32 clksor = nv_rd32(priv, 0x614300 + soff);
int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
int TU, VTUi, VTUf, VTUa; int TU, VTUi, VTUf, VTUa;
u64 link_data_rate, link_ratio, unk; u64 link_data_rate, link_ratio, unk;
u32 best_diff = 64 * symbol; u32 best_diff = 64 * symbol;
u32 link_nr, link_bw, bits; u32 link_nr, link_bw, bits;
u64 value;
/* calculate packed data rate for each lane */
if (dpctrl > 0x00030000) link_nr = 4; link_bw = (clksor & 0x000c0000) ? 270000 : 162000;
else if (dpctrl > 0x00010000) link_nr = 2; link_nr = hweight32(dpctrl & 0x000f0000);
else link_nr = 1;
/* symbols/hblank - algorithm taken from comments in tegra driver */
if (clksor & 0x000c0000) value = vblanke + vactive - vblanks - 7;
link_bw = 270000; value = value * link_bw;
else do_div(value, pclk);
link_bw = 162000; value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
nv_mask(priv, 0x61c1e8 + soff, 0x0000ffff, value);
/* symbols/vblank - algorithm taken from comments in tegra driver */
value = vblanks - vblanke - 25;
value = value * link_bw;
do_div(value, pclk);
value = value - ((36 / link_nr) + 3) - 1;
nv_mask(priv, 0x61c1ec + soff, 0x00ffffff, value);
/* watermark / activesym */
if ((ctrl & 0xf0000) == 0x60000) bits = 30; if ((ctrl & 0xf0000) == 0x60000) bits = 30;
else if ((ctrl & 0xf0000) == 0x50000) bits = 24; else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
else bits = 18; else bits = 18;
...@@ -1802,7 +1814,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) ...@@ -1802,7 +1814,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
} else } else
if (!outp->info.location) { if (!outp->info.location) {
if (outp->info.type == DCB_OUTPUT_DP) if (outp->info.type == DCB_OUTPUT_DP)
nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk); nv50_disp_intr_unk20_2_dp(priv, head, &outp->info, pclk);
oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800; oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
oval = (conf & 0x0100) ? 0x00000101 : 0x00000000; oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
hval = 0x00000000; hval = 0x00000000;
......
...@@ -976,6 +976,9 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, ...@@ -976,6 +976,9 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
const int or = ffs(outp->or) - 1; const int or = ffs(outp->or) - 1;
const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020)); const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020));
const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300)); const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300));
const s32 vactive = nv_rd32(priv, 0x660414 + (head * 0x300)) & 0xffff;
const s32 vblanke = nv_rd32(priv, 0x66041c + (head * 0x300)) & 0xffff;
const s32 vblanks = nv_rd32(priv, 0x660420 + (head * 0x300)) & 0xffff;
const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1; const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
const u32 hoff = (head * 0x800); const u32 hoff = (head * 0x800);
...@@ -983,23 +986,35 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, ...@@ -983,23 +986,35 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
const u32 loff = (link * 0x080) + soff; const u32 loff = (link * 0x080) + soff;
const u32 symbol = 100000; const u32 symbol = 100000;
const u32 TU = 64; const u32 TU = 64;
u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x000f0000; u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
u32 clksor = nv_rd32(priv, 0x612300 + soff); u32 clksor = nv_rd32(priv, 0x612300 + soff);
u32 datarate, link_nr, link_bw, bits; u32 datarate, link_nr, link_bw, bits;
u64 ratio, value; u64 ratio, value;
link_nr = hweight32(dpctrl & 0x000f0000);
link_bw = (clksor & 0x007c0000) >> 18;
link_bw *= 27000;
/* symbols/hblank - algorithm taken from comments in tegra driver */
value = vblanke + vactive - vblanks - 7;
value = value * link_bw;
do_div(value, pclk);
value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
nv_mask(priv, 0x616620 + hoff, 0x0000ffff, value);
/* symbols/vblank - algorithm taken from comments in tegra driver */
value = vblanks - vblanke - 25;
value = value * link_bw;
do_div(value, pclk);
value = value - ((36 / link_nr) + 3) - 1;
nv_mask(priv, 0x616624 + hoff, 0x00ffffff, value);
/* watermark */
if ((conf & 0x3c0) == 0x180) bits = 30; if ((conf & 0x3c0) == 0x180) bits = 30;
else if ((conf & 0x3c0) == 0x140) bits = 24; else if ((conf & 0x3c0) == 0x140) bits = 24;
else bits = 18; else bits = 18;
datarate = (pclk * bits) / 8; datarate = (pclk * bits) / 8;
if (dpctrl > 0x00030000) link_nr = 4;
else if (dpctrl > 0x00010000) link_nr = 2;
else link_nr = 1;
link_bw = (clksor & 0x007c0000) >> 18;
link_bw *= 27000;
ratio = datarate; ratio = datarate;
ratio *= symbol; ratio *= symbol;
do_div(ratio, link_nr * link_bw); do_div(ratio, link_nr * link_bw);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment