sorgf119.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. * Copyright 2012 Red Hat Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * Authors: Ben Skeggs
  23. */
  24. #include "nv50.h"
  25. #include "outpdp.h"
  26. static inline u32
  27. gf119_sor_soff(struct nvkm_output_dp *outp)
  28. {
  29. return (ffs(outp->base.info.or) - 1) * 0x800;
  30. }
  31. static inline u32
  32. gf119_sor_loff(struct nvkm_output_dp *outp)
  33. {
  34. return gf119_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
  35. }
  36. static int
  37. gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
  38. {
  39. struct nvkm_device *device = outp->base.disp->engine.subdev.device;
  40. const u32 soff = gf119_sor_soff(outp);
  41. nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern);
  42. return 0;
  43. }
  44. int
  45. gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
  46. {
  47. struct nvkm_device *device = outp->base.disp->engine.subdev.device;
  48. const u32 soff = gf119_sor_soff(outp);
  49. const u32 loff = gf119_sor_loff(outp);
  50. u32 dpctrl = 0x00000000;
  51. u32 clksor = 0x00000000;
  52. clksor |= bw << 18;
  53. dpctrl |= ((1 << nr) - 1) << 16;
  54. if (outp->lt.mst)
  55. dpctrl |= 0x40000000;
  56. if (ef)
  57. dpctrl |= 0x00004000;
  58. nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor);
  59. nvkm_mask(device, 0x61c10c + loff, 0x401f4000, dpctrl);
  60. return 0;
  61. }
  62. int
  63. gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp,
  64. int ln, int vs, int pe, int pc)
  65. {
  66. struct nvkm_device *device = outp->base.disp->engine.subdev.device;
  67. struct nvkm_bios *bios = device->bios;
  68. const u32 shift = g94_sor_dp_lane_map(device, ln);
  69. const u32 loff = gf119_sor_loff(outp);
  70. u32 addr, data[4];
  71. u8 ver, hdr, cnt, len;
  72. struct nvbios_dpout info;
  73. struct nvbios_dpcfg ocfg;
  74. addr = nvbios_dpout_match(bios, outp->base.info.hasht,
  75. outp->base.info.hashm,
  76. &ver, &hdr, &cnt, &len, &info);
  77. if (!addr)
  78. return -ENODEV;
  79. addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
  80. &ver, &hdr, &cnt, &len, &ocfg);
  81. if (!addr)
  82. return -EINVAL;
  83. data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift);
  84. data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
  85. data[2] = nvkm_rd32(device, 0x61c130 + loff);
  86. if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
  87. data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
  88. nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
  89. nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
  90. nvkm_wr32(device, 0x61c130 + loff, data[2]);
  91. data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift);
  92. nvkm_wr32(device, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
  93. return 0;
  94. }
  95. void
  96. gf119_sor_dp_vcpi(struct nvkm_output_dp *outp, int head, u8 slot,
  97. u8 slot_nr, u16 pbn, u16 aligned)
  98. {
  99. struct nvkm_device *device = outp->base.disp->engine.subdev.device;
  100. const u32 hoff = head * 0x800;
  101. nvkm_mask(device, 0x616588 + hoff, 0x00003f3f, (slot_nr << 8) | slot);
  102. nvkm_mask(device, 0x61658c + hoff, 0xffffffff, (aligned << 16) | pbn);
  103. }
  104. static const struct nvkm_output_dp_func
  105. gf119_sor_dp_func = {
  106. .pattern = gf119_sor_dp_pattern,
  107. .lnk_pwr = g94_sor_dp_lnk_pwr,
  108. .lnk_ctl = gf119_sor_dp_lnk_ctl,
  109. .drv_ctl = gf119_sor_dp_drv_ctl,
  110. .vcpi = gf119_sor_dp_vcpi,
  111. };
  112. int
  113. gf119_sor_dp_new(struct nvkm_disp *disp, int index,
  114. struct dcb_output *dcbE, struct nvkm_output **poutp)
  115. {
  116. return nvkm_output_dp_new_(&gf119_sor_dp_func, disp, index, dcbE, poutp);
  117. }