Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / drivers / video / omap2 / dss / hdmi_wp.c
1 /*
2  * HDMI wrapper
3  *
4  * Copyright (C) 2013 Texas Instruments Incorporated
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
11 #include <linux/kernel.h>
12 #include <linux/err.h>
13 #include <linux/io.h>
14 #include <linux/platform_device.h>
15 #include <video/omapdss.h>
16
17 #include "dss.h"
18 #include "hdmi.h"
19
20 void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s)
21 {
22 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, hdmi_read_reg(wp->base, r))
23
24         DUMPREG(HDMI_WP_REVISION);
25         DUMPREG(HDMI_WP_SYSCONFIG);
26         DUMPREG(HDMI_WP_IRQSTATUS_RAW);
27         DUMPREG(HDMI_WP_IRQSTATUS);
28         DUMPREG(HDMI_WP_IRQENABLE_SET);
29         DUMPREG(HDMI_WP_IRQENABLE_CLR);
30         DUMPREG(HDMI_WP_IRQWAKEEN);
31         DUMPREG(HDMI_WP_PWR_CTRL);
32         DUMPREG(HDMI_WP_DEBOUNCE);
33         DUMPREG(HDMI_WP_VIDEO_CFG);
34         DUMPREG(HDMI_WP_VIDEO_SIZE);
35         DUMPREG(HDMI_WP_VIDEO_TIMING_H);
36         DUMPREG(HDMI_WP_VIDEO_TIMING_V);
37         DUMPREG(HDMI_WP_WP_CLK);
38         DUMPREG(HDMI_WP_AUDIO_CFG);
39         DUMPREG(HDMI_WP_AUDIO_CFG2);
40         DUMPREG(HDMI_WP_AUDIO_CTRL);
41         DUMPREG(HDMI_WP_AUDIO_DATA);
42 }
43
44 u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp)
45 {
46         return hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
47 }
48
49 void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)
50 {
51         hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);
52         /* flush posted write */
53         hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
54 }
55
56 void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)
57 {
58         hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);
59 }
60
61 void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)
62 {
63         hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);
64 }
65
66 /* PHY_PWR_CMD */
67 int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val)
68 {
69         /* Return if already the state */
70         if (REG_GET(wp->base, HDMI_WP_PWR_CTRL, 5, 4) == val)
71                 return 0;
72
73         /* Command for power control of HDMI PHY */
74         REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 7, 6);
75
76         /* Status of the power control of HDMI PHY */
77         if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 5, 4, val)
78                         != val) {
79                 pr_err("Failed to set PHY power mode to %d\n", val);
80                 return -ETIMEDOUT;
81         }
82
83         return 0;
84 }
85
86 /* PLL_PWR_CMD */
87 int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val)
88 {
89         /* Command for power control of HDMI PLL */
90         REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 3, 2);
91
92         /* wait till PHY_PWR_STATUS is set */
93         if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 1, 0, val)
94                         != val) {
95                 pr_err("Failed to set PLL_PWR_STATUS\n");
96                 return -ETIMEDOUT;
97         }
98
99         return 0;
100 }
101
102 int hdmi_wp_video_start(struct hdmi_wp_data *wp)
103 {
104         REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, true, 31, 31);
105
106         return 0;
107 }
108
109 void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
110 {
111         REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);
112 }
113
114 void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
115                 struct hdmi_video_format *video_fmt)
116 {
117         u32 l = 0;
118
119         REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,
120                 10, 8);
121
122         l |= FLD_VAL(video_fmt->y_res, 31, 16);
123         l |= FLD_VAL(video_fmt->x_res, 15, 0);
124         hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);
125 }
126
127 void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
128                 struct omap_video_timings *timings)
129 {
130         u32 r;
131         bool vsync_pol, hsync_pol;
132         pr_debug("Enter hdmi_wp_video_config_interface\n");
133
134         vsync_pol = timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
135         hsync_pol = timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
136
137         r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
138         r = FLD_MOD(r, vsync_pol, 7, 7);
139         r = FLD_MOD(r, hsync_pol, 6, 6);
140         r = FLD_MOD(r, timings->interlace, 3, 3);
141         r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
142         hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
143 }
144
145 void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
146                 struct omap_video_timings *timings)
147 {
148         u32 timing_h = 0;
149         u32 timing_v = 0;
150
151         pr_debug("Enter hdmi_wp_video_config_timing\n");
152
153         timing_h |= FLD_VAL(timings->hbp, 31, 20);
154         timing_h |= FLD_VAL(timings->hfp, 19, 8);
155         timing_h |= FLD_VAL(timings->hsw, 7, 0);
156         hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);
157
158         timing_v |= FLD_VAL(timings->vbp, 31, 20);
159         timing_v |= FLD_VAL(timings->vfp, 19, 8);
160         timing_v |= FLD_VAL(timings->vsw, 7, 0);
161         hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);
162 }
163
164 void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
165                 struct omap_video_timings *timings, struct hdmi_config *param)
166 {
167         pr_debug("Enter hdmi_wp_video_init_format\n");
168
169         video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
170         video_fmt->y_res = param->timings.y_res;
171         video_fmt->x_res = param->timings.x_res;
172
173         timings->hbp = param->timings.hbp;
174         timings->hfp = param->timings.hfp;
175         timings->hsw = param->timings.hsw;
176         timings->vbp = param->timings.vbp;
177         timings->vfp = param->timings.vfp;
178         timings->vsw = param->timings.vsw;
179         timings->vsync_level = param->timings.vsync_level;
180         timings->hsync_level = param->timings.hsync_level;
181         timings->interlace = param->timings.interlace;
182 }
183
184 #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
185 void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
186                 struct hdmi_audio_format *aud_fmt)
187 {
188         u32 r;
189
190         DSSDBG("Enter hdmi_wp_audio_config_format\n");
191
192         r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
193         r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
194         r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
195         r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
196         r = FLD_MOD(r, aud_fmt->type, 4, 4);
197         r = FLD_MOD(r, aud_fmt->justification, 3, 3);
198         r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
199         r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
200         r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
201         hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);
202 }
203
204 void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
205                 struct hdmi_audio_dma *aud_dma)
206 {
207         u32 r;
208
209         DSSDBG("Enter hdmi_wp_audio_config_dma\n");
210
211         r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);
212         r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
213         r = FLD_MOD(r, aud_dma->block_size, 7, 0);
214         hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);
215
216         r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);
217         r = FLD_MOD(r, aud_dma->mode, 9, 9);
218         r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
219         hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);
220 }
221
222 int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable)
223 {
224         REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 31, 31);
225
226         return 0;
227 }
228
229 int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
230 {
231         REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 30, 30);
232
233         return 0;
234 }
235 #endif
236
237 #define WP_SIZE 0x200
238
239 int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
240 {
241         struct resource *res;
242         struct resource temp_res;
243
244         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi_wp");
245         if (!res) {
246                 DSSDBG("can't get WP mem resource by name\n");
247                 /*
248                  * if hwmod/DT doesn't have the memory resource information
249                  * split into HDMI sub blocks by name, we try again by getting
250                  * the platform's first resource. this code will be removed when
251                  * the driver can get the mem resources by name
252                  */
253                 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
254                 if (!res) {
255                         DSSERR("can't get WP mem resource\n");
256                         return -EINVAL;
257                 }
258
259                 temp_res.start = res->start;
260                 temp_res.end = temp_res.start + WP_SIZE - 1;
261                 res = &temp_res;
262         }
263
264         wp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
265         if (!wp->base) {
266                 DSSERR("can't ioremap HDMI WP\n");
267                 return -ENOMEM;
268         }
269
270         return 0;
271 }