rootnv50.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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 "rootnv50.h"
  25. #include "dmacnv50.h"
  26. #include <core/client.h>
  27. #include <core/ramht.h>
  28. #include <subdev/timer.h>
  29. #include <nvif/class.h>
  30. #include <nvif/unpack.h>
  31. int
  32. nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0)
  33. {
  34. struct nvkm_device *device = disp->base.engine.subdev.device;
  35. const u32 blanke = nvkm_rd32(device, 0x610aec + (head * 0x540));
  36. const u32 blanks = nvkm_rd32(device, 0x610af4 + (head * 0x540));
  37. const u32 total = nvkm_rd32(device, 0x610afc + (head * 0x540));
  38. union {
  39. struct nv04_disp_scanoutpos_v0 v0;
  40. } *args = data;
  41. int ret;
  42. nvif_ioctl(object, "disp scanoutpos size %d\n", size);
  43. if (nvif_unpack(args->v0, 0, 0, false)) {
  44. nvif_ioctl(object, "disp scanoutpos vers %d\n",
  45. args->v0.version);
  46. args->v0.vblanke = (blanke & 0xffff0000) >> 16;
  47. args->v0.hblanke = (blanke & 0x0000ffff);
  48. args->v0.vblanks = (blanks & 0xffff0000) >> 16;
  49. args->v0.hblanks = (blanks & 0x0000ffff);
  50. args->v0.vtotal = ( total & 0xffff0000) >> 16;
  51. args->v0.htotal = ( total & 0x0000ffff);
  52. args->v0.time[0] = ktime_to_ns(ktime_get());
  53. args->v0.vline = /* vline read locks hline */
  54. nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff;
  55. args->v0.time[1] = ktime_to_ns(ktime_get());
  56. args->v0.hline =
  57. nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff;
  58. } else
  59. return ret;
  60. return 0;
  61. }
  62. int
  63. nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
  64. {
  65. union {
  66. struct nv50_disp_mthd_v0 v0;
  67. struct nv50_disp_mthd_v1 v1;
  68. } *args = data;
  69. struct nv50_disp_root *root = nv50_disp_root(object);
  70. struct nv50_disp *disp = root->disp;
  71. const struct nv50_disp_func *func = disp->func;
  72. struct nvkm_output *outp = NULL;
  73. struct nvkm_output *temp;
  74. u16 type, mask = 0;
  75. int head, ret;
  76. if (mthd != NV50_DISP_MTHD)
  77. return -EINVAL;
  78. nvif_ioctl(object, "disp mthd size %d\n", size);
  79. if (nvif_unpack(args->v0, 0, 0, true)) {
  80. nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
  81. args->v0.version, args->v0.method, args->v0.head);
  82. mthd = args->v0.method;
  83. head = args->v0.head;
  84. } else
  85. if (nvif_unpack(args->v1, 1, 1, true)) {
  86. nvif_ioctl(object, "disp mthd vers %d mthd %02x "
  87. "type %04x mask %04x\n",
  88. args->v1.version, args->v1.method,
  89. args->v1.hasht, args->v1.hashm);
  90. mthd = args->v1.method;
  91. type = args->v1.hasht;
  92. mask = args->v1.hashm;
  93. head = ffs((mask >> 8) & 0x0f) - 1;
  94. } else
  95. return ret;
  96. if (head < 0 || head >= disp->base.head.nr)
  97. return -ENXIO;
  98. if (mask) {
  99. list_for_each_entry(temp, &disp->base.outp, head) {
  100. if ((temp->info.hasht == type) &&
  101. (temp->info.hashm & mask) == mask) {
  102. outp = temp;
  103. break;
  104. }
  105. }
  106. if (outp == NULL)
  107. return -ENXIO;
  108. }
  109. switch (mthd) {
  110. case NV50_DISP_SCANOUTPOS:
  111. return func->head.scanoutpos(object, disp, data, size, head);
  112. default:
  113. break;
  114. }
  115. switch (mthd * !!outp) {
  116. case NV50_DISP_MTHD_V1_DAC_PWR:
  117. return func->dac.power(object, disp, data, size, head, outp);
  118. case NV50_DISP_MTHD_V1_DAC_LOAD:
  119. return func->dac.sense(object, disp, data, size, head, outp);
  120. case NV50_DISP_MTHD_V1_SOR_PWR:
  121. return func->sor.power(object, disp, data, size, head, outp);
  122. case NV50_DISP_MTHD_V1_SOR_HDA_ELD:
  123. if (!func->sor.hda_eld)
  124. return -ENODEV;
  125. return func->sor.hda_eld(object, disp, data, size, head, outp);
  126. case NV50_DISP_MTHD_V1_SOR_HDMI_PWR:
  127. if (!func->sor.hdmi)
  128. return -ENODEV;
  129. return func->sor.hdmi(object, disp, data, size, head, outp);
  130. case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
  131. union {
  132. struct nv50_disp_sor_lvds_script_v0 v0;
  133. } *args = data;
  134. nvif_ioctl(object, "disp sor lvds script size %d\n", size);
  135. if (nvif_unpack(args->v0, 0, 0, false)) {
  136. nvif_ioctl(object, "disp sor lvds script "
  137. "vers %d name %04x\n",
  138. args->v0.version, args->v0.script);
  139. disp->sor.lvdsconf = args->v0.script;
  140. return 0;
  141. } else
  142. return ret;
  143. }
  144. break;
  145. case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
  146. struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
  147. union {
  148. struct nv50_disp_sor_dp_pwr_v0 v0;
  149. } *args = data;
  150. nvif_ioctl(object, "disp sor dp pwr size %d\n", size);
  151. if (nvif_unpack(args->v0, 0, 0, false)) {
  152. nvif_ioctl(object, "disp sor dp pwr vers %d state %d\n",
  153. args->v0.version, args->v0.state);
  154. if (args->v0.state == 0) {
  155. nvkm_notify_put(&outpdp->irq);
  156. outpdp->func->lnk_pwr(outpdp, 0);
  157. atomic_set(&outpdp->lt.done, 0);
  158. return 0;
  159. } else
  160. if (args->v0.state != 0) {
  161. nvkm_output_dp_train(&outpdp->base, 0, true);
  162. return 0;
  163. }
  164. } else
  165. return ret;
  166. }
  167. break;
  168. case NV50_DISP_MTHD_V1_PIOR_PWR:
  169. if (!func->pior.power)
  170. return -ENODEV;
  171. return func->pior.power(object, disp, data, size, head, outp);
  172. default:
  173. break;
  174. }
  175. return -EINVAL;
  176. }
  177. static int
  178. nv50_disp_root_dmac_new_(const struct nvkm_oclass *oclass,
  179. void *data, u32 size, struct nvkm_object **pobject)
  180. {
  181. const struct nv50_disp_dmac_oclass *sclass = oclass->priv;
  182. struct nv50_disp_root *root = nv50_disp_root(oclass->parent);
  183. return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid,
  184. oclass, data, size, pobject);
  185. }
  186. static int
  187. nv50_disp_root_pioc_new_(const struct nvkm_oclass *oclass,
  188. void *data, u32 size, struct nvkm_object **pobject)
  189. {
  190. const struct nv50_disp_pioc_oclass *sclass = oclass->priv;
  191. struct nv50_disp_root *root = nv50_disp_root(oclass->parent);
  192. return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid,
  193. oclass, data, size, pobject);
  194. }
  195. static int
  196. nv50_disp_root_child_get_(struct nvkm_object *object, int index,
  197. struct nvkm_oclass *sclass)
  198. {
  199. struct nv50_disp_root *root = nv50_disp_root(object);
  200. if (index < ARRAY_SIZE(root->func->dmac)) {
  201. sclass->base = root->func->dmac[index]->base;
  202. sclass->priv = root->func->dmac[index];
  203. sclass->ctor = nv50_disp_root_dmac_new_;
  204. return 0;
  205. }
  206. index -= ARRAY_SIZE(root->func->dmac);
  207. if (index < ARRAY_SIZE(root->func->pioc)) {
  208. sclass->base = root->func->pioc[index]->base;
  209. sclass->priv = root->func->pioc[index];
  210. sclass->ctor = nv50_disp_root_pioc_new_;
  211. return 0;
  212. }
  213. return -EINVAL;
  214. }
  215. static int
  216. nv50_disp_root_fini_(struct nvkm_object *object, bool suspend)
  217. {
  218. struct nv50_disp_root *root = nv50_disp_root(object);
  219. root->func->fini(root);
  220. return 0;
  221. }
  222. static int
  223. nv50_disp_root_init_(struct nvkm_object *object)
  224. {
  225. struct nv50_disp_root *root = nv50_disp_root(object);
  226. return root->func->init(root);
  227. }
  228. static void *
  229. nv50_disp_root_dtor_(struct nvkm_object *object)
  230. {
  231. struct nv50_disp_root *root = nv50_disp_root(object);
  232. nvkm_ramht_del(&root->ramht);
  233. nvkm_gpuobj_del(&root->instmem);
  234. return root;
  235. }
  236. static const struct nvkm_object_func
  237. nv50_disp_root_ = {
  238. .dtor = nv50_disp_root_dtor_,
  239. .init = nv50_disp_root_init_,
  240. .fini = nv50_disp_root_fini_,
  241. .mthd = nv50_disp_root_mthd_,
  242. .ntfy = nvkm_disp_ntfy,
  243. .sclass = nv50_disp_root_child_get_,
  244. };
  245. int
  246. nv50_disp_root_new_(const struct nv50_disp_root_func *func,
  247. struct nvkm_disp *base, const struct nvkm_oclass *oclass,
  248. void *data, u32 size, struct nvkm_object **pobject)
  249. {
  250. struct nv50_disp *disp = nv50_disp(base);
  251. struct nv50_disp_root *root;
  252. struct nvkm_device *device = disp->base.engine.subdev.device;
  253. int ret;
  254. if (!(root = kzalloc(sizeof(*root), GFP_KERNEL)))
  255. return -ENOMEM;
  256. *pobject = &root->object;
  257. nvkm_object_ctor(&nv50_disp_root_, oclass, &root->object);
  258. root->func = func;
  259. root->disp = disp;
  260. ret = nvkm_gpuobj_new(disp->base.engine.subdev.device, 0x10000, 0x10000,
  261. false, NULL, &root->instmem);
  262. if (ret)
  263. return ret;
  264. return nvkm_ramht_new(device, 0x1000, 0, root->instmem, &root->ramht);
  265. }
  266. void
  267. nv50_disp_root_fini(struct nv50_disp_root *root)
  268. {
  269. struct nvkm_device *device = root->disp->base.engine.subdev.device;
  270. /* disable all interrupts */
  271. nvkm_wr32(device, 0x610024, 0x00000000);
  272. nvkm_wr32(device, 0x610020, 0x00000000);
  273. }
  274. int
  275. nv50_disp_root_init(struct nv50_disp_root *root)
  276. {
  277. struct nv50_disp *disp = root->disp;
  278. struct nvkm_device *device = disp->base.engine.subdev.device;
  279. u32 tmp;
  280. int i;
  281. /* The below segments of code copying values from one register to
  282. * another appear to inform EVO of the display capabilities or
  283. * something similar. NFI what the 0x614004 caps are for..
  284. */
  285. tmp = nvkm_rd32(device, 0x614004);
  286. nvkm_wr32(device, 0x610184, tmp);
  287. /* ... CRTC caps */
  288. for (i = 0; i < disp->base.head.nr; i++) {
  289. tmp = nvkm_rd32(device, 0x616100 + (i * 0x800));
  290. nvkm_wr32(device, 0x610190 + (i * 0x10), tmp);
  291. tmp = nvkm_rd32(device, 0x616104 + (i * 0x800));
  292. nvkm_wr32(device, 0x610194 + (i * 0x10), tmp);
  293. tmp = nvkm_rd32(device, 0x616108 + (i * 0x800));
  294. nvkm_wr32(device, 0x610198 + (i * 0x10), tmp);
  295. tmp = nvkm_rd32(device, 0x61610c + (i * 0x800));
  296. nvkm_wr32(device, 0x61019c + (i * 0x10), tmp);
  297. }
  298. /* ... DAC caps */
  299. for (i = 0; i < disp->func->dac.nr; i++) {
  300. tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800));
  301. nvkm_wr32(device, 0x6101d0 + (i * 0x04), tmp);
  302. }
  303. /* ... SOR caps */
  304. for (i = 0; i < disp->func->sor.nr; i++) {
  305. tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800));
  306. nvkm_wr32(device, 0x6101e0 + (i * 0x04), tmp);
  307. }
  308. /* ... PIOR caps */
  309. for (i = 0; i < disp->func->pior.nr; i++) {
  310. tmp = nvkm_rd32(device, 0x61e000 + (i * 0x800));
  311. nvkm_wr32(device, 0x6101f0 + (i * 0x04), tmp);
  312. }
  313. /* steal display away from vbios, or something like that */
  314. if (nvkm_rd32(device, 0x610024) & 0x00000100) {
  315. nvkm_wr32(device, 0x610024, 0x00000100);
  316. nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000);
  317. if (nvkm_msec(device, 2000,
  318. if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002))
  319. break;
  320. ) < 0)
  321. return -EBUSY;
  322. }
  323. /* point at display engine memory area (hash table, objects) */
  324. nvkm_wr32(device, 0x610010, (root->instmem->addr >> 8) | 9);
  325. /* enable supervisor interrupts, disable everything else */
  326. nvkm_wr32(device, 0x61002c, 0x00000370);
  327. nvkm_wr32(device, 0x610028, 0x00000000);
  328. return 0;
  329. }
  330. static const struct nv50_disp_root_func
  331. nv50_disp_root = {
  332. .init = nv50_disp_root_init,
  333. .fini = nv50_disp_root_fini,
  334. .dmac = {
  335. &nv50_disp_core_oclass,
  336. &nv50_disp_base_oclass,
  337. &nv50_disp_ovly_oclass,
  338. },
  339. .pioc = {
  340. &nv50_disp_oimm_oclass,
  341. &nv50_disp_curs_oclass,
  342. },
  343. };
  344. static int
  345. nv50_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
  346. void *data, u32 size, struct nvkm_object **pobject)
  347. {
  348. return nv50_disp_root_new_(&nv50_disp_root, disp, oclass,
  349. data, size, pobject);
  350. }
  351. const struct nvkm_disp_oclass
  352. nv50_disp_root_oclass = {
  353. .base.oclass = NV50_DISP,
  354. .base.minver = -1,
  355. .base.maxver = -1,
  356. .ctor = nv50_disp_root_new,
  357. };