carminefb.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Frame buffer driver for the Carmine GPU.
  4. *
  5. * The driver configures the GPU as follows
  6. * - FB0 is display 0 with unique memory area
  7. * - FB1 is display 1 with unique memory area
  8. * - both display use 32 bit colors
  9. */
  10. #include <linux/delay.h>
  11. #include <linux/errno.h>
  12. #include <linux/fb.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/pci.h>
  15. #include <linux/slab.h>
  16. #include <linux/module.h>
  17. #include "carminefb.h"
  18. #include "carminefb_regs.h"
  19. #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
  20. #error "The endianness of the target host has not been defined."
  21. #endif
  22. /*
  23. * The initial video mode can be supplied via two different ways:
  24. * - as a string that is passed to fb_find_mode() (module option fb_mode_str)
  25. * - as an integer that picks the video mode from carmine_modedb[] (module
  26. * option fb_mode)
  27. *
  28. * If nothing is used than the initial video mode will be the
  29. * CARMINEFB_DEFAULT_VIDEO_MODE member of the carmine_modedb[].
  30. */
  31. #define CARMINEFB_DEFAULT_VIDEO_MODE 1
  32. static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
  33. module_param(fb_mode, uint, 0444);
  34. MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
  35. static char *fb_mode_str;
  36. module_param(fb_mode_str, charp, 0444);
  37. MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
  38. /*
  39. * Carminefb displays:
  40. * 0b000 None
  41. * 0b001 Display 0
  42. * 0b010 Display 1
  43. */
  44. static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
  45. module_param(fb_displays, int, 0444);
  46. MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
  47. struct carmine_hw {
  48. void __iomem *v_regs;
  49. void __iomem *screen_mem;
  50. struct fb_info *fb[MAX_DISPLAY];
  51. };
  52. struct carmine_resolution {
  53. u32 htp;
  54. u32 hsp;
  55. u32 hsw;
  56. u32 hdp;
  57. u32 vtr;
  58. u32 vsp;
  59. u32 vsw;
  60. u32 vdp;
  61. u32 disp_mode;
  62. };
  63. struct carmine_fb {
  64. void __iomem *display_reg;
  65. void __iomem *screen_base;
  66. u32 smem_offset;
  67. u32 cur_mode;
  68. u32 new_mode;
  69. struct carmine_resolution *res;
  70. u32 pseudo_palette[16];
  71. };
  72. static struct fb_fix_screeninfo carminefb_fix = {
  73. .id = "Carmine",
  74. .type = FB_TYPE_PACKED_PIXELS,
  75. .visual = FB_VISUAL_TRUECOLOR,
  76. .accel = FB_ACCEL_NONE,
  77. };
  78. static const struct fb_videomode carmine_modedb[] = {
  79. {
  80. .name = "640x480",
  81. .xres = 640,
  82. .yres = 480,
  83. }, {
  84. .name = "800x600",
  85. .xres = 800,
  86. .yres = 600,
  87. },
  88. };
  89. static struct carmine_resolution car_modes[] = {
  90. {
  91. /* 640x480 */
  92. .htp = 800,
  93. .hsp = 672,
  94. .hsw = 96,
  95. .hdp = 640,
  96. .vtr = 525,
  97. .vsp = 490,
  98. .vsw = 2,
  99. .vdp = 480,
  100. .disp_mode = 0x1400,
  101. },
  102. {
  103. /* 800x600 */
  104. .htp = 1060,
  105. .hsp = 864,
  106. .hsw = 72,
  107. .hdp = 800,
  108. .vtr = 628,
  109. .vsp = 601,
  110. .vsw = 2,
  111. .vdp = 600,
  112. .disp_mode = 0x0d00,
  113. }
  114. };
  115. static int carmine_find_mode(const struct fb_var_screeninfo *var)
  116. {
  117. int i;
  118. for (i = 0; i < ARRAY_SIZE(car_modes); i++)
  119. if (car_modes[i].hdp == var->xres &&
  120. car_modes[i].vdp == var->yres)
  121. return i;
  122. return -EINVAL;
  123. }
  124. static void c_set_disp_reg(const struct carmine_fb *par,
  125. u32 offset, u32 val)
  126. {
  127. writel(val, par->display_reg + offset);
  128. }
  129. static u32 c_get_disp_reg(const struct carmine_fb *par,
  130. u32 offset)
  131. {
  132. return readl(par->display_reg + offset);
  133. }
  134. static void c_set_hw_reg(const struct carmine_hw *hw,
  135. u32 offset, u32 val)
  136. {
  137. writel(val, hw->v_regs + offset);
  138. }
  139. static u32 c_get_hw_reg(const struct carmine_hw *hw,
  140. u32 offset)
  141. {
  142. return readl(hw->v_regs + offset);
  143. }
  144. static int carmine_setcolreg(unsigned regno, unsigned red, unsigned green,
  145. unsigned blue, unsigned transp, struct fb_info *info)
  146. {
  147. if (regno >= 16)
  148. return 1;
  149. red >>= 8;
  150. green >>= 8;
  151. blue >>= 8;
  152. transp >>= 8;
  153. ((__be32 *)info->pseudo_palette)[regno] = cpu_to_be32(transp << 24 |
  154. red << 0 | green << 8 | blue << 16);
  155. return 0;
  156. }
  157. static int carmine_check_var(struct fb_var_screeninfo *var,
  158. struct fb_info *info)
  159. {
  160. int ret;
  161. ret = carmine_find_mode(var);
  162. if (ret < 0)
  163. return ret;
  164. if (var->grayscale || var->rotate || var->nonstd)
  165. return -EINVAL;
  166. var->xres_virtual = var->xres;
  167. var->yres_virtual = var->yres;
  168. var->bits_per_pixel = 32;
  169. #ifdef __BIG_ENDIAN
  170. var->transp.offset = 24;
  171. var->red.offset = 0;
  172. var->green.offset = 8;
  173. var->blue.offset = 16;
  174. #else
  175. var->transp.offset = 24;
  176. var->red.offset = 16;
  177. var->green.offset = 8;
  178. var->blue.offset = 0;
  179. #endif
  180. var->red.length = 8;
  181. var->green.length = 8;
  182. var->blue.length = 8;
  183. var->transp.length = 8;
  184. var->red.msb_right = 0;
  185. var->green.msb_right = 0;
  186. var->blue.msb_right = 0;
  187. var->transp.msb_right = 0;
  188. return 0;
  189. }
  190. static void carmine_init_display_param(struct carmine_fb *par)
  191. {
  192. u32 width;
  193. u32 height;
  194. u32 param;
  195. u32 window_size;
  196. u32 soffset = par->smem_offset;
  197. c_set_disp_reg(par, CARMINE_DISP_REG_C_TRANS, 0);
  198. c_set_disp_reg(par, CARMINE_DISP_REG_MLMR_TRANS, 0);
  199. c_set_disp_reg(par, CARMINE_DISP_REG_CURSOR_MODE,
  200. CARMINE_CURSOR0_PRIORITY_MASK |
  201. CARMINE_CURSOR1_PRIORITY_MASK |
  202. CARMINE_CURSOR_CUTZ_MASK);
  203. /* Set default cursor position */
  204. c_set_disp_reg(par, CARMINE_DISP_REG_CUR1_POS, 0 << 16 | 0);
  205. c_set_disp_reg(par, CARMINE_DISP_REG_CUR2_POS, 0 << 16 | 0);
  206. /* Set default display mode */
  207. c_set_disp_reg(par, CARMINE_DISP_REG_L0_EXT_MODE, CARMINE_WINDOW_MODE |
  208. CARMINE_EXT_CMODE_DIRECT24_RGBA);
  209. c_set_disp_reg(par, CARMINE_DISP_REG_L1_EXT_MODE,
  210. CARMINE_EXT_CMODE_DIRECT24_RGBA);
  211. c_set_disp_reg(par, CARMINE_DISP_REG_L2_EXT_MODE, CARMINE_EXTEND_MODE |
  212. CARMINE_EXT_CMODE_DIRECT24_RGBA);
  213. c_set_disp_reg(par, CARMINE_DISP_REG_L3_EXT_MODE, CARMINE_EXTEND_MODE |
  214. CARMINE_EXT_CMODE_DIRECT24_RGBA);
  215. c_set_disp_reg(par, CARMINE_DISP_REG_L4_EXT_MODE, CARMINE_EXTEND_MODE |
  216. CARMINE_EXT_CMODE_DIRECT24_RGBA);
  217. c_set_disp_reg(par, CARMINE_DISP_REG_L5_EXT_MODE, CARMINE_EXTEND_MODE |
  218. CARMINE_EXT_CMODE_DIRECT24_RGBA);
  219. c_set_disp_reg(par, CARMINE_DISP_REG_L6_EXT_MODE, CARMINE_EXTEND_MODE |
  220. CARMINE_EXT_CMODE_DIRECT24_RGBA);
  221. c_set_disp_reg(par, CARMINE_DISP_REG_L7_EXT_MODE, CARMINE_EXTEND_MODE |
  222. CARMINE_EXT_CMODE_DIRECT24_RGBA);
  223. /* Set default frame size to layer mode register */
  224. width = par->res->hdp * 4 / CARMINE_DISP_WIDTH_UNIT;
  225. width = width << CARMINE_DISP_WIDTH_SHIFT;
  226. height = par->res->vdp - 1;
  227. param = width | height;
  228. c_set_disp_reg(par, CARMINE_DISP_REG_L0_MODE_W_H, param);
  229. c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIDTH, width);
  230. c_set_disp_reg(par, CARMINE_DISP_REG_L2_MODE_W_H, param);
  231. c_set_disp_reg(par, CARMINE_DISP_REG_L3_MODE_W_H, param);
  232. c_set_disp_reg(par, CARMINE_DISP_REG_L4_MODE_W_H, param);
  233. c_set_disp_reg(par, CARMINE_DISP_REG_L5_MODE_W_H, param);
  234. c_set_disp_reg(par, CARMINE_DISP_REG_L6_MODE_W_H, param);
  235. c_set_disp_reg(par, CARMINE_DISP_REG_L7_MODE_W_H, param);
  236. /* Set default pos and size */
  237. window_size = (par->res->vdp - 1) << CARMINE_DISP_WIN_H_SHIFT;
  238. window_size |= par->res->hdp;
  239. c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_POS, 0);
  240. c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_SIZE, window_size);
  241. c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_POS, 0);
  242. c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_SIZE, window_size);
  243. c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_POS, 0);
  244. c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_SIZE, window_size);
  245. c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_POS, 0);
  246. c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_SIZE, window_size);
  247. c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_POS, 0);
  248. c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_SIZE, window_size);
  249. c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_POS, 0);
  250. c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_SIZE, window_size);
  251. c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_POS, 0);
  252. c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_SIZE, window_size);
  253. c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_POS, 0);
  254. c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_SIZE, window_size);
  255. /* Set default origin address */
  256. c_set_disp_reg(par, CARMINE_DISP_REG_L0_ORG_ADR, soffset);
  257. c_set_disp_reg(par, CARMINE_DISP_REG_L1_ORG_ADR, soffset);
  258. c_set_disp_reg(par, CARMINE_DISP_REG_L2_ORG_ADR1, soffset);
  259. c_set_disp_reg(par, CARMINE_DISP_REG_L3_ORG_ADR1, soffset);
  260. c_set_disp_reg(par, CARMINE_DISP_REG_L4_ORG_ADR1, soffset);
  261. c_set_disp_reg(par, CARMINE_DISP_REG_L5_ORG_ADR1, soffset);
  262. c_set_disp_reg(par, CARMINE_DISP_REG_L6_ORG_ADR1, soffset);
  263. c_set_disp_reg(par, CARMINE_DISP_REG_L7_ORG_ADR1, soffset);
  264. /* Set default display address */
  265. c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_ADR, soffset);
  266. c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_ADR1, soffset);
  267. c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_ADR1, soffset);
  268. c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_ADR1, soffset);
  269. c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_ADR1, soffset);
  270. c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_ADR0, soffset);
  271. c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_ADR0, soffset);
  272. /* Set default display position */
  273. c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_POS, 0);
  274. c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_POS, 0);
  275. c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_POS, 0);
  276. c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_POS, 0);
  277. c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_POS, 0);
  278. c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_POS, 0);
  279. c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_POS, 0);
  280. /* Set default blend mode */
  281. c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L0, 0);
  282. c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L1, 0);
  283. c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L2, 0);
  284. c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L3, 0);
  285. c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L4, 0);
  286. c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L5, 0);
  287. c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L6, 0);
  288. c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L7, 0);
  289. /* default transparency mode */
  290. c_set_disp_reg(par, CARMINE_DISP_REG_L0_TRANS, 0);
  291. c_set_disp_reg(par, CARMINE_DISP_REG_L1_TRANS, 0);
  292. c_set_disp_reg(par, CARMINE_DISP_REG_L2_TRANS, 0);
  293. c_set_disp_reg(par, CARMINE_DISP_REG_L3_TRANS, 0);
  294. c_set_disp_reg(par, CARMINE_DISP_REG_L4_TRANS, 0);
  295. c_set_disp_reg(par, CARMINE_DISP_REG_L5_TRANS, 0);
  296. c_set_disp_reg(par, CARMINE_DISP_REG_L6_TRANS, 0);
  297. c_set_disp_reg(par, CARMINE_DISP_REG_L7_TRANS, 0);
  298. /* Set default read skip parameter */
  299. c_set_disp_reg(par, CARMINE_DISP_REG_L0RM, 0);
  300. c_set_disp_reg(par, CARMINE_DISP_REG_L2RM, 0);
  301. c_set_disp_reg(par, CARMINE_DISP_REG_L3RM, 0);
  302. c_set_disp_reg(par, CARMINE_DISP_REG_L4RM, 0);
  303. c_set_disp_reg(par, CARMINE_DISP_REG_L5RM, 0);
  304. c_set_disp_reg(par, CARMINE_DISP_REG_L6RM, 0);
  305. c_set_disp_reg(par, CARMINE_DISP_REG_L7RM, 0);
  306. c_set_disp_reg(par, CARMINE_DISP_REG_L0PX, 0);
  307. c_set_disp_reg(par, CARMINE_DISP_REG_L2PX, 0);
  308. c_set_disp_reg(par, CARMINE_DISP_REG_L3PX, 0);
  309. c_set_disp_reg(par, CARMINE_DISP_REG_L4PX, 0);
  310. c_set_disp_reg(par, CARMINE_DISP_REG_L5PX, 0);
  311. c_set_disp_reg(par, CARMINE_DISP_REG_L6PX, 0);
  312. c_set_disp_reg(par, CARMINE_DISP_REG_L7PX, 0);
  313. c_set_disp_reg(par, CARMINE_DISP_REG_L0PY, 0);
  314. c_set_disp_reg(par, CARMINE_DISP_REG_L2PY, 0);
  315. c_set_disp_reg(par, CARMINE_DISP_REG_L3PY, 0);
  316. c_set_disp_reg(par, CARMINE_DISP_REG_L4PY, 0);
  317. c_set_disp_reg(par, CARMINE_DISP_REG_L5PY, 0);
  318. c_set_disp_reg(par, CARMINE_DISP_REG_L6PY, 0);
  319. c_set_disp_reg(par, CARMINE_DISP_REG_L7PY, 0);
  320. }
  321. static void set_display_parameters(struct carmine_fb *par)
  322. {
  323. u32 mode;
  324. u32 hdp, vdp, htp, hsp, hsw, vtr, vsp, vsw;
  325. /*
  326. * display timing. Parameters are decreased by one because hardware
  327. * spec is 0 to (n - 1)
  328. * */
  329. hdp = par->res->hdp - 1;
  330. vdp = par->res->vdp - 1;
  331. htp = par->res->htp - 1;
  332. hsp = par->res->hsp - 1;
  333. hsw = par->res->hsw - 1;
  334. vtr = par->res->vtr - 1;
  335. vsp = par->res->vsp - 1;
  336. vsw = par->res->vsw - 1;
  337. c_set_disp_reg(par, CARMINE_DISP_REG_H_TOTAL,
  338. htp << CARMINE_DISP_HTP_SHIFT);
  339. c_set_disp_reg(par, CARMINE_DISP_REG_H_PERIOD,
  340. (hdp << CARMINE_DISP_HDB_SHIFT) | hdp);
  341. c_set_disp_reg(par, CARMINE_DISP_REG_V_H_W_H_POS,
  342. (vsw << CARMINE_DISP_VSW_SHIFT) |
  343. (hsw << CARMINE_DISP_HSW_SHIFT) |
  344. (hsp));
  345. c_set_disp_reg(par, CARMINE_DISP_REG_V_TOTAL,
  346. vtr << CARMINE_DISP_VTR_SHIFT);
  347. c_set_disp_reg(par, CARMINE_DISP_REG_V_PERIOD_POS,
  348. (vdp << CARMINE_DISP_VDP_SHIFT) | vsp);
  349. /* clock */
  350. mode = c_get_disp_reg(par, CARMINE_DISP_REG_DCM1);
  351. mode = (mode & ~CARMINE_DISP_DCM_MASK) |
  352. (par->res->disp_mode & CARMINE_DISP_DCM_MASK);
  353. /* enable video output and layer 0 */
  354. mode |= CARMINE_DEN | CARMINE_L0E;
  355. c_set_disp_reg(par, CARMINE_DISP_REG_DCM1, mode);
  356. }
  357. static int carmine_set_par(struct fb_info *info)
  358. {
  359. struct carmine_fb *par = info->par;
  360. int ret;
  361. ret = carmine_find_mode(&info->var);
  362. if (ret < 0)
  363. return ret;
  364. par->new_mode = ret;
  365. if (par->cur_mode != par->new_mode) {
  366. par->cur_mode = par->new_mode;
  367. par->res = &car_modes[par->new_mode];
  368. carmine_init_display_param(par);
  369. set_display_parameters(par);
  370. }
  371. info->fix.line_length = info->var.xres * info->var.bits_per_pixel / 8;
  372. return 0;
  373. }
  374. static int init_hardware(struct carmine_hw *hw)
  375. {
  376. u32 flags;
  377. u32 loops;
  378. u32 ret;
  379. /* Initialize Carmine */
  380. /* Sets internal clock */
  381. c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE,
  382. CARMINE_DFLT_IP_CLOCK_ENABLE);
  383. /* Video signal output is turned off */
  384. c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
  385. c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
  386. /* Software reset */
  387. c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 1);
  388. c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 0);
  389. /* I/O mode settings */
  390. flags = CARMINE_DFLT_IP_DCTL_IO_CONT1 << 16 |
  391. CARMINE_DFLT_IP_DCTL_IO_CONT0;
  392. c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_IOCONT1_IOCONT0,
  393. flags);
  394. /* DRAM initial sequence */
  395. flags = CARMINE_DFLT_IP_DCTL_MODE << 16 | CARMINE_DFLT_IP_DCTL_ADD;
  396. c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD,
  397. flags);
  398. flags = CARMINE_DFLT_IP_DCTL_SET_TIME1 << 16 |
  399. CARMINE_DFLT_IP_DCTL_EMODE;
  400. c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_SETTIME1_EMODE,
  401. flags);
  402. flags = CARMINE_DFLT_IP_DCTL_REFRESH << 16 |
  403. CARMINE_DFLT_IP_DCTL_SET_TIME2;
  404. c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_REFRESH_SETTIME2,
  405. flags);
  406. flags = CARMINE_DFLT_IP_DCTL_RESERVE2 << 16 |
  407. CARMINE_DFLT_IP_DCTL_FIFO_DEPTH;
  408. c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV2_RSV1, flags);
  409. flags = CARMINE_DFLT_IP_DCTL_DDRIF2 << 16 | CARMINE_DFLT_IP_DCTL_DDRIF1;
  410. c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_DDRIF2_DDRIF1,
  411. flags);
  412. flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
  413. CARMINE_DFLT_IP_DCTL_STATES;
  414. c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
  415. flags);
  416. /* Executes DLL reset */
  417. if (CARMINE_DCTL_DLL_RESET) {
  418. for (loops = 0; loops < CARMINE_DCTL_INIT_WAIT_LIMIT; loops++) {
  419. ret = c_get_hw_reg(hw, CARMINE_DCTL_REG +
  420. CARMINE_DCTL_REG_RSV0_STATES);
  421. ret &= CARMINE_DCTL_REG_STATES_MASK;
  422. if (!ret)
  423. break;
  424. mdelay(CARMINE_DCTL_INIT_WAIT_INTERVAL);
  425. }
  426. if (loops >= CARMINE_DCTL_INIT_WAIT_LIMIT) {
  427. printk(KERN_ERR "DRAM init failed\n");
  428. return -EIO;
  429. }
  430. }
  431. flags = CARMINE_DFLT_IP_DCTL_MODE_AFT_RST << 16 |
  432. CARMINE_DFLT_IP_DCTL_ADD;
  433. c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD, flags);
  434. flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
  435. CARMINE_DFLT_IP_DCTL_STATES_AFT_RST;
  436. c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
  437. flags);
  438. /* Initialize the write back register */
  439. c_set_hw_reg(hw, CARMINE_WB_REG + CARMINE_WB_REG_WBM,
  440. CARMINE_WB_REG_WBM_DEFAULT);
  441. /* Initialize the Kottos registers */
  442. c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRINTM, 0);
  443. c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRERRM, 0);
  444. /* Set DC offsets */
  445. c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PX, 0);
  446. c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PY, 0);
  447. c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LX, 0);
  448. c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LY, 0);
  449. c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TX, 0);
  450. c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TY, 0);
  451. return 0;
  452. }
  453. static const struct fb_ops carminefb_ops = {
  454. .owner = THIS_MODULE,
  455. .fb_fillrect = cfb_fillrect,
  456. .fb_copyarea = cfb_copyarea,
  457. .fb_imageblit = cfb_imageblit,
  458. .fb_check_var = carmine_check_var,
  459. .fb_set_par = carmine_set_par,
  460. .fb_setcolreg = carmine_setcolreg,
  461. };
  462. static int alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
  463. int smem_offset, struct device *device,
  464. struct fb_info **rinfo)
  465. {
  466. int ret;
  467. struct fb_info *info;
  468. struct carmine_fb *par;
  469. info = framebuffer_alloc(sizeof *par, device);
  470. if (!info)
  471. return -ENOMEM;
  472. par = info->par;
  473. par->display_reg = regs;
  474. par->smem_offset = smem_offset;
  475. info->screen_base = smem_base + smem_offset;
  476. info->screen_size = CARMINE_DISPLAY_MEM;
  477. info->fbops = &carminefb_ops;
  478. info->fix = carminefb_fix;
  479. info->pseudo_palette = par->pseudo_palette;
  480. info->flags = FBINFO_DEFAULT;
  481. ret = fb_alloc_cmap(&info->cmap, 256, 1);
  482. if (ret < 0)
  483. goto err_free_fb;
  484. if (fb_mode >= ARRAY_SIZE(carmine_modedb))
  485. fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
  486. par->cur_mode = par->new_mode = ~0;
  487. ret = fb_find_mode(&info->var, info, fb_mode_str, carmine_modedb,
  488. ARRAY_SIZE(carmine_modedb),
  489. &carmine_modedb[fb_mode], 32);
  490. if (!ret || ret == 4) {
  491. ret = -EINVAL;
  492. goto err_dealloc_cmap;
  493. }
  494. fb_videomode_to_modelist(carmine_modedb, ARRAY_SIZE(carmine_modedb),
  495. &info->modelist);
  496. ret = register_framebuffer(info);
  497. if (ret < 0)
  498. goto err_dealloc_cmap;
  499. fb_info(info, "%s frame buffer device\n", info->fix.id);
  500. *rinfo = info;
  501. return 0;
  502. err_dealloc_cmap:
  503. fb_dealloc_cmap(&info->cmap);
  504. err_free_fb:
  505. framebuffer_release(info);
  506. return ret;
  507. }
  508. static void cleanup_fb_device(struct fb_info *info)
  509. {
  510. if (info) {
  511. unregister_framebuffer(info);
  512. fb_dealloc_cmap(&info->cmap);
  513. framebuffer_release(info);
  514. }
  515. }
  516. static int carminefb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
  517. {
  518. struct carmine_hw *hw;
  519. struct device *device = &dev->dev;
  520. struct fb_info *info;
  521. int ret;
  522. ret = pci_enable_device(dev);
  523. if (ret)
  524. return ret;
  525. ret = -ENOMEM;
  526. hw = kzalloc(sizeof *hw, GFP_KERNEL);
  527. if (!hw)
  528. goto err_enable_pci;
  529. carminefb_fix.mmio_start = pci_resource_start(dev, CARMINE_CONFIG_BAR);
  530. carminefb_fix.mmio_len = pci_resource_len(dev, CARMINE_CONFIG_BAR);
  531. if (!request_mem_region(carminefb_fix.mmio_start,
  532. carminefb_fix.mmio_len,
  533. "carminefb regbase")) {
  534. printk(KERN_ERR "carminefb: Can't reserve regbase.\n");
  535. ret = -EBUSY;
  536. goto err_free_hw;
  537. }
  538. hw->v_regs = ioremap(carminefb_fix.mmio_start,
  539. carminefb_fix.mmio_len);
  540. if (!hw->v_regs) {
  541. printk(KERN_ERR "carminefb: Can't remap %s register.\n",
  542. carminefb_fix.id);
  543. goto err_free_reg_mmio;
  544. }
  545. carminefb_fix.smem_start = pci_resource_start(dev, CARMINE_MEMORY_BAR);
  546. carminefb_fix.smem_len = pci_resource_len(dev, CARMINE_MEMORY_BAR);
  547. /* The memory area tends to be very large (256 MiB). Remap only what
  548. * is required for that largest resolution to avoid remaps at run
  549. * time
  550. */
  551. if (carminefb_fix.smem_len > CARMINE_TOTAL_DIPLAY_MEM)
  552. carminefb_fix.smem_len = CARMINE_TOTAL_DIPLAY_MEM;
  553. else if (carminefb_fix.smem_len < CARMINE_TOTAL_DIPLAY_MEM) {
  554. printk(KERN_ERR "carminefb: Memory bar is only %d bytes, %d "
  555. "are required.", carminefb_fix.smem_len,
  556. CARMINE_TOTAL_DIPLAY_MEM);
  557. goto err_unmap_vregs;
  558. }
  559. if (!request_mem_region(carminefb_fix.smem_start,
  560. carminefb_fix.smem_len, "carminefb smem")) {
  561. printk(KERN_ERR "carminefb: Can't reserve smem.\n");
  562. goto err_unmap_vregs;
  563. }
  564. hw->screen_mem = ioremap(carminefb_fix.smem_start,
  565. carminefb_fix.smem_len);
  566. if (!hw->screen_mem) {
  567. printk(KERN_ERR "carmine: Can't ioremap smem area.\n");
  568. goto err_reg_smem;
  569. }
  570. ret = init_hardware(hw);
  571. if (ret)
  572. goto err_unmap_screen;
  573. info = NULL;
  574. if (fb_displays & CARMINE_USE_DISPLAY0) {
  575. ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP0_REG,
  576. hw->screen_mem, CARMINE_DISPLAY_MEM * 0,
  577. device, &info);
  578. if (ret)
  579. goto err_deinit_hw;
  580. }
  581. hw->fb[0] = info;
  582. info = NULL;
  583. if (fb_displays & CARMINE_USE_DISPLAY1) {
  584. ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP1_REG,
  585. hw->screen_mem, CARMINE_DISPLAY_MEM * 1,
  586. device, &info);
  587. if (ret)
  588. goto err_cleanup_fb0;
  589. }
  590. hw->fb[1] = info;
  591. info = NULL;
  592. pci_set_drvdata(dev, hw);
  593. return 0;
  594. err_cleanup_fb0:
  595. cleanup_fb_device(hw->fb[0]);
  596. err_deinit_hw:
  597. /* disable clock, etc */
  598. c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
  599. err_unmap_screen:
  600. iounmap(hw->screen_mem);
  601. err_reg_smem:
  602. release_mem_region(carminefb_fix.smem_start, carminefb_fix.smem_len);
  603. err_unmap_vregs:
  604. iounmap(hw->v_regs);
  605. err_free_reg_mmio:
  606. release_mem_region(carminefb_fix.mmio_start, carminefb_fix.mmio_len);
  607. err_free_hw:
  608. kfree(hw);
  609. err_enable_pci:
  610. pci_disable_device(dev);
  611. return ret;
  612. }
  613. static void carminefb_remove(struct pci_dev *dev)
  614. {
  615. struct carmine_hw *hw = pci_get_drvdata(dev);
  616. struct fb_fix_screeninfo fix;
  617. int i;
  618. /* in case we use only fb1 and not fb1 */
  619. if (hw->fb[0])
  620. fix = hw->fb[0]->fix;
  621. else
  622. fix = hw->fb[1]->fix;
  623. /* deactivate display(s) and switch clocks */
  624. c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
  625. c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
  626. c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
  627. for (i = 0; i < MAX_DISPLAY; i++)
  628. cleanup_fb_device(hw->fb[i]);
  629. iounmap(hw->screen_mem);
  630. release_mem_region(fix.smem_start, fix.smem_len);
  631. iounmap(hw->v_regs);
  632. release_mem_region(fix.mmio_start, fix.mmio_len);
  633. pci_disable_device(dev);
  634. kfree(hw);
  635. }
  636. #define PCI_VENDOR_ID_FUJITU_LIMITED 0x10cf
  637. static struct pci_device_id carmine_devices[] = {
  638. {
  639. PCI_DEVICE(PCI_VENDOR_ID_FUJITU_LIMITED, 0x202b)},
  640. {0, 0, 0, 0, 0, 0, 0}
  641. };
  642. MODULE_DEVICE_TABLE(pci, carmine_devices);
  643. static struct pci_driver carmine_pci_driver = {
  644. .name = "carminefb",
  645. .id_table = carmine_devices,
  646. .probe = carminefb_probe,
  647. .remove = carminefb_remove,
  648. };
  649. static int __init carminefb_init(void)
  650. {
  651. if (!(fb_displays &
  652. (CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1))) {
  653. printk(KERN_ERR "If you disable both displays than you don't "
  654. "need the driver at all\n");
  655. return -EINVAL;
  656. }
  657. return pci_register_driver(&carmine_pci_driver);
  658. }
  659. module_init(carminefb_init);
  660. static void __exit carminefb_cleanup(void)
  661. {
  662. pci_unregister_driver(&carmine_pci_driver);
  663. }
  664. module_exit(carminefb_cleanup);
  665. MODULE_AUTHOR("Sebastian Siewior <bigeasy@linutronix.de>");
  666. MODULE_DESCRIPTION("Framebuffer driver for Fujitsu Carmine based devices");
  667. MODULE_LICENSE("GPL v2");