/*
* OMAP5 HDMI CORE IP driver library
*
* Copyright (C) 2014 Texas Instruments Incorporated
*
* Authors:
* Yong Zhi
* Mythri pk
* Archit Taneja <archit@ti.com>
* Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#include <drm/drm_edid.h>
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
#include <sound/asound.h>
#include <sound/asoundef.h>
#endif
#include "hdmi5_core.h"
/* only 24 bit color depth used for now */
static const struct csc_table csc_table_deepcolor[] = {
/* HDMI_DEEP_COLOR_24BIT */
[0] = { 7036, 0, 0, 32, 0, 7036, 0, 32, 0, 0, 7036, 32, },
/* HDMI_DEEP_COLOR_30BIT */
[1] = { 7015, 0, 0, 128, 0, 7015, 0, 128, 0, 0, 7015, 128, },
/* HDMI_DEEP_COLOR_36BIT */
[2] = { 7010, 0, 0, 512, 0, 7010, 0, 512, 0, 0, 7010, 512, },
/* FULL RANGE */
[3] = { 8192, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 8192, 0, },
};
static void hdmi_core_ddc_init(struct hdmi_core_data *core)
{
void __iomem *base = core->base;
const unsigned long long iclk = 266000000; /* DSS L3 ICLK */
const unsigned ss_scl_high = 4000; /* ns */
const unsigned ss_scl_low = 4700; /* ns */
const unsigned fs_scl_high = 600; /* ns */
const unsigned fs_scl_low = 1300; /* ns */
const unsigned sda_hold = 300; /* ns */
const unsigned sfr_div = 10;
unsigned long long sfr;
unsigned v;
sfr = iclk / sfr_div; /* SFR_DIV */
sfr /= 1000; /* SFR clock in kHz */
/* Reset */
REG_FLD_MOD(base, HDMI_CORE_I2CM_SOFTRSTZ, 0, 0, 0);
if (hdmi_wait_for_bit_change(base, HDMI_CORE_I2CM_SOFTRSTZ,
0, 0, 1) != 1)
DSSERR("HDMI I2CM reset failed\n");
/* Standard (0) or Fast (1) Mode */
REG_FLD_MOD(base, HDMI_CORE_I2CM_DIV, 0, 3, 3);
/* Standard Mode SCL High counter */
v = DIV_ROUND_UP_ULL(ss_scl_high * sfr, 1000000);
REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR,
(v >> 8) & 0xff, 7, 0);
REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR,
v & 0xff, 7, 0);
/* Standard Mode SCL Low counter */
v = DIV_ROUND_UP_ULL(ss_scl_low * sfr, 1000000);
REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR,
(v >> 8) & 0xff, 7, 0);
REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR,
v & 0xff, 7, 0);
/* Fast Mode SCL High Counter */
v = DIV_ROUND_UP_ULL(fs_scl_high * sfr, 1000000);
REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR,
(v >> 8) & 0xff, 7, 0);
REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR,
v & 0xff, 7, 0);
/* Fast Mode SCL Low Counter */
v = DIV_ROUND_UP_ULL(fs_scl_low * sfr, 1000000);
REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR,
(v >> 8) & 0xff, 7, 0);
REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR,
v & 0xff, 7, 0);
/* SDA Hold Time */
v = DIV_ROUND_UP_ULL(sda_hold * sfr, 1000000);
REG_FLD_MOD(base, HDMI_CORE_I2CM_SDA_HOLD_ADDR, v & 0xff, 7, 0);
REG_FLD_MOD(base, HDMI_CORE_I2CM_SLAVE, 0x50, 6, 0);
REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGADDR, 0x30, 6, 0);
/* NACK_POL to high */
REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 7, 7);
/* NACK_MASK to unmasked */
REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x0, 6, 6);
/* ARBITRATION_POL to high */
REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 3, 3);
/* ARBITRATION_MASK to unmasked */
REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x0, 2, 2);