Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 1 | /* |
| 2 | * HDMI PLL |
| 3 | * |
Andrew F. Davis | bb5cdf8 | 2017-12-05 14:29:31 -0600 | [diff] [blame] | 4 | * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of the GNU General Public License version 2 as published by |
| 8 | * the Free Software Foundation. |
| 9 | */ |
| 10 | |
Tomi Valkeinen | ac9f242 | 2013-11-14 13:46:32 +0200 | [diff] [blame] | 11 | #define DSS_SUBSYS_NAME "HDMIPLL" |
| 12 | |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 13 | #include <linux/kernel.h> |
| 14 | #include <linux/module.h> |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 15 | #include <linux/err.h> |
| 16 | #include <linux/io.h> |
| 17 | #include <linux/platform_device.h> |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 18 | #include <linux/clk.h> |
Arnd Bergmann | 2d80245 | 2016-05-11 18:01:45 +0200 | [diff] [blame] | 19 | #include <linux/seq_file.h> |
Tomi Valkeinen | 86c9305 | 2016-05-17 17:07:46 +0300 | [diff] [blame] | 20 | #include <linux/pm_runtime.h> |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 21 | |
Peter Ujfalusi | 32043da | 2016-05-27 14:40:49 +0300 | [diff] [blame] | 22 | #include "omapdss.h" |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 23 | #include "dss.h" |
Archit Taneja | ef26958 | 2013-09-12 17:45:57 +0530 | [diff] [blame] | 24 | #include "hdmi.h" |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 25 | |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 26 | void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) |
| 27 | { |
| 28 | #define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ |
| 29 | hdmi_read_reg(pll->base, r)) |
| 30 | |
| 31 | DUMPPLL(PLLCTRL_PLL_CONTROL); |
| 32 | DUMPPLL(PLLCTRL_PLL_STATUS); |
| 33 | DUMPPLL(PLLCTRL_PLL_GO); |
| 34 | DUMPPLL(PLLCTRL_CFG1); |
| 35 | DUMPPLL(PLLCTRL_CFG2); |
| 36 | DUMPPLL(PLLCTRL_CFG3); |
| 37 | DUMPPLL(PLLCTRL_SSC_CFG1); |
| 38 | DUMPPLL(PLLCTRL_SSC_CFG2); |
| 39 | DUMPPLL(PLLCTRL_CFG4); |
| 40 | } |
| 41 | |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 42 | static int hdmi_pll_enable(struct dss_pll *dsspll) |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 43 | { |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 44 | struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll); |
Tomi Valkeinen | 03aafa2 | 2014-10-16 15:31:38 +0300 | [diff] [blame] | 45 | struct hdmi_wp_data *wp = pll->wp; |
Tomi Valkeinen | f7dd8f5 | 2016-05-17 17:00:52 +0300 | [diff] [blame] | 46 | int r; |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 47 | |
Tomi Valkeinen | 86c9305 | 2016-05-17 17:07:46 +0300 | [diff] [blame] | 48 | r = pm_runtime_get_sync(&pll->pdev->dev); |
| 49 | WARN_ON(r < 0); |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 50 | |
Laurent Pinchart | 2726099 | 2018-02-13 14:00:22 +0200 | [diff] [blame] | 51 | dss_ctrl_pll_enable(dsspll, true); |
Tomi Valkeinen | adb5ff8 | 2014-12-31 11:26:18 +0200 | [diff] [blame] | 52 | |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 53 | r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); |
| 54 | if (r) |
| 55 | return r; |
| 56 | |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 57 | return 0; |
| 58 | } |
| 59 | |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 60 | static void hdmi_pll_disable(struct dss_pll *dsspll) |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 61 | { |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 62 | struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll); |
Tomi Valkeinen | 03aafa2 | 2014-10-16 15:31:38 +0300 | [diff] [blame] | 63 | struct hdmi_wp_data *wp = pll->wp; |
Tomi Valkeinen | 86c9305 | 2016-05-17 17:07:46 +0300 | [diff] [blame] | 64 | int r; |
Tomi Valkeinen | 03aafa2 | 2014-10-16 15:31:38 +0300 | [diff] [blame] | 65 | |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 66 | hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); |
Tomi Valkeinen | adb5ff8 | 2014-12-31 11:26:18 +0200 | [diff] [blame] | 67 | |
Laurent Pinchart | 2726099 | 2018-02-13 14:00:22 +0200 | [diff] [blame] | 68 | dss_ctrl_pll_enable(dsspll, false); |
Tomi Valkeinen | 86c9305 | 2016-05-17 17:07:46 +0300 | [diff] [blame] | 69 | |
| 70 | r = pm_runtime_put_sync(&pll->pdev->dev); |
| 71 | WARN_ON(r < 0 && r != -ENOSYS); |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 72 | } |
| 73 | |
Laurent Pinchart | 1fdf904 | 2017-08-11 16:49:02 +0300 | [diff] [blame] | 74 | static const struct dss_pll_ops hdmi_pll_ops = { |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 75 | .enable = hdmi_pll_enable, |
| 76 | .disable = hdmi_pll_disable, |
| 77 | .set_config = dss_pll_write_config_type_b, |
Archit Taneja | 2d64b1b | 2013-09-23 15:12:34 +0530 | [diff] [blame] | 78 | }; |
| 79 | |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 80 | static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = { |
Tomi Valkeinen | 06ede3d | 2016-05-18 10:48:44 +0300 | [diff] [blame] | 81 | .type = DSS_PLL_TYPE_B, |
| 82 | |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 83 | .n_max = 255, |
| 84 | .m_min = 20, |
| 85 | .m_max = 4095, |
| 86 | .mX_max = 127, |
| 87 | .fint_min = 500000, |
| 88 | .fint_max = 2500000, |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 89 | |
| 90 | .clkdco_min = 500000000, |
| 91 | .clkdco_low = 1000000000, |
| 92 | .clkdco_max = 2000000000, |
| 93 | |
| 94 | .n_msb = 8, |
| 95 | .n_lsb = 1, |
| 96 | .m_msb = 20, |
| 97 | .m_lsb = 9, |
| 98 | |
| 99 | .mX_msb[0] = 24, |
| 100 | .mX_lsb[0] = 18, |
| 101 | |
| 102 | .has_selfreqdco = true, |
Archit Taneja | 2d64b1b | 2013-09-23 15:12:34 +0530 | [diff] [blame] | 103 | }; |
| 104 | |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 105 | static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = { |
Tomi Valkeinen | 06ede3d | 2016-05-18 10:48:44 +0300 | [diff] [blame] | 106 | .type = DSS_PLL_TYPE_B, |
| 107 | |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 108 | .n_max = 255, |
| 109 | .m_min = 20, |
| 110 | .m_max = 2045, |
| 111 | .mX_max = 127, |
| 112 | .fint_min = 620000, |
| 113 | .fint_max = 2500000, |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 114 | |
| 115 | .clkdco_min = 750000000, |
| 116 | .clkdco_low = 1500000000, |
| 117 | .clkdco_max = 2500000000UL, |
| 118 | |
| 119 | .n_msb = 8, |
| 120 | .n_lsb = 1, |
| 121 | .m_msb = 20, |
| 122 | .m_lsb = 9, |
| 123 | |
| 124 | .mX_msb[0] = 24, |
| 125 | .mX_lsb[0] = 18, |
| 126 | |
| 127 | .has_selfreqdco = true, |
| 128 | .has_refsel = true, |
| 129 | }; |
| 130 | |
Laurent Pinchart | 7b29525 | 2018-02-13 14:00:21 +0200 | [diff] [blame] | 131 | static int hdmi_init_pll_data(struct dss_device *dss, |
| 132 | struct platform_device *pdev, |
Laurent Pinchart | 1fdf904 | 2017-08-11 16:49:02 +0300 | [diff] [blame] | 133 | struct hdmi_pll_data *hpll) |
Archit Taneja | 2d64b1b | 2013-09-23 15:12:34 +0530 | [diff] [blame] | 134 | { |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 135 | struct dss_pll *pll = &hpll->pll; |
| 136 | struct clk *clk; |
| 137 | int r; |
Archit Taneja | 2d64b1b | 2013-09-23 15:12:34 +0530 | [diff] [blame] | 138 | |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 139 | clk = devm_clk_get(&pdev->dev, "sys_clk"); |
| 140 | if (IS_ERR(clk)) { |
| 141 | DSSERR("can't get sys_clk\n"); |
| 142 | return PTR_ERR(clk); |
Archit Taneja | 2d64b1b | 2013-09-23 15:12:34 +0530 | [diff] [blame] | 143 | } |
| 144 | |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 145 | pll->name = "hdmi"; |
Tomi Valkeinen | 64e22ff | 2015-01-02 10:05:33 +0200 | [diff] [blame] | 146 | pll->id = DSS_PLL_HDMI; |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 147 | pll->base = hpll->base; |
| 148 | pll->clkin = clk; |
| 149 | |
Laurent Pinchart | ba63b63 | 2017-08-11 16:49:05 +0300 | [diff] [blame] | 150 | if (hpll->wp->version == 4) |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 151 | pll->hw = &dss_omap4_hdmi_pll_hw; |
Laurent Pinchart | ba63b63 | 2017-08-11 16:49:05 +0300 | [diff] [blame] | 152 | else |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 153 | pll->hw = &dss_omap5_hdmi_pll_hw; |
Archit Taneja | 2d64b1b | 2013-09-23 15:12:34 +0530 | [diff] [blame] | 154 | |
Laurent Pinchart | 1fdf904 | 2017-08-11 16:49:02 +0300 | [diff] [blame] | 155 | pll->ops = &hdmi_pll_ops; |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 156 | |
Laurent Pinchart | 798957a | 2018-02-13 14:00:30 +0200 | [diff] [blame] | 157 | r = dss_pll_register(dss, pll); |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 158 | if (r) |
| 159 | return r; |
Archit Taneja | 2d64b1b | 2013-09-23 15:12:34 +0530 | [diff] [blame] | 160 | |
| 161 | return 0; |
| 162 | } |
| 163 | |
Laurent Pinchart | 7b29525 | 2018-02-13 14:00:21 +0200 | [diff] [blame] | 164 | int hdmi_pll_init(struct dss_device *dss, struct platform_device *pdev, |
| 165 | struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 166 | { |
Archit Taneja | 2d64b1b | 2013-09-23 15:12:34 +0530 | [diff] [blame] | 167 | int r; |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 168 | struct resource *res; |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 169 | |
Tomi Valkeinen | 86c9305 | 2016-05-17 17:07:46 +0300 | [diff] [blame] | 170 | pll->pdev = pdev; |
Tomi Valkeinen | 03aafa2 | 2014-10-16 15:31:38 +0300 | [diff] [blame] | 171 | pll->wp = wp; |
| 172 | |
Tomi Valkeinen | 7760150 | 2013-12-17 14:41:14 +0200 | [diff] [blame] | 173 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); |
Tomi Valkeinen | 59b3d38 | 2014-04-28 16:11:01 +0300 | [diff] [blame] | 174 | pll->base = devm_ioremap_resource(&pdev->dev, res); |
Laurent Pinchart | b22622f | 2017-05-07 00:29:09 +0300 | [diff] [blame] | 175 | if (IS_ERR(pll->base)) |
Tomi Valkeinen | 2b22df8 | 2014-05-23 14:50:09 +0300 | [diff] [blame] | 176 | return PTR_ERR(pll->base); |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 177 | |
Laurent Pinchart | 7b29525 | 2018-02-13 14:00:21 +0200 | [diff] [blame] | 178 | r = hdmi_init_pll_data(dss, pdev, pll); |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 179 | if (r) { |
| 180 | DSSERR("failed to init HDMI PLL\n"); |
| 181 | return r; |
| 182 | } |
| 183 | |
Archit Taneja | c1577c1 | 2013-10-08 12:55:26 +0530 | [diff] [blame] | 184 | return 0; |
| 185 | } |
Tomi Valkeinen | c84c3a5 | 2014-10-22 15:02:17 +0300 | [diff] [blame] | 186 | |
| 187 | void hdmi_pll_uninit(struct hdmi_pll_data *hpll) |
| 188 | { |
| 189 | struct dss_pll *pll = &hpll->pll; |
| 190 | |
| 191 | dss_pll_unregister(pll); |
| 192 | } |