modetest.c 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404
  1. /*
  2. * DRM based mode setting test program
  3. * Copyright 2008 Tungsten Graphics
  4. * Jakob Bornecrantz <jakob@tungstengraphics.com>
  5. * Copyright 2008 Intel Corporation
  6. * Jesse Barnes <jesse.barnes@intel.com>
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a
  9. * copy of this software and associated documentation files (the "Software"),
  10. * to deal in the Software without restriction, including without limitation
  11. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12. * and/or sell copies of the Software, and to permit persons to whom the
  13. * Software is furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  24. * IN THE SOFTWARE.
  25. */
  26. /*
  27. * This fairly simple test program dumps output in a similar format to the
  28. * "xrandr" tool everyone knows & loves. It's necessarily slightly different
  29. * since the kernel separates outputs into encoder and connector structures,
  30. * each with their own unique ID. The program also allows test testing of the
  31. * memory management and mode setting APIs by allowing the user to specify a
  32. * connector and mode to use for mode setting. If all works as expected, a
  33. * blue background should be painted on the monitor attached to the specified
  34. * connector after the selected mode is set.
  35. *
  36. * TODO: use cairo to write the mode info on the selected output once
  37. * the mode has been programmed, along with possible test patterns.
  38. */
  39. #include <assert.h>
  40. #include <ctype.h>
  41. #include <stdbool.h>
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <stdint.h>
  45. #include <inttypes.h>
  46. #include <unistd.h>
  47. #include <string.h>
  48. #include <strings.h>
  49. #include <errno.h>
  50. #include <poll.h>
  51. #include <sys/time.h>
  52. #if HAVE_SYS_SELECT_H
  53. #include <sys/select.h>
  54. #endif
  55. #include <math.h>
  56. #include "xf86drm.h"
  57. #include "xf86drmMode.h"
  58. #include "drm_fourcc.h"
  59. #include "util/common.h"
  60. #include "util/format.h"
  61. #include "util/kms.h"
  62. #include "util/pattern.h"
  63. #include "buffers.h"
  64. #include "cursor.h"
  65. #include "process_linker_types.h"
  66. #define DPU_PRINT(level, ...) \
  67. { \
  68. if (log_level >= DPU_LOG_##level) \
  69. { \
  70. struct timeval ts; \
  71. gettimeofday(&ts, 0); \
  72. printf("DPU[%d][%ld.%06ld] %s: ", pid, ts.tv_sec, ts.tv_usec, #level); \
  73. printf(__VA_ARGS__); \
  74. } \
  75. }
  76. typedef enum _DpuLogLevel
  77. {
  78. DPU_LOG_QUIET = 0,
  79. DPU_LOG_ERROR,
  80. DPU_LOG_WARNING,
  81. DPU_LOG_INFO,
  82. DPU_LOG_DEBUG,
  83. DPU_LOG_TRACE,
  84. DPU_LOG_MAX
  85. } DpuLogLevel;
  86. static enum util_fill_pattern primary_fill = UTIL_PATTERN_SMPTE;
  87. static enum util_fill_pattern secondary_fill = UTIL_PATTERN_TILES;
  88. static int log_level = DPU_LOG_ERROR;
  89. static int pid = 0;
  90. int g_prime_fd;
  91. struct crtc {
  92. drmModeCrtc *crtc;
  93. drmModeObjectProperties *props;
  94. drmModePropertyRes **props_info;
  95. drmModeModeInfo *mode;
  96. };
  97. struct encoder {
  98. drmModeEncoder *encoder;
  99. };
  100. struct connector {
  101. drmModeConnector *connector;
  102. drmModeObjectProperties *props;
  103. drmModePropertyRes **props_info;
  104. char *name;
  105. };
  106. struct fb {
  107. drmModeFB *fb;
  108. };
  109. struct plane {
  110. drmModePlane *plane;
  111. drmModeObjectProperties *props;
  112. drmModePropertyRes **props_info;
  113. };
  114. struct resources {
  115. drmModeRes *res;
  116. drmModePlaneRes *plane_res;
  117. struct crtc *crtcs;
  118. struct encoder *encoders;
  119. struct connector *connectors;
  120. struct fb *fbs;
  121. struct plane *planes;
  122. };
  123. struct device {
  124. int fd;
  125. struct resources *resources;
  126. struct {
  127. unsigned int width;
  128. unsigned int height;
  129. unsigned int fb_id;
  130. struct bo *bo;
  131. struct bo *cursor_bo;
  132. } mode;
  133. int use_atomic;
  134. drmModeAtomicReq *req;
  135. };
  136. static inline int64_t U642I64(uint64_t val)
  137. {
  138. return (int64_t)*((int64_t *)&val);
  139. }
  140. static float mode_vrefresh(drmModeModeInfo *mode)
  141. {
  142. return mode->clock * 1000.00
  143. / (mode->htotal * mode->vtotal);
  144. }
  145. #define bit_name_fn(res) \
  146. const char * res##_str(int type) { \
  147. unsigned int i; \
  148. const char *sep = ""; \
  149. for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
  150. if (type & (1 << i)) { \
  151. printf("%s%s", sep, res##_names[i]); \
  152. sep = ", "; \
  153. } \
  154. } \
  155. return NULL; \
  156. }
  157. static const char *mode_type_names[] = {
  158. "builtin",
  159. "clock_c",
  160. "crtc_c",
  161. "preferred",
  162. "default",
  163. "userdef",
  164. "driver",
  165. };
  166. static bit_name_fn(mode_type)
  167. static const char *mode_flag_names[] = {
  168. "phsync",
  169. "nhsync",
  170. "pvsync",
  171. "nvsync",
  172. "interlace",
  173. "dblscan",
  174. "csync",
  175. "pcsync",
  176. "ncsync",
  177. "hskew",
  178. "bcast",
  179. "pixmux",
  180. "dblclk",
  181. "clkdiv2"
  182. };
  183. static bit_name_fn(mode_flag)
  184. static void dump_fourcc(uint32_t fourcc)
  185. {
  186. printf(" %c%c%c%c",
  187. fourcc,
  188. fourcc >> 8,
  189. fourcc >> 16,
  190. fourcc >> 24);
  191. }
  192. static void dump_encoders(struct device *dev)
  193. {
  194. drmModeEncoder *encoder;
  195. int i;
  196. printf("Encoders:\n");
  197. printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
  198. for (i = 0; i < dev->resources->res->count_encoders; i++) {
  199. encoder = dev->resources->encoders[i].encoder;
  200. if (!encoder)
  201. continue;
  202. printf("%d\t%d\t%s\t0x%08x\t0x%08x\n",
  203. encoder->encoder_id,
  204. encoder->crtc_id,
  205. util_lookup_encoder_type_name(encoder->encoder_type),
  206. encoder->possible_crtcs,
  207. encoder->possible_clones);
  208. }
  209. printf("\n");
  210. }
  211. static void dump_mode(drmModeModeInfo *mode, int index)
  212. {
  213. printf(" #%i %s %.2f %d %d %d %d %d %d %d %d %d",
  214. index,
  215. mode->name,
  216. mode_vrefresh(mode),
  217. mode->hdisplay,
  218. mode->hsync_start,
  219. mode->hsync_end,
  220. mode->htotal,
  221. mode->vdisplay,
  222. mode->vsync_start,
  223. mode->vsync_end,
  224. mode->vtotal,
  225. mode->clock);
  226. printf(" flags: ");
  227. mode_flag_str(mode->flags);
  228. printf("; type: ");
  229. mode_type_str(mode->type);
  230. printf("\n");
  231. }
  232. static void dump_blob(struct device *dev, uint32_t blob_id)
  233. {
  234. uint32_t i;
  235. unsigned char *blob_data;
  236. drmModePropertyBlobPtr blob;
  237. blob = drmModeGetPropertyBlob(dev->fd, blob_id);
  238. if (!blob) {
  239. printf("\n");
  240. return;
  241. }
  242. blob_data = blob->data;
  243. for (i = 0; i < blob->length; i++) {
  244. if (i % 16 == 0)
  245. printf("\n\t\t\t");
  246. printf("%.2hhx", blob_data[i]);
  247. }
  248. printf("\n");
  249. drmModeFreePropertyBlob(blob);
  250. }
  251. static const char *modifier_to_string(uint64_t modifier)
  252. {
  253. switch (modifier) {
  254. case DRM_FORMAT_MOD_INVALID:
  255. return "INVALID";
  256. case DRM_FORMAT_MOD_LINEAR:
  257. return "LINEAR";
  258. case I915_FORMAT_MOD_X_TILED:
  259. return "X_TILED";
  260. case I915_FORMAT_MOD_Y_TILED:
  261. return "Y_TILED";
  262. case I915_FORMAT_MOD_Yf_TILED:
  263. return "Yf_TILED";
  264. case I915_FORMAT_MOD_Y_TILED_CCS:
  265. return "Y_TILED_CCS";
  266. case I915_FORMAT_MOD_Yf_TILED_CCS:
  267. return "Yf_TILED_CCS";
  268. case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
  269. return "SAMSUNG_64_32_TILE";
  270. case DRM_FORMAT_MOD_VIVANTE_TILED:
  271. return "VIVANTE_TILED";
  272. case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
  273. return "VIVANTE_SUPER_TILED";
  274. case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
  275. return "VIVANTE_SPLIT_TILED";
  276. case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
  277. return "VIVANTE_SPLIT_SUPER_TILED";
  278. case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED:
  279. return "NVIDIA_TEGRA_TILED";
  280. case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0):
  281. return "NVIDIA_16BX2_BLOCK(0)";
  282. case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1):
  283. return "NVIDIA_16BX2_BLOCK(1)";
  284. case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2):
  285. return "NVIDIA_16BX2_BLOCK(2)";
  286. case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3):
  287. return "NVIDIA_16BX2_BLOCK(3)";
  288. case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4):
  289. return "NVIDIA_16BX2_BLOCK(4)";
  290. case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5):
  291. return "NVIDIA_16BX2_BLOCK(5)";
  292. case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
  293. return "MOD_BROADCOM_VC4_T_TILED";
  294. case DRM_FORMAT_MOD_QCOM_COMPRESSED:
  295. return "QCOM_COMPRESSED";
  296. default:
  297. return "(UNKNOWN MODIFIER)";
  298. }
  299. }
  300. static void dump_in_formats(struct device *dev, uint32_t blob_id)
  301. {
  302. uint32_t i, j;
  303. drmModePropertyBlobPtr blob;
  304. struct drm_format_modifier_blob *header;
  305. uint32_t *formats;
  306. struct drm_format_modifier *modifiers;
  307. printf("\t\tin_formats blob decoded:\n");
  308. blob = drmModeGetPropertyBlob(dev->fd, blob_id);
  309. if (!blob) {
  310. printf("\n");
  311. return;
  312. }
  313. header = blob->data;
  314. formats = (uint32_t *) ((char *) header + header->formats_offset);
  315. modifiers = (struct drm_format_modifier *)
  316. ((char *) header + header->modifiers_offset);
  317. for (i = 0; i < header->count_formats; i++) {
  318. printf("\t\t\t");
  319. dump_fourcc(formats[i]);
  320. printf(": ");
  321. for (j = 0; j < header->count_modifiers; j++) {
  322. uint64_t mask = 1ULL << i;
  323. if (modifiers[j].formats & mask)
  324. printf(" %s", modifier_to_string(modifiers[j].modifier));
  325. }
  326. printf("\n");
  327. }
  328. drmModeFreePropertyBlob(blob);
  329. }
  330. static void dump_prop(struct device *dev, drmModePropertyPtr prop,
  331. uint32_t prop_id, uint64_t value)
  332. {
  333. int i;
  334. printf("\t%d", prop_id);
  335. if (!prop) {
  336. printf("\n");
  337. return;
  338. }
  339. printf(" %s:\n", prop->name);
  340. printf("\t\tflags:");
  341. if (prop->flags & DRM_MODE_PROP_PENDING)
  342. printf(" pending");
  343. if (prop->flags & DRM_MODE_PROP_IMMUTABLE)
  344. printf(" immutable");
  345. if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
  346. printf(" signed range");
  347. if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE))
  348. printf(" range");
  349. if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM))
  350. printf(" enum");
  351. if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK))
  352. printf(" bitmask");
  353. if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
  354. printf(" blob");
  355. if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT))
  356. printf(" object");
  357. printf("\n");
  358. if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) {
  359. printf("\t\tvalues:");
  360. for (i = 0; i < prop->count_values; i++)
  361. printf(" %"PRId64, U642I64(prop->values[i]));
  362. printf("\n");
  363. }
  364. if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) {
  365. printf("\t\tvalues:");
  366. for (i = 0; i < prop->count_values; i++)
  367. printf(" %"PRIu64, prop->values[i]);
  368. printf("\n");
  369. }
  370. if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) {
  371. printf("\t\tenums:");
  372. for (i = 0; i < prop->count_enums; i++)
  373. printf(" %s=%llu", prop->enums[i].name,
  374. prop->enums[i].value);
  375. printf("\n");
  376. } else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
  377. printf("\t\tvalues:");
  378. for (i = 0; i < prop->count_enums; i++)
  379. printf(" %s=0x%llx", prop->enums[i].name,
  380. (1LL << prop->enums[i].value));
  381. printf("\n");
  382. } else {
  383. assert(prop->count_enums == 0);
  384. }
  385. if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) {
  386. printf("\t\tblobs:\n");
  387. for (i = 0; i < prop->count_blobs; i++)
  388. dump_blob(dev, prop->blob_ids[i]);
  389. printf("\n");
  390. } else {
  391. assert(prop->count_blobs == 0);
  392. }
  393. printf("\t\tvalue:");
  394. if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
  395. dump_blob(dev, value);
  396. else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
  397. printf(" %"PRId64"\n", value);
  398. else
  399. printf(" %"PRIu64"\n", value);
  400. if (strcmp(prop->name, "IN_FORMATS") == 0)
  401. dump_in_formats(dev, value);
  402. }
  403. static void dump_connectors(struct device *dev)
  404. {
  405. int i, j;
  406. printf("Connectors:\n");
  407. printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n");
  408. for (i = 0; i < dev->resources->res->count_connectors; i++) {
  409. struct connector *_connector = &dev->resources->connectors[i];
  410. drmModeConnector *connector = _connector->connector;
  411. if (!connector)
  412. continue;
  413. printf("%d\t%d\t%s\t%-15s\t%dx%d\t\t%d\t",
  414. connector->connector_id,
  415. connector->encoder_id,
  416. util_lookup_connector_status_name(connector->connection),
  417. _connector->name,
  418. connector->mmWidth, connector->mmHeight,
  419. connector->count_modes);
  420. for (j = 0; j < connector->count_encoders; j++)
  421. printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]);
  422. printf("\n");
  423. if (connector->count_modes) {
  424. printf(" modes:\n");
  425. printf("\tindex name refresh (Hz) hdisp hss hse htot vdisp "
  426. "vss vse vtot)\n");
  427. for (j = 0; j < connector->count_modes; j++)
  428. dump_mode(&connector->modes[j], j);
  429. }
  430. if (_connector->props) {
  431. printf(" props:\n");
  432. for (j = 0; j < (int)_connector->props->count_props; j++)
  433. dump_prop(dev, _connector->props_info[j],
  434. _connector->props->props[j],
  435. _connector->props->prop_values[j]);
  436. }
  437. }
  438. printf("\n");
  439. }
  440. static void dump_crtcs(struct device *dev)
  441. {
  442. int i;
  443. uint32_t j;
  444. printf("CRTCs:\n");
  445. printf("id\tfb\tpos\tsize\n");
  446. for (i = 0; i < dev->resources->res->count_crtcs; i++) {
  447. struct crtc *_crtc = &dev->resources->crtcs[i];
  448. drmModeCrtc *crtc = _crtc->crtc;
  449. if (!crtc)
  450. continue;
  451. printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
  452. crtc->crtc_id,
  453. crtc->buffer_id,
  454. crtc->x, crtc->y,
  455. crtc->width, crtc->height);
  456. dump_mode(&crtc->mode, 0);
  457. if (_crtc->props) {
  458. printf(" props:\n");
  459. for (j = 0; j < _crtc->props->count_props; j++)
  460. dump_prop(dev, _crtc->props_info[j],
  461. _crtc->props->props[j],
  462. _crtc->props->prop_values[j]);
  463. } else {
  464. printf(" no properties found\n");
  465. }
  466. }
  467. printf("\n");
  468. }
  469. static void dump_framebuffers(struct device *dev)
  470. {
  471. drmModeFB *fb;
  472. int i;
  473. printf("Frame buffers:\n");
  474. printf("id\tsize\tpitch\n");
  475. for (i = 0; i < dev->resources->res->count_fbs; i++) {
  476. fb = dev->resources->fbs[i].fb;
  477. if (!fb)
  478. continue;
  479. printf("%u\t(%ux%u)\t%u\n",
  480. fb->fb_id,
  481. fb->width, fb->height,
  482. fb->pitch);
  483. }
  484. printf("\n");
  485. }
  486. static void dump_planes(struct device *dev)
  487. {
  488. unsigned int i, j;
  489. printf("Planes:\n");
  490. printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");
  491. if (!dev->resources->plane_res)
  492. return;
  493. for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
  494. struct plane *plane = &dev->resources->planes[i];
  495. drmModePlane *ovr = plane->plane;
  496. if (!ovr)
  497. continue;
  498. printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n",
  499. ovr->plane_id, ovr->crtc_id, ovr->fb_id,
  500. ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
  501. ovr->gamma_size, ovr->possible_crtcs);
  502. if (!ovr->count_formats)
  503. continue;
  504. printf(" formats:");
  505. for (j = 0; j < ovr->count_formats; j++)
  506. dump_fourcc(ovr->formats[j]);
  507. printf("\n");
  508. if (plane->props) {
  509. printf(" props:\n");
  510. for (j = 0; j < plane->props->count_props; j++)
  511. dump_prop(dev, plane->props_info[j],
  512. plane->props->props[j],
  513. plane->props->prop_values[j]);
  514. } else {
  515. printf(" no properties found\n");
  516. }
  517. }
  518. printf("\n");
  519. return;
  520. }
  521. static void free_resources(struct resources *res)
  522. {
  523. int i;
  524. if (!res)
  525. return;
  526. #define free_resource(_res, __res, type, Type) \
  527. do { \
  528. if (!(_res)->type##s) \
  529. break; \
  530. for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
  531. if (!(_res)->type##s[i].type) \
  532. break; \
  533. drmModeFree##Type((_res)->type##s[i].type); \
  534. } \
  535. free((_res)->type##s); \
  536. } while (0)
  537. #define free_properties(_res, __res, type) \
  538. do { \
  539. for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
  540. drmModeFreeObjectProperties(res->type##s[i].props); \
  541. free(res->type##s[i].props_info); \
  542. } \
  543. } while (0)
  544. if (res->res) {
  545. free_properties(res, res, crtc);
  546. free_resource(res, res, crtc, Crtc);
  547. free_resource(res, res, encoder, Encoder);
  548. for (i = 0; i < res->res->count_connectors; i++)
  549. free(res->connectors[i].name);
  550. free_resource(res, res, connector, Connector);
  551. free_resource(res, res, fb, FB);
  552. drmModeFreeResources(res->res);
  553. }
  554. if (res->plane_res) {
  555. free_properties(res, plane_res, plane);
  556. free_resource(res, plane_res, plane, Plane);
  557. drmModeFreePlaneResources(res->plane_res);
  558. }
  559. free(res);
  560. }
  561. static struct resources *get_resources(struct device *dev)
  562. {
  563. struct resources *res;
  564. int i;
  565. res = calloc(1, sizeof(*res));
  566. if (res == 0)
  567. return NULL;
  568. drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
  569. res->res = drmModeGetResources(dev->fd);
  570. if (!res->res) {
  571. fprintf(stderr, "drmModeGetResources failed: %s\n",
  572. strerror(errno));
  573. goto error;
  574. }
  575. res->crtcs = calloc(res->res->count_crtcs, sizeof(*res->crtcs));
  576. res->encoders = calloc(res->res->count_encoders, sizeof(*res->encoders));
  577. res->connectors = calloc(res->res->count_connectors, sizeof(*res->connectors));
  578. res->fbs = calloc(res->res->count_fbs, sizeof(*res->fbs));
  579. if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs)
  580. goto error;
  581. #define get_resource(_res, __res, type, Type) \
  582. do { \
  583. for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
  584. (_res)->type##s[i].type = \
  585. drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \
  586. if (!(_res)->type##s[i].type) \
  587. fprintf(stderr, "could not get %s %i: %s\n", \
  588. #type, (_res)->__res->type##s[i], \
  589. strerror(errno)); \
  590. } \
  591. } while (0)
  592. get_resource(res, res, crtc, Crtc);
  593. get_resource(res, res, encoder, Encoder);
  594. get_resource(res, res, connector, Connector);
  595. get_resource(res, res, fb, FB);
  596. /* Set the name of all connectors based on the type name and the per-type ID. */
  597. for (i = 0; i < res->res->count_connectors; i++) {
  598. struct connector *connector = &res->connectors[i];
  599. drmModeConnector *conn = connector->connector;
  600. int num;
  601. num = asprintf(&connector->name, "%s-%u",
  602. util_lookup_connector_type_name(conn->connector_type),
  603. conn->connector_type_id);
  604. if (num < 0)
  605. goto error;
  606. }
  607. #define get_properties(_res, __res, type, Type) \
  608. do { \
  609. for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
  610. struct type *obj = &res->type##s[i]; \
  611. unsigned int j; \
  612. obj->props = \
  613. drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \
  614. DRM_MODE_OBJECT_##Type); \
  615. if (!obj->props) { \
  616. fprintf(stderr, \
  617. "could not get %s %i properties: %s\n", \
  618. #type, obj->type->type##_id, \
  619. strerror(errno)); \
  620. continue; \
  621. } \
  622. obj->props_info = calloc(obj->props->count_props, \
  623. sizeof(*obj->props_info)); \
  624. if (!obj->props_info) \
  625. continue; \
  626. for (j = 0; j < obj->props->count_props; ++j) \
  627. obj->props_info[j] = \
  628. drmModeGetProperty(dev->fd, obj->props->props[j]); \
  629. } \
  630. } while (0)
  631. get_properties(res, res, crtc, CRTC);
  632. get_properties(res, res, connector, CONNECTOR);
  633. for (i = 0; i < res->res->count_crtcs; ++i)
  634. res->crtcs[i].mode = &res->crtcs[i].crtc->mode;
  635. res->plane_res = drmModeGetPlaneResources(dev->fd);
  636. if (!res->plane_res) {
  637. fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
  638. strerror(errno));
  639. return res;
  640. }
  641. res->planes = calloc(res->plane_res->count_planes, sizeof(*res->planes));
  642. if (!res->planes)
  643. goto error;
  644. get_resource(res, plane_res, plane, Plane);
  645. get_properties(res, plane_res, plane, PLANE);
  646. return res;
  647. error:
  648. free_resources(res);
  649. return NULL;
  650. }
  651. static int get_crtc_index(struct device *dev, uint32_t id)
  652. {
  653. int i;
  654. for (i = 0; i < dev->resources->res->count_crtcs; ++i) {
  655. drmModeCrtc *crtc = dev->resources->crtcs[i].crtc;
  656. if (crtc && crtc->crtc_id == id)
  657. return i;
  658. }
  659. return -1;
  660. }
  661. static drmModeConnector *get_connector_by_name(struct device *dev, const char *name)
  662. {
  663. struct connector *connector;
  664. int i;
  665. for (i = 0; i < dev->resources->res->count_connectors; i++) {
  666. connector = &dev->resources->connectors[i];
  667. if (strcmp(connector->name, name) == 0)
  668. return connector->connector;
  669. }
  670. return NULL;
  671. }
  672. static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id)
  673. {
  674. drmModeConnector *connector;
  675. int i;
  676. for (i = 0; i < dev->resources->res->count_connectors; i++) {
  677. connector = dev->resources->connectors[i].connector;
  678. if (connector && connector->connector_id == id)
  679. return connector;
  680. }
  681. return NULL;
  682. }
  683. static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id)
  684. {
  685. drmModeEncoder *encoder;
  686. int i;
  687. for (i = 0; i < dev->resources->res->count_encoders; i++) {
  688. encoder = dev->resources->encoders[i].encoder;
  689. if (encoder && encoder->encoder_id == id)
  690. return encoder;
  691. }
  692. return NULL;
  693. }
  694. /* -----------------------------------------------------------------------------
  695. * Pipes and planes
  696. */
  697. /*
  698. * Mode setting with the kernel interfaces is a bit of a chore.
  699. * First you have to find the connector in question and make sure the
  700. * requested mode is available.
  701. * Then you need to find the encoder attached to that connector so you
  702. * can bind it with a free crtc.
  703. */
  704. struct pipe_arg {
  705. const char **cons;
  706. uint32_t *con_ids;
  707. unsigned int num_cons;
  708. uint32_t crtc_id;
  709. char mode_str[64];
  710. char format_str[5];
  711. float vrefresh;
  712. unsigned int fourcc;
  713. drmModeModeInfo *mode;
  714. struct crtc *crtc;
  715. unsigned int fb_id[2], current_fb_id;
  716. struct timeval start;
  717. int swap_count;
  718. };
  719. struct plane_arg {
  720. uint32_t plane_id; /* the id of plane to use */
  721. uint32_t crtc_id; /* the id of CRTC to bind to */
  722. bool has_position;
  723. int32_t x, y;
  724. uint32_t w, h;
  725. double scale;
  726. unsigned int fb_id;
  727. unsigned int old_fb_id;
  728. struct bo *bo;
  729. struct bo *old_bo;
  730. char format_str[5]; /* need to leave room for terminating \0 */
  731. unsigned int fourcc;
  732. };
  733. static drmModeModeInfo *
  734. connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str,
  735. const float vrefresh)
  736. {
  737. drmModeConnector *connector;
  738. drmModeModeInfo *mode;
  739. int i;
  740. connector = get_connector_by_id(dev, con_id);
  741. if (!connector || !connector->count_modes)
  742. return NULL;
  743. /* Pick by Index */
  744. if (mode_str[0] == '#') {
  745. int index = atoi(mode_str + 1);
  746. if (index >= connector->count_modes || index < 0)
  747. return NULL;
  748. return &connector->modes[index];
  749. }
  750. /* Pick by Name */
  751. for (i = 0; i < connector->count_modes; i++) {
  752. mode = &connector->modes[i];
  753. if (!strcmp(mode->name, mode_str)) {
  754. /* If the vertical refresh frequency is not specified
  755. * then return the first mode that match with the name.
  756. * Else, return the mode that match the name and
  757. * the specified vertical refresh frequency.
  758. */
  759. if (vrefresh == 0)
  760. return mode;
  761. else if (fabs(mode_vrefresh(mode) - vrefresh) < 0.005)
  762. return mode;
  763. }
  764. }
  765. return NULL;
  766. }
  767. static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe)
  768. {
  769. uint32_t possible_crtcs = ~0;
  770. uint32_t active_crtcs = 0;
  771. unsigned int crtc_idx;
  772. unsigned int i;
  773. int j;
  774. for (i = 0; i < pipe->num_cons; ++i) {
  775. uint32_t crtcs_for_connector = 0;
  776. drmModeConnector *connector;
  777. drmModeEncoder *encoder;
  778. int idx;
  779. connector = get_connector_by_id(dev, pipe->con_ids[i]);
  780. if (!connector)
  781. return NULL;
  782. for (j = 0; j < connector->count_encoders; ++j) {
  783. encoder = get_encoder_by_id(dev, connector->encoders[j]);
  784. if (!encoder)
  785. continue;
  786. crtcs_for_connector |= encoder->possible_crtcs;
  787. idx = get_crtc_index(dev, encoder->crtc_id);
  788. if (idx >= 0)
  789. active_crtcs |= 1 << idx;
  790. }
  791. possible_crtcs &= crtcs_for_connector;
  792. }
  793. if (!possible_crtcs)
  794. return NULL;
  795. /* Return the first possible and active CRTC if one exists, or the first
  796. * possible CRTC otherwise.
  797. */
  798. if (possible_crtcs & active_crtcs)
  799. crtc_idx = ffs(possible_crtcs & active_crtcs);
  800. else
  801. crtc_idx = ffs(possible_crtcs);
  802. return &dev->resources->crtcs[crtc_idx - 1];
  803. }
  804. static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe)
  805. {
  806. drmModeModeInfo *mode = NULL;
  807. int i;
  808. pipe->mode = NULL;
  809. for (i = 0; i < (int)pipe->num_cons; i++) {
  810. mode = connector_find_mode(dev, pipe->con_ids[i],
  811. pipe->mode_str, pipe->vrefresh);
  812. if (mode == NULL) {
  813. if (pipe->vrefresh)
  814. fprintf(stderr,
  815. "failed to find mode "
  816. "\"%s-%.2fHz\" for connector %s\n",
  817. pipe->mode_str, pipe->vrefresh, pipe->cons[i]);
  818. else
  819. fprintf(stderr,
  820. "failed to find mode \"%s\" for connector %s\n",
  821. pipe->mode_str, pipe->cons[i]);
  822. return -EINVAL;
  823. }
  824. }
  825. /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise
  826. * locate a CRTC that can be attached to all the connectors.
  827. */
  828. if (pipe->crtc_id != (uint32_t)-1) {
  829. for (i = 0; i < dev->resources->res->count_crtcs; i++) {
  830. struct crtc *crtc = &dev->resources->crtcs[i];
  831. if (pipe->crtc_id == crtc->crtc->crtc_id) {
  832. pipe->crtc = crtc;
  833. break;
  834. }
  835. }
  836. } else {
  837. pipe->crtc = pipe_find_crtc(dev, pipe);
  838. }
  839. if (!pipe->crtc) {
  840. fprintf(stderr, "failed to find CRTC for pipe\n");
  841. return -EINVAL;
  842. }
  843. pipe->mode = mode;
  844. pipe->crtc->mode = mode;
  845. return 0;
  846. }
  847. /* -----------------------------------------------------------------------------
  848. * Properties
  849. */
  850. struct property_arg {
  851. uint32_t obj_id;
  852. uint32_t obj_type;
  853. char name[DRM_PROP_NAME_LEN+1];
  854. uint32_t prop_id;
  855. uint64_t value;
  856. bool optional;
  857. };
  858. static bool set_property(struct device *dev, struct property_arg *p)
  859. {
  860. drmModeObjectProperties *props = NULL;
  861. drmModePropertyRes **props_info = NULL;
  862. const char *obj_type;
  863. int ret;
  864. int i;
  865. p->obj_type = 0;
  866. p->prop_id = 0;
  867. #define find_object(_res, __res, type, Type) \
  868. do { \
  869. for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
  870. struct type *obj = &(_res)->type##s[i]; \
  871. if (obj->type->type##_id != p->obj_id) \
  872. continue; \
  873. p->obj_type = DRM_MODE_OBJECT_##Type; \
  874. obj_type = #Type; \
  875. props = obj->props; \
  876. props_info = obj->props_info; \
  877. } \
  878. } while(0) \
  879. find_object(dev->resources, res, crtc, CRTC);
  880. if (p->obj_type == 0)
  881. find_object(dev->resources, res, connector, CONNECTOR);
  882. if (p->obj_type == 0)
  883. find_object(dev->resources, plane_res, plane, PLANE);
  884. if (p->obj_type == 0) {
  885. fprintf(stderr, "Object %i not found, can't set property\n",
  886. p->obj_id);
  887. return false;
  888. }
  889. if (!props) {
  890. fprintf(stderr, "%s %i has no properties\n",
  891. obj_type, p->obj_id);
  892. return false;
  893. }
  894. for (i = 0; i < (int)props->count_props; ++i) {
  895. if (!props_info[i])
  896. continue;
  897. if (strcmp(props_info[i]->name, p->name) == 0)
  898. break;
  899. }
  900. if (i == (int)props->count_props) {
  901. if (!p->optional)
  902. fprintf(stderr, "%s %i has no %s property\n",
  903. obj_type, p->obj_id, p->name);
  904. return false;
  905. }
  906. p->prop_id = props->props[i];
  907. if (!dev->use_atomic)
  908. ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type,
  909. p->prop_id, p->value);
  910. else
  911. ret = drmModeAtomicAddProperty(dev->req, p->obj_id, p->prop_id, p->value);
  912. if (ret < 0)
  913. fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n",
  914. obj_type, p->obj_id, p->name, p->value, strerror(errno));
  915. return true;
  916. }
  917. /* -------------------------------------------------------------------------- */
  918. static void
  919. page_flip_handler(int fd, unsigned int frame,
  920. unsigned int sec, unsigned int usec, void *data)
  921. {
  922. struct pipe_arg *pipe;
  923. unsigned int new_fb_id;
  924. struct timeval end;
  925. double t;
  926. pipe = data;
  927. if (pipe->current_fb_id == pipe->fb_id[0])
  928. new_fb_id = pipe->fb_id[1];
  929. else
  930. new_fb_id = pipe->fb_id[0];
  931. drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id,
  932. DRM_MODE_PAGE_FLIP_EVENT, pipe);
  933. pipe->current_fb_id = new_fb_id;
  934. pipe->swap_count++;
  935. if (pipe->swap_count == 60) {
  936. gettimeofday(&end, NULL);
  937. t = end.tv_sec + end.tv_usec * 1e-6 -
  938. (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6);
  939. fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t);
  940. pipe->swap_count = 0;
  941. pipe->start = end;
  942. }
  943. }
  944. static bool format_support(const drmModePlanePtr ovr, uint32_t fmt)
  945. {
  946. unsigned int i;
  947. for (i = 0; i < ovr->count_formats; ++i) {
  948. if (ovr->formats[i] == fmt)
  949. return true;
  950. }
  951. return false;
  952. }
  953. static void add_property(struct device *dev, uint32_t obj_id,
  954. const char *name, uint64_t value)
  955. {
  956. struct property_arg p;
  957. p.obj_id = obj_id;
  958. strcpy(p.name, name);
  959. p.value = value;
  960. set_property(dev, &p);
  961. }
  962. static bool add_property_optional(struct device *dev, uint32_t obj_id,
  963. const char *name, uint64_t value)
  964. {
  965. struct property_arg p;
  966. p.obj_id = obj_id;
  967. strcpy(p.name, name);
  968. p.value = value;
  969. p.optional = true;
  970. return set_property(dev, &p);
  971. }
  972. static void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc)
  973. {
  974. unsigned blob_id = 0;
  975. /* TODO: support 1024-sized LUTs, when the use-case arises */
  976. struct drm_color_lut gamma_lut[256];
  977. int i, ret;
  978. if (fourcc == DRM_FORMAT_C8) {
  979. /* TODO: Add C8 support for more patterns */
  980. util_smpte_c8_gamma(256, gamma_lut);
  981. drmModeCreatePropertyBlob(dev->fd, gamma_lut, sizeof(gamma_lut), &blob_id);
  982. } else {
  983. for (i = 0; i < 256; i++) {
  984. gamma_lut[i].red =
  985. gamma_lut[i].green =
  986. gamma_lut[i].blue = i << 8;
  987. }
  988. }
  989. add_property_optional(dev, crtc_id, "DEGAMMA_LUT", 0);
  990. add_property_optional(dev, crtc_id, "CTM", 0);
  991. if (!add_property_optional(dev, crtc_id, "GAMMA_LUT", blob_id)) {
  992. uint16_t r[256], g[256], b[256];
  993. for (i = 0; i < 256; i++) {
  994. r[i] = gamma_lut[i].red;
  995. g[i] = gamma_lut[i].green;
  996. b[i] = gamma_lut[i].blue;
  997. }
  998. ret = drmModeCrtcSetGamma(dev->fd, crtc_id, 256, r, g, b);
  999. if (ret)
  1000. fprintf(stderr, "failed to set gamma: %s\n", strerror(errno));
  1001. }
  1002. }
  1003. static int atomic_set_plane(struct device *dev, struct plane_arg *p,
  1004. int pattern, bool update)
  1005. {
  1006. uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
  1007. struct bo *plane_bo;
  1008. int crtc_x, crtc_y, crtc_w, crtc_h;
  1009. struct crtc *crtc = NULL;
  1010. unsigned int i;
  1011. unsigned int old_fb_id;
  1012. /* Find an unused plane which can be connected to our CRTC. Find the
  1013. * CRTC index first, then iterate over available planes.
  1014. */
  1015. for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) {
  1016. if (p->crtc_id == dev->resources->res->crtcs[i]) {
  1017. crtc = &dev->resources->crtcs[i];
  1018. break;
  1019. }
  1020. }
  1021. if (!crtc) {
  1022. fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
  1023. return -1;
  1024. }
  1025. if (!update)
  1026. fprintf(stderr, "testing %dx%d@%s on plane %u, crtc %u\n",
  1027. p->w, p->h, p->format_str, p->plane_id, p->crtc_id);
  1028. plane_bo = p->old_bo;
  1029. p->old_bo = p->bo;
  1030. if (!plane_bo) {
  1031. plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h,
  1032. handles, pitches, offsets, pattern);
  1033. if (plane_bo == NULL)
  1034. return -1;
  1035. if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
  1036. handles, pitches, offsets, &p->fb_id, 0)) {
  1037. fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
  1038. return -1;
  1039. }
  1040. }
  1041. p->bo = plane_bo;
  1042. old_fb_id = p->fb_id;
  1043. p->old_fb_id = old_fb_id;
  1044. crtc_w = p->w * p->scale;
  1045. crtc_h = p->h * p->scale;
  1046. if (!p->has_position) {
  1047. /* Default to the middle of the screen */
  1048. crtc_x = (crtc->mode->hdisplay - crtc_w) / 2;
  1049. crtc_y = (crtc->mode->vdisplay - crtc_h) / 2;
  1050. } else {
  1051. crtc_x = p->x;
  1052. crtc_y = p->y;
  1053. }
  1054. add_property(dev, p->plane_id, "FB_ID", p->fb_id);
  1055. add_property(dev, p->plane_id, "CRTC_ID", p->crtc_id);
  1056. add_property(dev, p->plane_id, "SRC_X", 0);
  1057. add_property(dev, p->plane_id, "SRC_Y", 0);
  1058. add_property(dev, p->plane_id, "SRC_W", p->w << 16);
  1059. add_property(dev, p->plane_id, "SRC_H", p->h << 16);
  1060. add_property(dev, p->plane_id, "CRTC_X", crtc_x);
  1061. add_property(dev, p->plane_id, "CRTC_Y", crtc_y);
  1062. add_property(dev, p->plane_id, "CRTC_W", crtc_w);
  1063. add_property(dev, p->plane_id, "CRTC_H", crtc_h);
  1064. return 0;
  1065. }
  1066. static int set_plane(struct device *dev, struct plane_arg *p)
  1067. {
  1068. drmModePlane *ovr;
  1069. uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
  1070. uint32_t plane_id;
  1071. struct bo *plane_bo;
  1072. uint32_t plane_flags = 0;
  1073. int crtc_x, crtc_y, crtc_w, crtc_h;
  1074. struct crtc *crtc = NULL;
  1075. unsigned int pipe;
  1076. unsigned int i;
  1077. /* Find an unused plane which can be connected to our CRTC. Find the
  1078. * CRTC index first, then iterate over available planes.
  1079. */
  1080. for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) {
  1081. if (p->crtc_id == dev->resources->res->crtcs[i]) {
  1082. crtc = &dev->resources->crtcs[i];
  1083. pipe = i;
  1084. break;
  1085. }
  1086. }
  1087. if (!crtc) {
  1088. fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
  1089. return -1;
  1090. }
  1091. plane_id = p->plane_id;
  1092. for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
  1093. ovr = dev->resources->planes[i].plane;
  1094. if (!ovr)
  1095. continue;
  1096. if (plane_id && plane_id != ovr->plane_id)
  1097. continue;
  1098. if (!format_support(ovr, p->fourcc))
  1099. continue;
  1100. if ((ovr->possible_crtcs & (1 << pipe)) &&
  1101. (ovr->crtc_id == 0 || ovr->crtc_id == p->crtc_id)) {
  1102. plane_id = ovr->plane_id;
  1103. break;
  1104. }
  1105. }
  1106. if (i == dev->resources->plane_res->count_planes) {
  1107. fprintf(stderr, "no unused plane available for CRTC %u\n",
  1108. crtc->crtc->crtc_id);
  1109. return -1;
  1110. }
  1111. fprintf(stderr, "testing %dx%d@%s overlay plane %u\n",
  1112. p->w, p->h, p->format_str, plane_id);
  1113. plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h, handles,
  1114. pitches, offsets, secondary_fill);
  1115. if (plane_bo == NULL)
  1116. return -1;
  1117. p->bo = plane_bo;
  1118. /* just use single plane format for now.. */
  1119. if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
  1120. handles, pitches, offsets, &p->fb_id, plane_flags)) {
  1121. fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
  1122. return -1;
  1123. }
  1124. crtc_w = p->w * p->scale;
  1125. crtc_h = p->h * p->scale;
  1126. if (!p->has_position) {
  1127. /* Default to the middle of the screen */
  1128. crtc_x = (crtc->mode->hdisplay - crtc_w) / 2;
  1129. crtc_y = (crtc->mode->vdisplay - crtc_h) / 2;
  1130. } else {
  1131. crtc_x = p->x;
  1132. crtc_y = p->y;
  1133. }
  1134. /* note src coords (last 4 args) are in Q16 format */
  1135. if (drmModeSetPlane(dev->fd, plane_id, crtc->crtc->crtc_id, p->fb_id,
  1136. plane_flags, crtc_x, crtc_y, crtc_w, crtc_h,
  1137. 0, 0, p->w << 16, p->h << 16)) {
  1138. fprintf(stderr, "failed to enable plane: %s\n",
  1139. strerror(errno));
  1140. return -1;
  1141. }
  1142. ovr->crtc_id = crtc->crtc->crtc_id;
  1143. return 0;
  1144. }
  1145. static void atomic_set_planes(struct device *dev, struct plane_arg *p,
  1146. unsigned int count, bool update)
  1147. {
  1148. unsigned int i, pattern = primary_fill;
  1149. /* set up planes */
  1150. for (i = 0; i < count; i++) {
  1151. if (i > 0)
  1152. pattern = secondary_fill;
  1153. else
  1154. set_gamma(dev, p[i].crtc_id, p[i].fourcc);
  1155. if (atomic_set_plane(dev, &p[i], pattern, update))
  1156. return;
  1157. }
  1158. }
  1159. static void atomic_clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
  1160. {
  1161. unsigned int i;
  1162. for (i = 0; i < count; i++) {
  1163. add_property(dev, p[i].plane_id, "FB_ID", 0);
  1164. add_property(dev, p[i].plane_id, "CRTC_ID", 0);
  1165. add_property(dev, p[i].plane_id, "SRC_X", 0);
  1166. add_property(dev, p[i].plane_id, "SRC_Y", 0);
  1167. add_property(dev, p[i].plane_id, "SRC_W", 0);
  1168. add_property(dev, p[i].plane_id, "SRC_H", 0);
  1169. add_property(dev, p[i].plane_id, "CRTC_X", 0);
  1170. add_property(dev, p[i].plane_id, "CRTC_Y", 0);
  1171. add_property(dev, p[i].plane_id, "CRTC_W", 0);
  1172. add_property(dev, p[i].plane_id, "CRTC_H", 0);
  1173. }
  1174. }
  1175. static void atomic_clear_FB(struct device *dev, struct plane_arg *p, unsigned int count)
  1176. {
  1177. unsigned int i;
  1178. for (i = 0; i < count; i++) {
  1179. if (p[i].fb_id) {
  1180. drmModeRmFB(dev->fd, p[i].fb_id);
  1181. p[i].fb_id = 0;
  1182. }
  1183. if (p[i].old_fb_id) {
  1184. drmModeRmFB(dev->fd, p[i].old_fb_id);
  1185. p[i].old_fb_id = 0;
  1186. }
  1187. if (p[i].bo) {
  1188. bo_destroy(p[i].bo);
  1189. p[i].bo = NULL;
  1190. }
  1191. if (p[i].old_bo) {
  1192. bo_destroy(p[i].old_bo);
  1193. p[i].old_bo = NULL;
  1194. }
  1195. }
  1196. }
  1197. static void clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
  1198. {
  1199. unsigned int i;
  1200. for (i = 0; i < count; i++) {
  1201. if (p[i].fb_id)
  1202. drmModeRmFB(dev->fd, p[i].fb_id);
  1203. if (p[i].bo)
  1204. bo_destroy(p[i].bo);
  1205. }
  1206. }
  1207. static void atomic_set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  1208. {
  1209. unsigned int i;
  1210. unsigned int j;
  1211. int ret;
  1212. for (i = 0; i < count; i++) {
  1213. struct pipe_arg *pipe = &pipes[i];
  1214. ret = pipe_find_crtc_and_mode(dev, pipe);
  1215. if (ret < 0)
  1216. continue;
  1217. }
  1218. for (i = 0; i < count; i++) {
  1219. struct pipe_arg *pipe = &pipes[i];
  1220. uint32_t blob_id;
  1221. if (pipe->mode == NULL)
  1222. continue;
  1223. printf("setting mode %s-%.2fHz on connectors ",
  1224. pipe->mode->name, mode_vrefresh(pipe->mode));
  1225. for (j = 0; j < pipe->num_cons; ++j) {
  1226. printf("%s, ", pipe->cons[j]);
  1227. add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc->crtc->crtc_id);
  1228. }
  1229. printf("crtc %d\n", pipe->crtc->crtc->crtc_id);
  1230. drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id);
  1231. add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", blob_id);
  1232. add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 1);
  1233. }
  1234. }
  1235. static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  1236. {
  1237. unsigned int i;
  1238. unsigned int j;
  1239. for (i = 0; i < count; i++) {
  1240. struct pipe_arg *pipe = &pipes[i];
  1241. if (pipe->mode == NULL)
  1242. continue;
  1243. for (j = 0; j < pipe->num_cons; ++j)
  1244. add_property(dev, pipe->con_ids[j], "CRTC_ID",0);
  1245. add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", 0);
  1246. add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 0);
  1247. }
  1248. }
  1249. static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  1250. {
  1251. uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
  1252. unsigned int fb_id;
  1253. struct bo *bo;
  1254. unsigned int i;
  1255. unsigned int j;
  1256. int ret, x;
  1257. dev->mode.width = 0;
  1258. dev->mode.height = 0;
  1259. dev->mode.fb_id = 0;
  1260. for (i = 0; i < count; i++) {
  1261. struct pipe_arg *pipe = &pipes[i];
  1262. ret = pipe_find_crtc_and_mode(dev, pipe);
  1263. if (ret < 0)
  1264. continue;
  1265. dev->mode.width += pipe->mode->hdisplay;
  1266. if (dev->mode.height < pipe->mode->vdisplay)
  1267. dev->mode.height = pipe->mode->vdisplay;
  1268. }
  1269. bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width,
  1270. dev->mode.height, handles, pitches, offsets,
  1271. primary_fill);
  1272. if (bo == NULL)
  1273. return;
  1274. dev->mode.bo = bo;
  1275. ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height,
  1276. pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0);
  1277. if (ret) {
  1278. fprintf(stderr, "failed to add fb (%ux%u): %s\n",
  1279. dev->mode.width, dev->mode.height, strerror(errno));
  1280. return;
  1281. }
  1282. dev->mode.fb_id = fb_id;
  1283. x = 0;
  1284. for (i = 0; i < count; i++) {
  1285. struct pipe_arg *pipe = &pipes[i];
  1286. if (pipe->mode == NULL)
  1287. continue;
  1288. printf("setting mode %s-%.2fHz@%s on connectors ",
  1289. pipe->mode->name, mode_vrefresh(pipe->mode),
  1290. pipe->format_str);
  1291. for (j = 0; j < pipe->num_cons; ++j)
  1292. printf("%s, ", pipe->cons[j]);
  1293. printf("crtc %d\n", pipe->crtc->crtc->crtc_id);
  1294. ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id,
  1295. x, 0, pipe->con_ids, pipe->num_cons,
  1296. pipe->mode);
  1297. /* XXX: Actually check if this is needed */
  1298. drmModeDirtyFB(dev->fd, fb_id, NULL, 0);
  1299. x += pipe->mode->hdisplay;
  1300. if (ret) {
  1301. fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
  1302. return;
  1303. }
  1304. set_gamma(dev, pipe->crtc->crtc->crtc_id, pipe->fourcc);
  1305. }
  1306. }
  1307. static void set_mode_plink(struct device *dev, PlinkYuvInfo *pic, struct pipe_arg *pipes, unsigned int count)
  1308. {
  1309. uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
  1310. unsigned int fb_id;
  1311. struct bo *bo;
  1312. unsigned int i;
  1313. unsigned int j;
  1314. int ret, x;
  1315. dev->mode.width = 0;
  1316. dev->mode.height = 0;
  1317. dev->mode.fb_id = 0;
  1318. for (i = 0; i < count; i++) {
  1319. struct pipe_arg *pipe = &pipes[i];
  1320. ret = pipe_find_crtc_and_mode(dev, pipe);
  1321. if (ret < 0)
  1322. continue;
  1323. dev->mode.width += pipe->mode->hdisplay;
  1324. if (dev->mode.height < pipe->mode->vdisplay)
  1325. dev->mode.height = pipe->mode->vdisplay;
  1326. }
  1327. bo = bo_create_plink(dev->fd, pipes[0].fourcc, pic->pic_width,
  1328. pic->pic_height, handles, pitches, offsets,
  1329. primary_fill, g_prime_fd, pic->stride_y);
  1330. if (bo == NULL)
  1331. return;
  1332. DPU_PRINT(INFO, "handles:%d handles1:%d pitches:%d pitches1:%d offsets:%d offsets1:%d\n",
  1333. handles[0], handles[1], pitches[0], pitches[1], offsets[0], offsets[1]);
  1334. dev->mode.bo = bo;
  1335. ret = drmModeAddFB2(dev->fd, pic->pic_width, pic->pic_height,
  1336. pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0);
  1337. if (ret) {
  1338. fprintf(stderr, "failed to add fb (%ux%u): %s\n",
  1339. dev->mode.width, dev->mode.height, strerror(errno));
  1340. return;
  1341. }
  1342. dev->mode.fb_id = fb_id;
  1343. x = 0;
  1344. for (i = 0; i < count; i++) {
  1345. struct pipe_arg *pipe = &pipes[i];
  1346. if (pipe->mode == NULL)
  1347. continue;
  1348. DPU_PRINT(INFO, "setting mode %s-%.2fHz@%s on connectors ",
  1349. pipe->mode->name, mode_vrefresh(pipe->mode),
  1350. pipe->format_str);
  1351. for (j = 0; j < pipe->num_cons; ++j)
  1352. DPU_PRINT(INFO, "%s, ", pipe->cons[j]);
  1353. DPU_PRINT(INFO, "crtc %d\n", pipe->crtc->crtc->crtc_id);
  1354. ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id,
  1355. x, 0, pipe->con_ids, pipe->num_cons,
  1356. pipe->mode);
  1357. #if 0
  1358. /* XXX: Actually check if this is needed */
  1359. drmModeDirtyFB(dev->fd, fb_id, NULL, 0);
  1360. x += pipe->mode->hdisplay;
  1361. if (ret) {
  1362. fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
  1363. return;
  1364. }
  1365. set_gamma(dev, pipe->crtc->crtc->crtc_id, pipe->fourcc);
  1366. #endif
  1367. }
  1368. }
  1369. static void clear_mode(struct device *dev)
  1370. {
  1371. if (dev->mode.fb_id)
  1372. drmModeRmFB(dev->fd, dev->mode.fb_id);
  1373. if (dev->mode.bo)
  1374. bo_destroy(dev->mode.bo);
  1375. }
  1376. static void set_planes(struct device *dev, struct plane_arg *p, unsigned int count)
  1377. {
  1378. unsigned int i;
  1379. /* set up planes/overlays */
  1380. for (i = 0; i < count; i++)
  1381. if (set_plane(dev, &p[i]))
  1382. return;
  1383. }
  1384. static void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  1385. {
  1386. uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
  1387. struct bo *bo;
  1388. unsigned int i;
  1389. int ret;
  1390. /* maybe make cursor width/height configurable some day */
  1391. uint32_t cw = 64;
  1392. uint32_t ch = 64;
  1393. /* create cursor bo.. just using PATTERN_PLAIN as it has
  1394. * translucent alpha
  1395. */
  1396. bo = bo_create(dev->fd, DRM_FORMAT_ARGB8888, cw, ch, handles, pitches,
  1397. offsets, UTIL_PATTERN_PLAIN);
  1398. if (bo == NULL)
  1399. return;
  1400. dev->mode.cursor_bo = bo;
  1401. for (i = 0; i < count; i++) {
  1402. struct pipe_arg *pipe = &pipes[i];
  1403. ret = cursor_init(dev->fd, handles[0],
  1404. pipe->crtc->crtc->crtc_id,
  1405. pipe->mode->hdisplay, pipe->mode->vdisplay,
  1406. cw, ch);
  1407. if (ret) {
  1408. fprintf(stderr, "failed to init cursor for CRTC[%u]\n",
  1409. pipe->crtc_id);
  1410. return;
  1411. }
  1412. }
  1413. cursor_start();
  1414. }
  1415. static void clear_cursors(struct device *dev)
  1416. {
  1417. cursor_stop();
  1418. if (dev->mode.cursor_bo)
  1419. bo_destroy(dev->mode.cursor_bo);
  1420. }
  1421. static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  1422. {
  1423. uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
  1424. unsigned int other_fb_id;
  1425. struct bo *other_bo;
  1426. drmEventContext evctx;
  1427. unsigned int i;
  1428. int ret;
  1429. other_bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width,
  1430. dev->mode.height, handles, pitches, offsets,
  1431. UTIL_PATTERN_PLAIN);
  1432. if (other_bo == NULL)
  1433. return;
  1434. ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height,
  1435. pipes[0].fourcc, handles, pitches, offsets,
  1436. &other_fb_id, 0);
  1437. if (ret) {
  1438. fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
  1439. goto err;
  1440. }
  1441. for (i = 0; i < count; i++) {
  1442. struct pipe_arg *pipe = &pipes[i];
  1443. if (pipe->mode == NULL)
  1444. continue;
  1445. ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id,
  1446. other_fb_id, DRM_MODE_PAGE_FLIP_EVENT,
  1447. pipe);
  1448. if (ret) {
  1449. fprintf(stderr, "failed to page flip: %s\n", strerror(errno));
  1450. goto err_rmfb;
  1451. }
  1452. gettimeofday(&pipe->start, NULL);
  1453. pipe->swap_count = 0;
  1454. pipe->fb_id[0] = dev->mode.fb_id;
  1455. pipe->fb_id[1] = other_fb_id;
  1456. pipe->current_fb_id = other_fb_id;
  1457. }
  1458. memset(&evctx, 0, sizeof evctx);
  1459. evctx.version = DRM_EVENT_CONTEXT_VERSION;
  1460. evctx.vblank_handler = NULL;
  1461. evctx.page_flip_handler = page_flip_handler;
  1462. while (1) {
  1463. #if 0
  1464. struct pollfd pfd[2];
  1465. pfd[0].fd = 0;
  1466. pfd[0].events = POLLIN;
  1467. pfd[1].fd = fd;
  1468. pfd[1].events = POLLIN;
  1469. if (poll(pfd, 2, -1) < 0) {
  1470. fprintf(stderr, "poll error\n");
  1471. break;
  1472. }
  1473. if (pfd[0].revents)
  1474. break;
  1475. #else
  1476. struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
  1477. fd_set fds;
  1478. FD_ZERO(&fds);
  1479. FD_SET(0, &fds);
  1480. FD_SET(dev->fd, &fds);
  1481. ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout);
  1482. if (ret <= 0) {
  1483. fprintf(stderr, "select timed out or error (ret %d)\n",
  1484. ret);
  1485. continue;
  1486. } else if (FD_ISSET(0, &fds)) {
  1487. break;
  1488. }
  1489. #endif
  1490. drmHandleEvent(dev->fd, &evctx);
  1491. }
  1492. err_rmfb:
  1493. drmModeRmFB(dev->fd, other_fb_id);
  1494. err:
  1495. bo_destroy(other_bo);
  1496. }
  1497. #define min(a, b) ((a) < (b) ? (a) : (b))
  1498. static int parse_connector(struct pipe_arg *pipe, const char *arg)
  1499. {
  1500. unsigned int len;
  1501. unsigned int i;
  1502. const char *p;
  1503. char *endp;
  1504. pipe->vrefresh = 0;
  1505. pipe->crtc_id = (uint32_t)-1;
  1506. strcpy(pipe->format_str, "XR24");
  1507. /* Count the number of connectors and allocate them. */
  1508. pipe->num_cons = 1;
  1509. for (p = arg; *p && *p != ':' && *p != '@'; ++p) {
  1510. if (*p == ',')
  1511. pipe->num_cons++;
  1512. }
  1513. pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids));
  1514. pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons));
  1515. if (pipe->con_ids == NULL || pipe->cons == NULL)
  1516. return -1;
  1517. /* Parse the connectors. */
  1518. for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) {
  1519. endp = strpbrk(p, ",@:");
  1520. if (!endp)
  1521. break;
  1522. pipe->cons[i] = strndup(p, endp - p);
  1523. if (*endp != ',')
  1524. break;
  1525. }
  1526. if (i != pipe->num_cons - 1)
  1527. return -1;
  1528. /* Parse the remaining parameters. */
  1529. if (!endp)
  1530. return -1;
  1531. if (*endp == '@') {
  1532. arg = endp + 1;
  1533. pipe->crtc_id = strtoul(arg, &endp, 10);
  1534. }
  1535. if (*endp != ':')
  1536. return -1;
  1537. arg = endp + 1;
  1538. /* Search for the vertical refresh or the format. */
  1539. p = strpbrk(arg, "-@");
  1540. if (p == NULL)
  1541. p = arg + strlen(arg);
  1542. len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg));
  1543. strncpy(pipe->mode_str, arg, len);
  1544. pipe->mode_str[len] = '\0';
  1545. if (*p == '-') {
  1546. pipe->vrefresh = strtof(p + 1, &endp);
  1547. p = endp;
  1548. }
  1549. if (*p == '@') {
  1550. strncpy(pipe->format_str, p + 1, 4);
  1551. pipe->format_str[4] = '\0';
  1552. }
  1553. pipe->fourcc = util_format_fourcc(pipe->format_str);
  1554. if (pipe->fourcc == 0) {
  1555. fprintf(stderr, "unknown format %s\n", pipe->format_str);
  1556. return -1;
  1557. }
  1558. return 0;
  1559. }
  1560. static int parse_plane(struct plane_arg *plane, const char *p)
  1561. {
  1562. char *end;
  1563. plane->plane_id = strtoul(p, &end, 10);
  1564. if (*end != '@')
  1565. return -EINVAL;
  1566. p = end + 1;
  1567. plane->crtc_id = strtoul(p, &end, 10);
  1568. if (*end != ':')
  1569. return -EINVAL;
  1570. p = end + 1;
  1571. plane->w = strtoul(p, &end, 10);
  1572. if (*end != 'x')
  1573. return -EINVAL;
  1574. p = end + 1;
  1575. plane->h = strtoul(p, &end, 10);
  1576. if (*end == '+' || *end == '-') {
  1577. plane->x = strtol(end, &end, 10);
  1578. if (*end != '+' && *end != '-')
  1579. return -EINVAL;
  1580. plane->y = strtol(end, &end, 10);
  1581. plane->has_position = true;
  1582. }
  1583. if (*end == '*') {
  1584. p = end + 1;
  1585. plane->scale = strtod(p, &end);
  1586. if (plane->scale <= 0.0)
  1587. return -EINVAL;
  1588. } else {
  1589. plane->scale = 1.0;
  1590. }
  1591. if (*end == '@') {
  1592. strncpy(plane->format_str, end + 1, 4);
  1593. plane->format_str[4] = '\0';
  1594. } else {
  1595. strcpy(plane->format_str, "XR24");
  1596. }
  1597. plane->fourcc = util_format_fourcc(plane->format_str);
  1598. if (plane->fourcc == 0) {
  1599. fprintf(stderr, "unknown format %s\n", plane->format_str);
  1600. return -EINVAL;
  1601. }
  1602. return 0;
  1603. }
  1604. static int parse_property(struct property_arg *p, const char *arg)
  1605. {
  1606. if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3)
  1607. return -1;
  1608. p->obj_type = 0;
  1609. p->name[DRM_PROP_NAME_LEN] = '\0';
  1610. return 0;
  1611. }
  1612. static void parse_fill_patterns(char *arg)
  1613. {
  1614. char *fill = strtok(arg, ",");
  1615. if (!fill)
  1616. return;
  1617. primary_fill = util_pattern_enum(fill);
  1618. fill = strtok(NULL, ",");
  1619. if (!fill)
  1620. return;
  1621. secondary_fill = util_pattern_enum(fill);
  1622. }
  1623. static void usage(char *name)
  1624. {
  1625. fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name);
  1626. fprintf(stderr, "\n Query options:\n\n");
  1627. fprintf(stderr, "\t-c\tlist connectors\n");
  1628. fprintf(stderr, "\t-e\tlist encoders\n");
  1629. fprintf(stderr, "\t-f\tlist framebuffers\n");
  1630. fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n");
  1631. fprintf(stderr, "\n Test options:\n\n");
  1632. fprintf(stderr, "\t-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n");
  1633. fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>]\tset a mode\n");
  1634. fprintf(stderr, "\t-C\ttest hw cursor\n");
  1635. fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
  1636. fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
  1637. fprintf(stderr, "\t-a \tuse atomic API\n");
  1638. fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n");
  1639. fprintf(stderr, "\n Generic options:\n\n");
  1640. fprintf(stderr, "\t-d\tdrop master after mode set\n");
  1641. fprintf(stderr, "\t-M module\tuse the given driver\n");
  1642. fprintf(stderr, "\t-D device\tuse the given device\n");
  1643. fprintf(stderr, "\n\tDefault is to dump all info.\n");
  1644. exit(0);
  1645. }
  1646. static int page_flipping_supported(void)
  1647. {
  1648. /*FIXME: generic ioctl needed? */
  1649. return 1;
  1650. #if 0
  1651. int ret, value;
  1652. struct drm_i915_getparam gp;
  1653. gp.param = I915_PARAM_HAS_PAGEFLIPPING;
  1654. gp.value = &value;
  1655. ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
  1656. if (ret) {
  1657. fprintf(stderr, "drm_i915_getparam: %m\n");
  1658. return 0;
  1659. }
  1660. return *gp.value;
  1661. #endif
  1662. }
  1663. static int cursor_supported(void)
  1664. {
  1665. /*FIXME: generic ioctl needed? */
  1666. return 1;
  1667. }
  1668. static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe)
  1669. {
  1670. drmModeConnector *connector;
  1671. unsigned int i;
  1672. uint32_t id;
  1673. char *endp;
  1674. for (i = 0; i < pipe->num_cons; i++) {
  1675. id = strtoul(pipe->cons[i], &endp, 10);
  1676. if (endp == pipe->cons[i]) {
  1677. connector = get_connector_by_name(dev, pipe->cons[i]);
  1678. if (!connector) {
  1679. fprintf(stderr, "no connector named '%s'\n",
  1680. pipe->cons[i]);
  1681. return -ENODEV;
  1682. }
  1683. id = connector->connector_id;
  1684. }
  1685. pipe->con_ids[i] = id;
  1686. }
  1687. return 0;
  1688. }
  1689. static int getLogLevel()
  1690. {
  1691. /* DPU test use the same loglevel as libplink.so */
  1692. char *env = getenv("PLINK_LOG_LEVEL");
  1693. pid = getpid();
  1694. if (env == NULL)
  1695. return DPU_LOG_ERROR;
  1696. else
  1697. {
  1698. int level = atoi(env);
  1699. if (level >= DPU_LOG_MAX || level < DPU_LOG_QUIET)
  1700. return DPU_LOG_ERROR;
  1701. else
  1702. return level;
  1703. }
  1704. }
  1705. static char optstr[] = "acdD:efF:M:P:ps:Cvw:L:";
  1706. int main(int argc, char **argv)
  1707. {
  1708. struct device dev;
  1709. int c;
  1710. int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0;
  1711. int drop_master = 0;
  1712. int test_vsync = 0;
  1713. int test_cursor = 0;
  1714. int use_atomic = 0;
  1715. char *device = NULL;
  1716. char *module = NULL;
  1717. unsigned int i;
  1718. unsigned int count = 0, plane_count = 0;
  1719. unsigned int prop_count = 0;
  1720. struct pipe_arg *pipe_args = NULL;
  1721. struct plane_arg *plane_args = NULL;
  1722. struct property_arg *prop_args = NULL;
  1723. unsigned int args = 0;
  1724. int ret;
  1725. PlinkStatus pstatus = PLINK_STATUS_OK;
  1726. PlinkPacket sendpkt, recvpkt;
  1727. PlinkDescHdr *hdr;
  1728. PlinkYuvInfo *pic;
  1729. PlinkMsg *recvmsg, sendmsg;
  1730. PlinkHandle plink = NULL;
  1731. char *plinkname = NULL;
  1732. int exitcode = 0;
  1733. log_level = getLogLevel();
  1734. memset(&dev, 0, sizeof dev);
  1735. printf("log_level:%d\n", log_level);
  1736. opterr = 0;
  1737. while ((c = getopt(argc, argv, optstr)) != -1) {
  1738. args++;
  1739. switch (c) {
  1740. case 'a':
  1741. use_atomic = 1;
  1742. break;
  1743. case 'c':
  1744. connectors = 1;
  1745. break;
  1746. case 'D':
  1747. device = optarg;
  1748. args--;
  1749. break;
  1750. case 'd':
  1751. drop_master = 1;
  1752. break;
  1753. case 'e':
  1754. encoders = 1;
  1755. break;
  1756. case 'f':
  1757. framebuffers = 1;
  1758. break;
  1759. case 'F':
  1760. parse_fill_patterns(optarg);
  1761. break;
  1762. case 'M':
  1763. module = optarg;
  1764. /* Preserve the default behaviour of dumping all information. */
  1765. args--;
  1766. break;
  1767. case 'P':
  1768. plane_args = realloc(plane_args,
  1769. (plane_count + 1) * sizeof *plane_args);
  1770. if (plane_args == NULL) {
  1771. fprintf(stderr, "memory allocation failed\n");
  1772. return 1;
  1773. }
  1774. memset(&plane_args[plane_count], 0, sizeof(*plane_args));
  1775. if (parse_plane(&plane_args[plane_count], optarg) < 0)
  1776. usage(argv[0]);
  1777. plane_count++;
  1778. break;
  1779. case 'p':
  1780. crtcs = 1;
  1781. planes = 1;
  1782. break;
  1783. case 's':
  1784. pipe_args = realloc(pipe_args,
  1785. (count + 1) * sizeof *pipe_args);
  1786. if (pipe_args == NULL) {
  1787. fprintf(stderr, "memory allocation failed\n");
  1788. return 1;
  1789. }
  1790. memset(&pipe_args[count], 0, sizeof(*pipe_args));
  1791. if (parse_connector(&pipe_args[count], optarg) < 0)
  1792. usage(argv[0]);
  1793. count++;
  1794. break;
  1795. case 'C':
  1796. test_cursor = 1;
  1797. break;
  1798. case 'v':
  1799. test_vsync = 1;
  1800. break;
  1801. case 'w':
  1802. prop_args = realloc(prop_args,
  1803. (prop_count + 1) * sizeof *prop_args);
  1804. if (prop_args == NULL) {
  1805. fprintf(stderr, "memory allocation failed\n");
  1806. return 1;
  1807. }
  1808. memset(&prop_args[prop_count], 0, sizeof(*prop_args));
  1809. if (parse_property(&prop_args[prop_count], optarg) < 0)
  1810. usage(argv[0]);
  1811. prop_count++;
  1812. break;
  1813. case 'L':
  1814. plinkname = optarg;
  1815. args--;
  1816. printf("plinkname:%s\n", plinkname);
  1817. break;
  1818. default:
  1819. usage(argv[0]);
  1820. break;
  1821. }
  1822. }
  1823. if (PLINK_create(&plink, plinkname, PLINK_MODE_CLIENT) != PLINK_STATUS_OK) {
  1824. printf("Failed to create PLINK.");
  1825. return -1;
  1826. }
  1827. if (PLINK_connect(plink, NULL) != PLINK_STATUS_OK) {
  1828. printf("Failed to connect to server.");
  1829. return -1;
  1830. }
  1831. if (!args || (args == 1 && use_atomic))
  1832. encoders = connectors = crtcs = planes = framebuffers = 1;
  1833. dev.fd = util_open(device, module);
  1834. if (dev.fd < 0)
  1835. return -1;
  1836. ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
  1837. if (ret && use_atomic) {
  1838. fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno));
  1839. drmClose(dev.fd);
  1840. return -1;
  1841. }
  1842. dev.use_atomic = use_atomic;
  1843. if (test_vsync && !page_flipping_supported()) {
  1844. fprintf(stderr, "page flipping not supported by drm.\n");
  1845. return -1;
  1846. }
  1847. if (test_vsync && !count) {
  1848. fprintf(stderr, "page flipping requires at least one -s option.\n");
  1849. return -1;
  1850. }
  1851. if (test_cursor && !cursor_supported()) {
  1852. fprintf(stderr, "hw cursor not supported by drm.\n");
  1853. return -1;
  1854. }
  1855. dev.resources = get_resources(&dev);
  1856. if (!dev.resources) {
  1857. drmClose(dev.fd);
  1858. return 1;
  1859. }
  1860. for (i = 0; i < count; i++) {
  1861. if (pipe_resolve_connectors(&dev, &pipe_args[i]) < 0) {
  1862. free_resources(dev.resources);
  1863. drmClose(dev.fd);
  1864. return 1;
  1865. }
  1866. }
  1867. #define dump_resource(dev, res) if (res) dump_##res(dev)
  1868. dump_resource(&dev, encoders);
  1869. dump_resource(&dev, connectors);
  1870. dump_resource(&dev, crtcs);
  1871. dump_resource(&dev, planes);
  1872. dump_resource(&dev, framebuffers);
  1873. for (i = 0; i < prop_count; ++i)
  1874. set_property(&dev, &prop_args[i]);
  1875. if (dev.use_atomic) {
  1876. dev.req = drmModeAtomicAlloc();
  1877. if (count && plane_count) {
  1878. uint64_t cap = 0;
  1879. ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
  1880. if (ret || cap == 0) {
  1881. fprintf(stderr, "driver doesn't support the dumb buffer API\n");
  1882. return 1;
  1883. }
  1884. atomic_set_mode(&dev, pipe_args, count);
  1885. atomic_set_planes(&dev, plane_args, plane_count, false);
  1886. ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
  1887. if (ret) {
  1888. fprintf(stderr, "Atomic Commit failed [1]\n");
  1889. return 1;
  1890. }
  1891. gettimeofday(&pipe_args->start, NULL);
  1892. pipe_args->swap_count = 0;
  1893. while (test_vsync) {
  1894. drmModeAtomicFree(dev.req);
  1895. dev.req = drmModeAtomicAlloc();
  1896. atomic_set_planes(&dev, plane_args, plane_count, true);
  1897. ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
  1898. if (ret) {
  1899. fprintf(stderr, "Atomic Commit failed [2]\n");
  1900. return 1;
  1901. }
  1902. pipe_args->swap_count++;
  1903. if (pipe_args->swap_count == 60) {
  1904. struct timeval end;
  1905. double t;
  1906. gettimeofday(&end, NULL);
  1907. t = end.tv_sec + end.tv_usec * 1e-6 -
  1908. (pipe_args->start.tv_sec + pipe_args->start.tv_usec * 1e-6);
  1909. fprintf(stderr, "freq: %.02fHz\n", pipe_args->swap_count / t);
  1910. pipe_args->swap_count = 0;
  1911. pipe_args->start = end;
  1912. }
  1913. }
  1914. if (drop_master)
  1915. drmDropMaster(dev.fd);
  1916. getchar();
  1917. drmModeAtomicFree(dev.req);
  1918. dev.req = drmModeAtomicAlloc();
  1919. atomic_clear_mode(&dev, pipe_args, count);
  1920. atomic_clear_planes(&dev, plane_args, plane_count);
  1921. ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
  1922. if (ret) {
  1923. fprintf(stderr, "Atomic Commit failed\n");
  1924. return 1;
  1925. }
  1926. atomic_clear_FB(&dev, plane_args, plane_count);
  1927. }
  1928. drmModeAtomicFree(dev.req);
  1929. } else {
  1930. do {
  1931. pstatus = PLINK_recv(plink, 0, &recvpkt);
  1932. if (pstatus != PLINK_STATUS_OK) {
  1933. DPU_PRINT(ERROR, "Failed to recieve packet from upper\n");
  1934. break;
  1935. } else if (recvpkt.fd == PLINK_INVALID_FD) {
  1936. DPU_PRINT(ERROR, "received invalid buffer fd\n");
  1937. break;
  1938. }
  1939. DPU_PRINT(INFO, "receive fd = %d, num = %d\n", recvpkt.fd, recvpkt.num);
  1940. if (recvpkt.fd != PLINK_INVALID_FD)
  1941. g_prime_fd = recvpkt.fd;
  1942. hdr = (PlinkDescHdr *)(recvpkt.list[0]);
  1943. switch (hdr->type) {
  1944. case PLINK_TYPE_2D_YUV:
  1945. pic = (PlinkYuvInfo *)(recvpkt.list[0]);
  1946. DPU_PRINT(INFO, "[CLIENT] Received frame %d 0x%010llx: %dx%d, format = %d, stride = luma %d, chroma %d, offset_y = %u, offset_u = %u\n",
  1947. pic->header.id, pic->bus_address_y,
  1948. pic->pic_width, pic->pic_height,
  1949. pic->format, pic->stride_y, pic->stride_u,
  1950. pic->offset_y, pic->offset_u);
  1951. break;
  1952. case PLINK_TYPE_MESSAGE:
  1953. recvmsg = (PlinkMsg *)(recvpkt.list[0]);
  1954. if (recvmsg->msg == PLINK_EXIT_CODE)
  1955. exitcode = 1;
  1956. DPU_PRINT(INFO, "Exit\n");
  1957. break;
  1958. }
  1959. if (exitcode)
  1960. break;
  1961. if (count || plane_count) {
  1962. uint64_t cap = 0;
  1963. ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
  1964. if (ret || cap == 0) {
  1965. DPU_PRINT(ERROR, "driver doesn't support the dumb buffer API\n");
  1966. return 1;
  1967. }
  1968. if (count)
  1969. set_mode_plink(&dev, pic, pipe_args, count);
  1970. if (plane_count)
  1971. set_planes(&dev, plane_args, plane_count);
  1972. if (test_cursor)
  1973. set_cursors(&dev, pipe_args, count);
  1974. if (test_vsync)
  1975. test_page_flip(&dev, pipe_args, count);
  1976. if (drop_master)
  1977. drmDropMaster(dev.fd);
  1978. //getchar();
  1979. if (test_cursor)
  1980. clear_cursors(&dev);
  1981. if (plane_count)
  1982. clear_planes(&dev, plane_args, plane_count);
  1983. if (count) {
  1984. //clear_mode(&dev);
  1985. close(recvpkt.fd);
  1986. }
  1987. }
  1988. sendmsg.header.type = PLINK_TYPE_MESSAGE;
  1989. sendmsg.header.size = DATA_SIZE(PlinkMsg);
  1990. sendmsg.msg = hdr->id;
  1991. sendpkt.list[0] = &sendmsg;
  1992. sendpkt.num = 1;
  1993. sendpkt.fd = PLINK_INVALID_FD;
  1994. pstatus = PLINK_send(plink, 0, &sendpkt);
  1995. if (pstatus != PLINK_STATUS_OK) {
  1996. DPU_PRINT(ERROR, "failed to send msg to isp: %d\n", pstatus);
  1997. break;
  1998. }
  1999. if (log_level >= DPU_LOG_DEBUG)
  2000. fflush(stdout);
  2001. } while (1);
  2002. }
  2003. fflush(stdout);
  2004. free_resources(dev.resources);
  2005. return 0;
  2006. }