Logo Search packages:      
Sourcecode: linux-fsl-imx51 version File versions  Download package

ipu_sdc.c

Go to the documentation of this file.
/*
 * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
 */

/*
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

/*!
 * @file ipu_sdc.c
 *
 * @brief IPU SDC submodule API functions
 *
 * @ingroup IPU
 */
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/ipu.h>
#include "ipu_prv.h"
#include "ipu_regs.h"
#include "ipu_param_mem.h"

static uint32_t g_h_start_width;
static uint32_t g_v_start_width;

static const uint32_t di_mappings[] = {
      0x1600AAAA, 0x00E05555, 0x00070000, 3,    /* RGB888 */
      0x0005000F, 0x000B000F, 0x0011000F, 1,    /* RGB666 */
      0x0011000F, 0x000B000F, 0x0005000F, 1,    /* BGR666 */
      0x0004003F, 0x000A000F, 0x000F003F, 1     /* RGB565 */
};

/*!
 * This function is called to initialize a synchronous LCD panel.
 *
 * @param       panel           The type of panel.
 *
 * @param       pixel_clk       Desired pixel clock frequency in Hz.
 *
 * @param       pixel_fmt       Input parameter for pixel format of buffer. Pixel
 *                              format is a FOURCC ASCII code.
 *
 * @param       width           The width of panel in pixels.
 *
 * @param       height          The height of panel in pixels.
 *
 * @param       hStartWidth     The number of pixel clocks between the HSYNC
 *                              signal pulse and the start of valid data.
 *
 * @param       hSyncWidth      The width of the HSYNC signal in units of pixel
 *                              clocks.
 *
 * @param       hEndWidth       The number of pixel clocks between the end of
 *                              valid data and the HSYNC signal for next line.
 *
 * @param       vStartWidth     The number of lines between the VSYNC
 *                              signal pulse and the start of valid data.
 *
 * @param       vSyncWidth      The width of the VSYNC signal in units of lines
 *
 * @param       vEndWidth       The number of lines between the end of valid
 *                              data and the VSYNC signal for next frame.
 *
 * @param       sig             Bitfield of signal polarities for LCD interface.
 *
 * @return      This function returns 0 on success or negative error code on
 *              fail.
 */
00076 int32_t ipu_sdc_init_panel(ipu_panel_t panel,
                     uint32_t pixel_clk,
                     uint16_t width, uint16_t height,
                     uint32_t pixel_fmt,
                     uint16_t h_start_width, uint16_t h_sync_width,
                     uint16_t h_end_width, uint16_t v_start_width,
                     uint16_t v_sync_width, uint16_t v_end_width,
                     ipu_di_signal_cfg_t sig)
{
      unsigned long lock_flags;
      uint32_t reg;
      uint32_t old_conf;
      uint32_t div;

      dev_dbg(g_ipu_dev, "panel size = %d x %d\n", width, height);

      if ((v_sync_width == 0) || (h_sync_width == 0))
            return EINVAL;

      /* Init panel size and blanking periods */
      reg =
          ((uint32_t) (h_sync_width - 1) << 26) |
          ((uint32_t) (width + h_sync_width + h_start_width + h_end_width - 1)
           << 16);
      __raw_writel(reg, SDC_HOR_CONF);

      reg = ((uint32_t) (v_sync_width - 1) << 26) | SDC_V_SYNC_WIDTH_L |
          ((uint32_t)
           (height + v_sync_width + v_start_width + v_end_width - 1) << 16);
      __raw_writel(reg, SDC_VER_CONF);

      g_h_start_width = h_start_width + h_sync_width;
      g_v_start_width = v_start_width + v_sync_width;

      switch (panel) {
      case IPU_PANEL_SHARP_TFT:
            __raw_writel(0x00FD0102L, SDC_SHARP_CONF_1);
            __raw_writel(0x00F500F4L, SDC_SHARP_CONF_2);
            __raw_writel(SDC_COM_SHARP | SDC_COM_TFT_COLOR, SDC_COM_CONF);
            break;
      case IPU_PANEL_TFT:
            __raw_writel(SDC_COM_TFT_COLOR, SDC_COM_CONF);
            break;
      default:
            return EINVAL;
      }

      spin_lock_irqsave(&ipu_lock, lock_flags);

      /* Init clocking */

      /* Calculate divider */
      /* fractional part is 4 bits so simply multiple by 2^4 to get fractional part */
      dev_dbg(g_ipu_dev, "pixel clk = %d\n", pixel_clk);
      div = (clk_get_rate(g_ipu_clk) * 16) / pixel_clk;
      if (div < 0x40) { /* Divider less than 4 */
            dev_dbg(g_ipu_dev,
                  "InitPanel() - Pixel clock divider less than 1\n");
            div = 0x40;
      }
      /* DISP3_IF_CLK_DOWN_WR is half the divider value and 2 less fraction bits */
      /* Subtract 1 extra from DISP3_IF_CLK_DOWN_WR based on timing debug     */
      /* DISP3_IF_CLK_UP_WR is 0 */
      __raw_writel((((div / 8) - 1) << 22) | div, DI_DISP3_TIME_CONF);

      /* DI settings */
      old_conf = __raw_readl(DI_DISP_IF_CONF) & 0x78FFFFFF;
      old_conf |= sig.datamask_en << DI_D3_DATAMSK_SHIFT |
          sig.clksel_en << DI_D3_CLK_SEL_SHIFT |
          sig.clkidle_en << DI_D3_CLK_IDLE_SHIFT;
      __raw_writel(old_conf, DI_DISP_IF_CONF);

      old_conf = __raw_readl(DI_DISP_SIG_POL) & 0xE0FFFFFF;
      old_conf |= sig.data_pol << DI_D3_DATA_POL_SHIFT |
          sig.clk_pol << DI_D3_CLK_POL_SHIFT |
          sig.enable_pol << DI_D3_DRDY_SHARP_POL_SHIFT |
          sig.Hsync_pol << DI_D3_HSYNC_POL_SHIFT |
          sig.Vsync_pol << DI_D3_VSYNC_POL_SHIFT;
      __raw_writel(old_conf, DI_DISP_SIG_POL);

      switch (pixel_fmt) {
      case IPU_PIX_FMT_RGB24:
            __raw_writel(di_mappings[0], DI_DISP3_B0_MAP);
            __raw_writel(di_mappings[1], DI_DISP3_B1_MAP);
            __raw_writel(di_mappings[2], DI_DISP3_B2_MAP);
            __raw_writel(__raw_readl(DI_DISP_ACC_CC) |
                       ((di_mappings[3] - 1) << 12), DI_DISP_ACC_CC);
            break;
      case IPU_PIX_FMT_RGB666:
            __raw_writel(di_mappings[4], DI_DISP3_B0_MAP);
            __raw_writel(di_mappings[5], DI_DISP3_B1_MAP);
            __raw_writel(di_mappings[6], DI_DISP3_B2_MAP);
            __raw_writel(__raw_readl(DI_DISP_ACC_CC) |
                       ((di_mappings[7] - 1) << 12), DI_DISP_ACC_CC);
            break;
      case IPU_PIX_FMT_BGR666:
            __raw_writel(di_mappings[8], DI_DISP3_B0_MAP);
            __raw_writel(di_mappings[9], DI_DISP3_B1_MAP);
            __raw_writel(di_mappings[10], DI_DISP3_B2_MAP);
            __raw_writel(__raw_readl(DI_DISP_ACC_CC) |
                       ((di_mappings[11] - 1) << 12), DI_DISP_ACC_CC);
            break;
      default:
            __raw_writel(di_mappings[12], DI_DISP3_B0_MAP);
            __raw_writel(di_mappings[13], DI_DISP3_B1_MAP);
            __raw_writel(di_mappings[14], DI_DISP3_B2_MAP);
            __raw_writel(__raw_readl(DI_DISP_ACC_CC) |
                       ((di_mappings[15] - 1) << 12), DI_DISP_ACC_CC);
            break;
      }

      spin_unlock_irqrestore(&ipu_lock, lock_flags);

      dev_dbg(g_ipu_dev, "DI_DISP_IF_CONF = 0x%08X\n",
            __raw_readl(DI_DISP_IF_CONF));
      dev_dbg(g_ipu_dev, "DI_DISP_SIG_POL = 0x%08X\n",
            __raw_readl(DI_DISP_SIG_POL));
      dev_dbg(g_ipu_dev, "DI_DISP3_TIME_CONF = 0x%08X\n",
            __raw_readl(DI_DISP3_TIME_CONF));

      return 0;
}

/*!
 * This function sets the foreground and background plane global alpha blending
 * modes.
 *
 * @param       enable          Boolean to enable or disable global alpha
 *                              blending. If disabled, per pixel blending is used.
 *
 * @param       alpha           Global alpha value.
 *
 * @return      This function returns 0 on success or negative error code on fail
 */
00210 int32_t ipu_sdc_set_global_alpha(bool enable, uint8_t alpha)
{
      uint32_t reg;
      unsigned long lock_flags;

      spin_lock_irqsave(&ipu_lock, lock_flags);

      if (enable) {
            reg = __raw_readl(SDC_GW_CTRL) & 0x00FFFFFFL;
            __raw_writel(reg | ((uint32_t) alpha << 24), SDC_GW_CTRL);

            reg = __raw_readl(SDC_COM_CONF);
            __raw_writel(reg | SDC_COM_GLB_A, SDC_COM_CONF);
      } else {
            reg = __raw_readl(SDC_COM_CONF);
            __raw_writel(reg & ~SDC_COM_GLB_A, SDC_COM_CONF);
      }

      spin_unlock_irqrestore(&ipu_lock, lock_flags);

      return 0;
}

/*!
 * This function sets the transparent color key for SDC graphic plane.
 *
 * @param       channel         Input parameter for the logical channel ID.
 *
 * @param       enable          Boolean to enable or disable color key
 *
 * @param       colorKey        24-bit RGB color to use as transparent color key.
 *
 * @return      This function returns 0 on success or negative error code on fail
 */
00244 int32_t ipu_sdc_set_color_key(ipu_channel_t channel, bool enable,
                        uint32_t color_key)
{
      uint32_t reg, sdc_conf;
      unsigned long lock_flags;

      spin_lock_irqsave(&ipu_lock, lock_flags);

      sdc_conf = __raw_readl(SDC_COM_CONF);
      if (channel == MEM_SDC_BG) {
            sdc_conf &= ~SDC_COM_GWSEL;
      } else {
            sdc_conf |= SDC_COM_GWSEL;
      }

      if (enable) {
            reg = __raw_readl(SDC_GW_CTRL) & 0xFF000000L;
            __raw_writel(reg | (color_key & 0x00FFFFFFL), SDC_GW_CTRL);

            sdc_conf |= SDC_COM_KEY_COLOR_G;
      } else {
            sdc_conf &= ~SDC_COM_KEY_COLOR_G;
      }
      __raw_writel(sdc_conf, SDC_COM_CONF);

      spin_unlock_irqrestore(&ipu_lock, lock_flags);

      return 0;
}

int32_t ipu_sdc_set_brightness(uint8_t value)
{
      __raw_writel(0x03000000UL | value << 16, SDC_PWM_CTRL);
      return 0;
}

/*!
 * This function sets the window position of the foreground or background plane.
 * modes.
 *
 * @param       channel         Input parameter for the logical channel ID.
 *
 * @param       x_pos           The X coordinate position to place window at.
 *                              The position is relative to the top left corner.
 *
 * @param       y_pos           The Y coordinate position to place window at.
 *                              The position is relative to the top left corner.
 *
 * @return      This function returns 0 on success or negative error code on fail
 */
00294 int32_t ipu_disp_set_window_pos(ipu_channel_t channel, int16_t x_pos,
                         int16_t y_pos)
{
      x_pos += g_h_start_width;
      y_pos += g_v_start_width;

      if (channel == MEM_SDC_BG) {
            __raw_writel((x_pos << 16) | y_pos, SDC_BG_POS);
      } else if (channel == MEM_SDC_FG) {
            __raw_writel((x_pos << 16) | y_pos, SDC_FG_POS);
      } else {
            return EINVAL;
      }
      return 0;
}

void _ipu_sdc_fg_init(ipu_channel_params_t * params)
{
      uint32_t reg;
      (void)params;

      /* Enable FG channel */
      reg = __raw_readl(SDC_COM_CONF);
      __raw_writel(reg | SDC_COM_FG_EN | SDC_COM_BG_EN, SDC_COM_CONF);
}

uint32_t _ipu_sdc_fg_uninit(void)
{
      uint32_t reg;

      /* Disable FG channel */
      reg = __raw_readl(SDC_COM_CONF);
      __raw_writel(reg & ~SDC_COM_FG_EN, SDC_COM_CONF);

      return (reg & SDC_COM_FG_EN);
}

void _ipu_sdc_bg_init(ipu_channel_params_t * params)
{
      uint32_t reg;
      (void)params;

      /* Enable FG channel */
      reg = __raw_readl(SDC_COM_CONF);
      __raw_writel(reg | SDC_COM_BG_EN, SDC_COM_CONF);
}

uint32_t _ipu_sdc_bg_uninit(void)
{
      uint32_t reg;

      /* Disable BG channel */
      reg = __raw_readl(SDC_COM_CONF);
      __raw_writel(reg & ~SDC_COM_BG_EN, SDC_COM_CONF);

      return (reg & SDC_COM_BG_EN);
}

/* Exported symbols for modules. */
EXPORT_SYMBOL(ipu_sdc_init_panel);
EXPORT_SYMBOL(ipu_sdc_set_global_alpha);
EXPORT_SYMBOL(ipu_sdc_set_color_key);
EXPORT_SYMBOL(ipu_sdc_set_brightness);
EXPORT_SYMBOL(ipu_disp_set_window_pos);

Generated by  Doxygen 1.6.0   Back to index