rootnv50.c 13 KB

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