dss.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. /*
  2. * linux/drivers/video/omap2/dss/dss.c
  3. *
  4. * Copyright (C) 2009 Nokia Corporation
  5. * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
  6. *
  7. * Some code and ideas taken from drivers/video/omap/ driver
  8. * by Imre Deak.
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License version 2 as published by
  12. * the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  17. * more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along with
  20. * this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. #define DSS_SUBSYS_NAME "DSS"
  23. #include <linux/kernel.h>
  24. #include <linux/io.h>
  25. #include <linux/err.h>
  26. #include <linux/delay.h>
  27. #include <linux/seq_file.h>
  28. #include <linux/clk.h>
  29. #include <linux/platform_device.h>
  30. #include <linux/pm_runtime.h>
  31. #include <video/omapdss.h>
  32. #include <plat/clock.h>
  33. #include "dss.h"
  34. #include "dss_features.h"
  35. #define DSS_SZ_REGS SZ_512
  36. struct dss_reg {
  37. u16 idx;
  38. };
  39. #define DSS_REG(idx) ((const struct dss_reg) { idx })
  40. #define DSS_REVISION DSS_REG(0x0000)
  41. #define DSS_SYSCONFIG DSS_REG(0x0010)
  42. #define DSS_SYSSTATUS DSS_REG(0x0014)
  43. #define DSS_CONTROL DSS_REG(0x0040)
  44. #define DSS_SDI_CONTROL DSS_REG(0x0044)
  45. #define DSS_PLL_CONTROL DSS_REG(0x0048)
  46. #define DSS_SDI_STATUS DSS_REG(0x005C)
  47. #define REG_GET(idx, start, end) \
  48. FLD_GET(dss_read_reg(idx), start, end)
  49. #define REG_FLD_MOD(idx, val, start, end) \
  50. dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
  51. static struct {
  52. struct platform_device *pdev;
  53. void __iomem *base;
  54. int ctx_loss_cnt;
  55. struct clk *dpll4_m4_ck;
  56. struct clk *dss_clk;
  57. unsigned long cache_req_pck;
  58. unsigned long cache_prate;
  59. struct dss_clock_info cache_dss_cinfo;
  60. struct dispc_clock_info cache_dispc_cinfo;
  61. enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
  62. enum omap_dss_clk_source dispc_clk_source;
  63. enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
  64. u32 ctx[DSS_SZ_REGS / sizeof(u32)];
  65. } dss;
  66. static const char * const dss_generic_clk_source_names[] = {
  67. [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC",
  68. [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI",
  69. [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
  70. };
  71. static inline void dss_write_reg(const struct dss_reg idx, u32 val)
  72. {
  73. __raw_writel(val, dss.base + idx.idx);
  74. }
  75. static inline u32 dss_read_reg(const struct dss_reg idx)
  76. {
  77. return __raw_readl(dss.base + idx.idx);
  78. }
  79. #define SR(reg) \
  80. dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
  81. #define RR(reg) \
  82. dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
  83. static void dss_save_context(void)
  84. {
  85. DSSDBG("dss_save_context\n");
  86. SR(CONTROL);
  87. if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
  88. OMAP_DISPLAY_TYPE_SDI) {
  89. SR(SDI_CONTROL);
  90. SR(PLL_CONTROL);
  91. }
  92. }
  93. static void dss_restore_context(void)
  94. {
  95. DSSDBG("dss_restore_context\n");
  96. RR(CONTROL);
  97. if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
  98. OMAP_DISPLAY_TYPE_SDI) {
  99. RR(SDI_CONTROL);
  100. RR(PLL_CONTROL);
  101. }
  102. }
  103. #undef SR
  104. #undef RR
  105. void dss_sdi_init(u8 datapairs)
  106. {
  107. u32 l;
  108. BUG_ON(datapairs > 3 || datapairs < 1);
  109. l = dss_read_reg(DSS_SDI_CONTROL);
  110. l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
  111. l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
  112. l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
  113. dss_write_reg(DSS_SDI_CONTROL, l);
  114. l = dss_read_reg(DSS_PLL_CONTROL);
  115. l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
  116. l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
  117. l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
  118. dss_write_reg(DSS_PLL_CONTROL, l);
  119. }
  120. int dss_sdi_enable(void)
  121. {
  122. unsigned long timeout;
  123. dispc_pck_free_enable(1);
  124. /* Reset SDI PLL */
  125. REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
  126. udelay(1); /* wait 2x PCLK */
  127. /* Lock SDI PLL */
  128. REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
  129. /* Waiting for PLL lock request to complete */
  130. timeout = jiffies + msecs_to_jiffies(500);
  131. while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
  132. if (time_after_eq(jiffies, timeout)) {
  133. DSSERR("PLL lock request timed out\n");
  134. goto err1;
  135. }
  136. }
  137. /* Clearing PLL_GO bit */
  138. REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
  139. /* Waiting for PLL to lock */
  140. timeout = jiffies + msecs_to_jiffies(500);
  141. while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
  142. if (time_after_eq(jiffies, timeout)) {
  143. DSSERR("PLL lock timed out\n");
  144. goto err1;
  145. }
  146. }
  147. dispc_lcd_enable_signal(1);
  148. /* Waiting for SDI reset to complete */
  149. timeout = jiffies + msecs_to_jiffies(500);
  150. while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
  151. if (time_after_eq(jiffies, timeout)) {
  152. DSSERR("SDI reset timed out\n");
  153. goto err2;
  154. }
  155. }
  156. return 0;
  157. err2:
  158. dispc_lcd_enable_signal(0);
  159. err1:
  160. /* Reset SDI PLL */
  161. REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
  162. dispc_pck_free_enable(0);
  163. return -ETIMEDOUT;
  164. }
  165. void dss_sdi_disable(void)
  166. {
  167. dispc_lcd_enable_signal(0);
  168. dispc_pck_free_enable(0);
  169. /* Reset SDI PLL */
  170. REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
  171. }
  172. const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
  173. {
  174. return dss_generic_clk_source_names[clk_src];
  175. }
  176. void dss_dump_clocks(struct seq_file *s)
  177. {
  178. unsigned long dpll4_ck_rate;
  179. unsigned long dpll4_m4_ck_rate;
  180. const char *fclk_name, *fclk_real_name;
  181. unsigned long fclk_rate;
  182. if (dss_runtime_get())
  183. return;
  184. seq_printf(s, "- DSS -\n");
  185. fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
  186. fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
  187. fclk_rate = clk_get_rate(dss.dss_clk);
  188. if (dss.dpll4_m4_ck) {
  189. dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
  190. dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
  191. seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
  192. if (cpu_is_omap3630() || cpu_is_omap44xx())
  193. seq_printf(s, "%s (%s) = %lu / %lu = %lu\n",
  194. fclk_name, fclk_real_name,
  195. dpll4_ck_rate,
  196. dpll4_ck_rate / dpll4_m4_ck_rate,
  197. fclk_rate);
  198. else
  199. seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
  200. fclk_name, fclk_real_name,
  201. dpll4_ck_rate,
  202. dpll4_ck_rate / dpll4_m4_ck_rate,
  203. fclk_rate);
  204. } else {
  205. seq_printf(s, "%s (%s) = %lu\n",
  206. fclk_name, fclk_real_name,
  207. fclk_rate);
  208. }
  209. dss_runtime_put();
  210. }
  211. void dss_dump_regs(struct seq_file *s)
  212. {
  213. #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
  214. if (dss_runtime_get())
  215. return;
  216. DUMPREG(DSS_REVISION);
  217. DUMPREG(DSS_SYSCONFIG);
  218. DUMPREG(DSS_SYSSTATUS);
  219. DUMPREG(DSS_CONTROL);
  220. if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
  221. OMAP_DISPLAY_TYPE_SDI) {
  222. DUMPREG(DSS_SDI_CONTROL);
  223. DUMPREG(DSS_PLL_CONTROL);
  224. DUMPREG(DSS_SDI_STATUS);
  225. }
  226. dss_runtime_put();
  227. #undef DUMPREG
  228. }
  229. void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
  230. {
  231. struct platform_device *dsidev;
  232. int b;
  233. u8 start, end;
  234. switch (clk_src) {
  235. case OMAP_DSS_CLK_SRC_FCK:
  236. b = 0;
  237. break;
  238. case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
  239. b = 1;
  240. dsidev = dsi_get_dsidev_from_id(0);
  241. dsi_wait_pll_hsdiv_dispc_active(dsidev);
  242. break;
  243. case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
  244. b = 2;
  245. dsidev = dsi_get_dsidev_from_id(1);
  246. dsi_wait_pll_hsdiv_dispc_active(dsidev);
  247. break;
  248. default:
  249. BUG();
  250. }
  251. dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
  252. REG_FLD_MOD(DSS_CONTROL, b, start, end); /* DISPC_CLK_SWITCH */
  253. dss.dispc_clk_source = clk_src;
  254. }
  255. void dss_select_dsi_clk_source(int dsi_module,
  256. enum omap_dss_clk_source clk_src)
  257. {
  258. struct platform_device *dsidev;
  259. int b;
  260. switch (clk_src) {
  261. case OMAP_DSS_CLK_SRC_FCK:
  262. b = 0;
  263. break;
  264. case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
  265. BUG_ON(dsi_module != 0);
  266. b = 1;
  267. dsidev = dsi_get_dsidev_from_id(0);
  268. dsi_wait_pll_hsdiv_dsi_active(dsidev);
  269. break;
  270. case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
  271. BUG_ON(dsi_module != 1);
  272. b = 1;
  273. dsidev = dsi_get_dsidev_from_id(1);
  274. dsi_wait_pll_hsdiv_dsi_active(dsidev);
  275. break;
  276. default:
  277. BUG();
  278. }
  279. REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */
  280. dss.dsi_clk_source[dsi_module] = clk_src;
  281. }
  282. void dss_select_lcd_clk_source(enum omap_channel channel,
  283. enum omap_dss_clk_source clk_src)
  284. {
  285. struct platform_device *dsidev;
  286. int b, ix, pos;
  287. if (!dss_has_feature(FEAT_LCD_CLK_SRC))
  288. return;
  289. switch (clk_src) {
  290. case OMAP_DSS_CLK_SRC_FCK:
  291. b = 0;
  292. break;
  293. case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
  294. BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
  295. b = 1;
  296. dsidev = dsi_get_dsidev_from_id(0);
  297. dsi_wait_pll_hsdiv_dispc_active(dsidev);
  298. break;
  299. case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
  300. BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2);
  301. b = 1;
  302. dsidev = dsi_get_dsidev_from_id(1);
  303. dsi_wait_pll_hsdiv_dispc_active(dsidev);
  304. break;
  305. default:
  306. BUG();
  307. }
  308. pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12;
  309. REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */
  310. ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
  311. dss.lcd_clk_source[ix] = clk_src;
  312. }
  313. enum omap_dss_clk_source dss_get_dispc_clk_source(void)
  314. {
  315. return dss.dispc_clk_source;
  316. }
  317. enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
  318. {
  319. return dss.dsi_clk_source[dsi_module];
  320. }
  321. enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
  322. {
  323. if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
  324. int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
  325. return dss.lcd_clk_source[ix];
  326. } else {
  327. /* LCD_CLK source is the same as DISPC_FCLK source for
  328. * OMAP2 and OMAP3 */
  329. return dss.dispc_clk_source;
  330. }
  331. }
  332. /* calculate clock rates using dividers in cinfo */
  333. int dss_calc_clock_rates(struct dss_clock_info *cinfo)
  334. {
  335. if (dss.dpll4_m4_ck) {
  336. unsigned long prate;
  337. u16 fck_div_max = 16;
  338. if (cpu_is_omap3630() || cpu_is_omap44xx())
  339. fck_div_max = 32;
  340. if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0)
  341. return -EINVAL;
  342. prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
  343. cinfo->fck = prate / cinfo->fck_div;
  344. } else {
  345. if (cinfo->fck_div != 0)
  346. return -EINVAL;
  347. cinfo->fck = clk_get_rate(dss.dss_clk);
  348. }
  349. return 0;
  350. }
  351. int dss_set_clock_div(struct dss_clock_info *cinfo)
  352. {
  353. if (dss.dpll4_m4_ck) {
  354. unsigned long prate;
  355. int r;
  356. prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
  357. DSSDBG("dpll4_m4 = %ld\n", prate);
  358. r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
  359. if (r)
  360. return r;
  361. } else {
  362. if (cinfo->fck_div != 0)
  363. return -EINVAL;
  364. }
  365. DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
  366. return 0;
  367. }
  368. int dss_get_clock_div(struct dss_clock_info *cinfo)
  369. {
  370. cinfo->fck = clk_get_rate(dss.dss_clk);
  371. if (dss.dpll4_m4_ck) {
  372. unsigned long prate;
  373. prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
  374. if (cpu_is_omap3630() || cpu_is_omap44xx())
  375. cinfo->fck_div = prate / (cinfo->fck);
  376. else
  377. cinfo->fck_div = prate / (cinfo->fck / 2);
  378. } else {
  379. cinfo->fck_div = 0;
  380. }
  381. return 0;
  382. }
  383. unsigned long dss_get_dpll4_rate(void)
  384. {
  385. if (dss.dpll4_m4_ck)
  386. return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
  387. else
  388. return 0;
  389. }
  390. int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
  391. struct dss_clock_info *dss_cinfo,
  392. struct dispc_clock_info *dispc_cinfo)
  393. {
  394. unsigned long prate;
  395. struct dss_clock_info best_dss;
  396. struct dispc_clock_info best_dispc;
  397. unsigned long fck, max_dss_fck;
  398. u16 fck_div, fck_div_max = 16;
  399. int match = 0;
  400. int min_fck_per_pck;
  401. prate = dss_get_dpll4_rate();
  402. max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
  403. fck = clk_get_rate(dss.dss_clk);
  404. if (req_pck == dss.cache_req_pck &&
  405. ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
  406. dss.cache_dss_cinfo.fck == fck)) {
  407. DSSDBG("dispc clock info found from cache.\n");
  408. *dss_cinfo = dss.cache_dss_cinfo;
  409. *dispc_cinfo = dss.cache_dispc_cinfo;
  410. return 0;
  411. }
  412. min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
  413. if (min_fck_per_pck &&
  414. req_pck * min_fck_per_pck > max_dss_fck) {
  415. DSSERR("Requested pixel clock not possible with the current "
  416. "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
  417. "the constraint off.\n");
  418. min_fck_per_pck = 0;
  419. }
  420. retry:
  421. memset(&best_dss, 0, sizeof(best_dss));
  422. memset(&best_dispc, 0, sizeof(best_dispc));
  423. if (dss.dpll4_m4_ck == NULL) {
  424. struct dispc_clock_info cur_dispc;
  425. /* XXX can we change the clock on omap2? */
  426. fck = clk_get_rate(dss.dss_clk);
  427. fck_div = 1;
  428. dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
  429. match = 1;
  430. best_dss.fck = fck;
  431. best_dss.fck_div = fck_div;
  432. best_dispc = cur_dispc;
  433. goto found;
  434. } else {
  435. if (cpu_is_omap3630() || cpu_is_omap44xx())
  436. fck_div_max = 32;
  437. for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
  438. struct dispc_clock_info cur_dispc;
  439. if (fck_div_max == 32)
  440. fck = prate / fck_div;
  441. else
  442. fck = prate / fck_div * 2;
  443. if (fck > max_dss_fck)
  444. continue;
  445. if (min_fck_per_pck &&
  446. fck < req_pck * min_fck_per_pck)
  447. continue;
  448. match = 1;
  449. dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
  450. if (abs(cur_dispc.pck - req_pck) <
  451. abs(best_dispc.pck - req_pck)) {
  452. best_dss.fck = fck;
  453. best_dss.fck_div = fck_div;
  454. best_dispc = cur_dispc;
  455. if (cur_dispc.pck == req_pck)
  456. goto found;
  457. }
  458. }
  459. }
  460. found:
  461. if (!match) {
  462. if (min_fck_per_pck) {
  463. DSSERR("Could not find suitable clock settings.\n"
  464. "Turning FCK/PCK constraint off and"
  465. "trying again.\n");
  466. min_fck_per_pck = 0;
  467. goto retry;
  468. }
  469. DSSERR("Could not find suitable clock settings.\n");
  470. return -EINVAL;
  471. }
  472. if (dss_cinfo)
  473. *dss_cinfo = best_dss;
  474. if (dispc_cinfo)
  475. *dispc_cinfo = best_dispc;
  476. dss.cache_req_pck = req_pck;
  477. dss.cache_prate = prate;
  478. dss.cache_dss_cinfo = best_dss;
  479. dss.cache_dispc_cinfo = best_dispc;
  480. return 0;
  481. }
  482. void dss_set_venc_output(enum omap_dss_venc_type type)
  483. {
  484. int l = 0;
  485. if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
  486. l = 0;
  487. else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
  488. l = 1;
  489. else
  490. BUG();
  491. /* venc out selection. 0 = comp, 1 = svideo */
  492. REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
  493. }
  494. void dss_set_dac_pwrdn_bgz(bool enable)
  495. {
  496. REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
  497. }
  498. void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
  499. {
  500. REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */
  501. }
  502. /* CONTEXT */
  503. static void dss_init_ctx_loss_count(void)
  504. {
  505. struct device *dev = &dss.pdev->dev;
  506. struct omap_display_platform_data *pdata = dev->platform_data;
  507. struct omap_dss_board_info *board_data = pdata->board_data;
  508. int cnt = 0;
  509. /*
  510. * get_context_loss_count returns negative on error. We'll ignore the
  511. * error and store the error to ctx_loss_cnt, which will cause
  512. * dss_need_ctx_restore() call to return true.
  513. */
  514. if (board_data->get_context_loss_count)
  515. cnt = board_data->get_context_loss_count(dev);
  516. WARN_ON(cnt < 0);
  517. dss.ctx_loss_cnt = cnt;
  518. DSSDBG("initial ctx_loss_cnt %u\n", cnt);
  519. }
  520. static bool dss_need_ctx_restore(void)
  521. {
  522. struct device *dev = &dss.pdev->dev;
  523. struct omap_display_platform_data *pdata = dev->platform_data;
  524. struct omap_dss_board_info *board_data = pdata->board_data;
  525. int cnt;
  526. /*
  527. * If get_context_loss_count is not available, assume that we need
  528. * context restore always.
  529. */
  530. if (!board_data->get_context_loss_count)
  531. return true;
  532. cnt = board_data->get_context_loss_count(dev);
  533. if (cnt < 0) {
  534. dev_err(dev, "getting context loss count failed, will force "
  535. "context restore\n");
  536. dss.ctx_loss_cnt = cnt;
  537. return true;
  538. }
  539. if (cnt == dss.ctx_loss_cnt)
  540. return false;
  541. DSSDBG("ctx_loss_cnt %d -> %d\n", dss.ctx_loss_cnt, cnt);
  542. dss.ctx_loss_cnt = cnt;
  543. return true;
  544. }
  545. static int dss_get_clocks(void)
  546. {
  547. struct clk *clk;
  548. int r;
  549. clk = clk_get(&dss.pdev->dev, "fck");
  550. if (IS_ERR(clk)) {
  551. DSSERR("can't get clock fck\n");
  552. r = PTR_ERR(clk);
  553. goto err;
  554. }
  555. dss.dss_clk = clk;
  556. if (cpu_is_omap34xx()) {
  557. clk = clk_get(NULL, "dpll4_m4_ck");
  558. if (IS_ERR(clk)) {
  559. DSSERR("Failed to get dpll4_m4_ck\n");
  560. r = PTR_ERR(clk);
  561. goto err;
  562. }
  563. } else if (cpu_is_omap44xx()) {
  564. clk = clk_get(NULL, "dpll_per_m5x2_ck");
  565. if (IS_ERR(clk)) {
  566. DSSERR("Failed to get dpll_per_m5x2_ck\n");
  567. r = PTR_ERR(clk);
  568. goto err;
  569. }
  570. } else { /* omap24xx */
  571. clk = NULL;
  572. }
  573. dss.dpll4_m4_ck = clk;
  574. return 0;
  575. err:
  576. if (dss.dss_clk)
  577. clk_put(dss.dss_clk);
  578. if (dss.dpll4_m4_ck)
  579. clk_put(dss.dpll4_m4_ck);
  580. return r;
  581. }
  582. static void dss_put_clocks(void)
  583. {
  584. if (dss.dpll4_m4_ck)
  585. clk_put(dss.dpll4_m4_ck);
  586. clk_put(dss.dss_clk);
  587. }
  588. int dss_runtime_get(void)
  589. {
  590. int r;
  591. DSSDBG("dss_runtime_get\n");
  592. r = pm_runtime_get_sync(&dss.pdev->dev);
  593. WARN_ON(r < 0);
  594. return r < 0 ? r : 0;
  595. }
  596. void dss_runtime_put(void)
  597. {
  598. int r;
  599. DSSDBG("dss_runtime_put\n");
  600. r = pm_runtime_put(&dss.pdev->dev);
  601. WARN_ON(r < 0);
  602. }
  603. /* DEBUGFS */
  604. #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
  605. void dss_debug_dump_clocks(struct seq_file *s)
  606. {
  607. dss_dump_clocks(s);
  608. dispc_dump_clocks(s);
  609. #ifdef CONFIG_OMAP2_DSS_DSI
  610. dsi_dump_clocks(s);
  611. #endif
  612. }
  613. #endif
  614. /* DSS HW IP initialisation */
  615. static int omap_dsshw_probe(struct platform_device *pdev)
  616. {
  617. struct resource *dss_mem;
  618. u32 rev;
  619. int r;
  620. dss.pdev = pdev;
  621. dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
  622. if (!dss_mem) {
  623. DSSERR("can't get IORESOURCE_MEM DSS\n");
  624. r = -EINVAL;
  625. goto err_ioremap;
  626. }
  627. dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
  628. if (!dss.base) {
  629. DSSERR("can't ioremap DSS\n");
  630. r = -ENOMEM;
  631. goto err_ioremap;
  632. }
  633. r = dss_get_clocks();
  634. if (r)
  635. goto err_clocks;
  636. dss_init_ctx_loss_count();
  637. pm_runtime_enable(&pdev->dev);
  638. r = dss_runtime_get();
  639. if (r)
  640. goto err_runtime_get;
  641. /* Select DPLL */
  642. REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
  643. #ifdef CONFIG_OMAP2_DSS_VENC
  644. REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
  645. REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
  646. REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
  647. #endif
  648. dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
  649. dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
  650. dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
  651. dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
  652. dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
  653. r = dpi_init();
  654. if (r) {
  655. DSSERR("Failed to initialize DPI\n");
  656. goto err_dpi;
  657. }
  658. r = sdi_init();
  659. if (r) {
  660. DSSERR("Failed to initialize SDI\n");
  661. goto err_sdi;
  662. }
  663. rev = dss_read_reg(DSS_REVISION);
  664. printk(KERN_INFO "OMAP DSS rev %d.%d\n",
  665. FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
  666. dss_runtime_put();
  667. return 0;
  668. err_sdi:
  669. dpi_exit();
  670. err_dpi:
  671. dss_runtime_put();
  672. err_runtime_get:
  673. pm_runtime_disable(&pdev->dev);
  674. dss_put_clocks();
  675. err_clocks:
  676. iounmap(dss.base);
  677. err_ioremap:
  678. return r;
  679. }
  680. static int omap_dsshw_remove(struct platform_device *pdev)
  681. {
  682. dpi_exit();
  683. sdi_exit();
  684. iounmap(dss.base);
  685. pm_runtime_disable(&pdev->dev);
  686. dss_put_clocks();
  687. return 0;
  688. }
  689. static int dss_runtime_suspend(struct device *dev)
  690. {
  691. dss_save_context();
  692. clk_disable(dss.dss_clk);
  693. return 0;
  694. }
  695. static int dss_runtime_resume(struct device *dev)
  696. {
  697. clk_enable(dss.dss_clk);
  698. if (dss_need_ctx_restore())
  699. dss_restore_context();
  700. return 0;
  701. }
  702. static const struct dev_pm_ops dss_pm_ops = {
  703. .runtime_suspend = dss_runtime_suspend,
  704. .runtime_resume = dss_runtime_resume,
  705. };
  706. static struct platform_driver omap_dsshw_driver = {
  707. .probe = omap_dsshw_probe,
  708. .remove = omap_dsshw_remove,
  709. .driver = {
  710. .name = "omapdss_dss",
  711. .owner = THIS_MODULE,
  712. .pm = &dss_pm_ops,
  713. },
  714. };
  715. int dss_init_platform_driver(void)
  716. {
  717. return platform_driver_register(&omap_dsshw_driver);
  718. }
  719. void dss_uninit_platform_driver(void)
  720. {
  721. return platform_driver_unregister(&omap_dsshw_driver);
  722. }