0001
0002
0003
0004
0005
0006
0007
0008 #define DSS_SUBSYS_NAME "HDMIWP"
0009
0010 #include <linux/kernel.h>
0011 #include <linux/err.h>
0012 #include <linux/io.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/seq_file.h>
0015
0016 #include <video/omapfb_dss.h>
0017
0018 #include "dss.h"
0019 #include "hdmi.h"
0020
0021 void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s)
0022 {
0023 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, hdmi_read_reg(wp->base, r))
0024
0025 DUMPREG(HDMI_WP_REVISION);
0026 DUMPREG(HDMI_WP_SYSCONFIG);
0027 DUMPREG(HDMI_WP_IRQSTATUS_RAW);
0028 DUMPREG(HDMI_WP_IRQSTATUS);
0029 DUMPREG(HDMI_WP_IRQENABLE_SET);
0030 DUMPREG(HDMI_WP_IRQENABLE_CLR);
0031 DUMPREG(HDMI_WP_IRQWAKEEN);
0032 DUMPREG(HDMI_WP_PWR_CTRL);
0033 DUMPREG(HDMI_WP_DEBOUNCE);
0034 DUMPREG(HDMI_WP_VIDEO_CFG);
0035 DUMPREG(HDMI_WP_VIDEO_SIZE);
0036 DUMPREG(HDMI_WP_VIDEO_TIMING_H);
0037 DUMPREG(HDMI_WP_VIDEO_TIMING_V);
0038 DUMPREG(HDMI_WP_CLK);
0039 DUMPREG(HDMI_WP_AUDIO_CFG);
0040 DUMPREG(HDMI_WP_AUDIO_CFG2);
0041 DUMPREG(HDMI_WP_AUDIO_CTRL);
0042 DUMPREG(HDMI_WP_AUDIO_DATA);
0043 }
0044
0045 u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp)
0046 {
0047 return hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
0048 }
0049
0050 void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)
0051 {
0052 hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);
0053
0054 hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
0055 }
0056
0057 void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)
0058 {
0059 hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);
0060 }
0061
0062 void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)
0063 {
0064 hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);
0065 }
0066
0067
0068 int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val)
0069 {
0070
0071 if (REG_GET(wp->base, HDMI_WP_PWR_CTRL, 5, 4) == val)
0072 return 0;
0073
0074
0075 REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 7, 6);
0076
0077
0078 if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 5, 4, val)
0079 != val) {
0080 DSSERR("Failed to set PHY power mode to %d\n", val);
0081 return -ETIMEDOUT;
0082 }
0083
0084 return 0;
0085 }
0086
0087
0088 int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val)
0089 {
0090
0091 REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 3, 2);
0092
0093
0094 if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 1, 0, val)
0095 != val) {
0096 DSSERR("Failed to set PLL_PWR_STATUS\n");
0097 return -ETIMEDOUT;
0098 }
0099
0100 return 0;
0101 }
0102
0103 int hdmi_wp_video_start(struct hdmi_wp_data *wp)
0104 {
0105 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, true, 31, 31);
0106
0107 return 0;
0108 }
0109
0110 void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
0111 {
0112 int i;
0113
0114 hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_FRAME_DONE);
0115
0116 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);
0117
0118 for (i = 0; i < 50; ++i) {
0119 u32 v;
0120
0121 msleep(20);
0122
0123 v = hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS_RAW);
0124 if (v & HDMI_IRQ_VIDEO_FRAME_DONE)
0125 return;
0126 }
0127
0128 DSSERR("no HDMI FRAMEDONE when disabling output\n");
0129 }
0130
0131 void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
0132 struct hdmi_video_format *video_fmt)
0133 {
0134 u32 l = 0;
0135
0136 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,
0137 10, 8);
0138
0139 l |= FLD_VAL(video_fmt->y_res, 31, 16);
0140 l |= FLD_VAL(video_fmt->x_res, 15, 0);
0141 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);
0142 }
0143
0144 void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
0145 struct omap_video_timings *timings)
0146 {
0147 u32 r;
0148 bool vsync_pol, hsync_pol;
0149 DSSDBG("Enter hdmi_wp_video_config_interface\n");
0150
0151 vsync_pol = timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
0152 hsync_pol = timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
0153
0154 r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
0155 r = FLD_MOD(r, vsync_pol, 7, 7);
0156 r = FLD_MOD(r, hsync_pol, 6, 6);
0157 r = FLD_MOD(r, timings->interlace, 3, 3);
0158 r = FLD_MOD(r, 1, 1, 0);
0159 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
0160 }
0161
0162 void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
0163 struct omap_video_timings *timings)
0164 {
0165 u32 timing_h = 0;
0166 u32 timing_v = 0;
0167
0168 DSSDBG("Enter hdmi_wp_video_config_timing\n");
0169
0170 timing_h |= FLD_VAL(timings->hbp, 31, 20);
0171 timing_h |= FLD_VAL(timings->hfp, 19, 8);
0172 timing_h |= FLD_VAL(timings->hsw, 7, 0);
0173 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);
0174
0175 timing_v |= FLD_VAL(timings->vbp, 31, 20);
0176 timing_v |= FLD_VAL(timings->vfp, 19, 8);
0177 timing_v |= FLD_VAL(timings->vsw, 7, 0);
0178 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);
0179 }
0180
0181 void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
0182 struct omap_video_timings *timings, struct hdmi_config *param)
0183 {
0184 DSSDBG("Enter hdmi_wp_video_init_format\n");
0185
0186 video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
0187 video_fmt->y_res = param->timings.y_res;
0188 video_fmt->x_res = param->timings.x_res;
0189 if (param->timings.interlace)
0190 video_fmt->y_res /= 2;
0191
0192 timings->hbp = param->timings.hbp;
0193 timings->hfp = param->timings.hfp;
0194 timings->hsw = param->timings.hsw;
0195 timings->vbp = param->timings.vbp;
0196 timings->vfp = param->timings.vfp;
0197 timings->vsw = param->timings.vsw;
0198 timings->vsync_level = param->timings.vsync_level;
0199 timings->hsync_level = param->timings.hsync_level;
0200 timings->interlace = param->timings.interlace;
0201 }
0202
0203 void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
0204 struct hdmi_audio_format *aud_fmt)
0205 {
0206 u32 r;
0207
0208 DSSDBG("Enter hdmi_wp_audio_config_format\n");
0209
0210 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
0211 if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
0212 omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||
0213 omapdss_get_version() == OMAPDSS_VER_OMAP4) {
0214 r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
0215 r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
0216 }
0217 r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
0218 r = FLD_MOD(r, aud_fmt->type, 4, 4);
0219 r = FLD_MOD(r, aud_fmt->justification, 3, 3);
0220 r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
0221 r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
0222 r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
0223 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);
0224 }
0225
0226 void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
0227 struct hdmi_audio_dma *aud_dma)
0228 {
0229 u32 r;
0230
0231 DSSDBG("Enter hdmi_wp_audio_config_dma\n");
0232
0233 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);
0234 r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
0235 r = FLD_MOD(r, aud_dma->block_size, 7, 0);
0236 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);
0237
0238 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);
0239 r = FLD_MOD(r, aud_dma->mode, 9, 9);
0240 r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
0241 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);
0242 }
0243
0244 int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable)
0245 {
0246 REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 31, 31);
0247
0248 return 0;
0249 }
0250
0251 int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
0252 {
0253 REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 30, 30);
0254
0255 return 0;
0256 }
0257
0258 int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
0259 {
0260 struct resource *res;
0261
0262 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp");
0263 if (!res) {
0264 DSSERR("can't get WP mem resource\n");
0265 return -EINVAL;
0266 }
0267 wp->phys_base = res->start;
0268
0269 wp->base = devm_ioremap_resource(&pdev->dev, res);
0270 if (IS_ERR(wp->base)) {
0271 DSSERR("can't ioremap HDMI WP\n");
0272 return PTR_ERR(wp->base);
0273 }
0274
0275 return 0;
0276 }
0277
0278 phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)
0279 {
0280 return wp->phys_base + HDMI_WP_AUDIO_DATA;
0281 }