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