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