blob: 631fc1f98d6a53733aa4ea599d2b7b1b0734326c [file] [log] [blame]
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* drivers/display/vout/vdac.c
*
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
*
*/
#include <common.h>
#include <malloc.h>
#include <asm/arch/register.h>
#include <asm/arch/secure_apb.h>
#include <amlogic/aml_efuse.h>
#include <asm/arch/cpu.h>
#include <asm/cpu_id.h>
#include "vdac.h"
static struct meson_vdac_ctrl_s *vdac_ctrl;
static unsigned int pri_flag;
#define REG_ADDR_HIU(reg) (reg + 0L)
static void vdac_write_hiu(unsigned int addr, unsigned int val)
{
*(volatile unsigned int *)REG_ADDR_HIU(addr) = (val);
}
static unsigned int vdac_read_hiu(unsigned int addr)
{
return *(volatile unsigned int *)(REG_ADDR_HIU(addr));
}
static void vdac_set_hiu_bits(unsigned int addr, unsigned int val,
unsigned int start, unsigned int len)
{
vdac_write_hiu(addr, ((vdac_read_hiu(addr) &
~(((1L << (len))-1) << (start))) |
(((val)&((1L<<(len))-1)) << (start))));
}
static int vdac_ctrl_config(bool on, unsigned int reg, unsigned int bit)
{
unsigned int val;
int i = 0;
int ret = -1;
if (!vdac_ctrl) {
printf("%s: vdac_ctrl data is NULL\n", __func__);
return ret;
}
while (i < VDAC_CTRL_MAX) {
if (vdac_ctrl[i].reg == VDAC_REG_MAX)
break;
if ((vdac_ctrl[i].reg == reg) && (vdac_ctrl[i].bit == bit)) {
if (on)
val = vdac_ctrl[i].val;
else
val = vdac_ctrl[i].val ? 0 : 1;
vdac_set_hiu_bits(reg, val, bit, vdac_ctrl[i].len);
//if (vdac_debug_print) {
// printf("vdac: reg=0x%02x set bit%d=%d, readback=0x%08x\n",
// reg, bit, val, vdac_hiu_reg_read(reg));
//}
ret = 0;
break;
}
i++;
}
return ret;
}
static void vdac_enable_cvbs_out(bool on)
{
unsigned int reg_cntl0 = HHI_VDAC_CNTL0;
unsigned int reg_cntl1 = HHI_VDAC_CNTL1;
if (on) {
if (get_cpu_id().family_id <= MESON_CPU_MAJOR_ID_GXLX)
vdac_set_hiu_bits(reg_cntl0, 0, 12, 4);
else
vdac_set_hiu_bits(reg_cntl0, 0x6, 12, 4);
vdac_ctrl_config(1, reg_cntl1, 3);
vdac_ctrl_config(1, reg_cntl0, 0);
vdac_ctrl_config(1, reg_cntl0, 9);
if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_TXLX) {
vdac_ctrl_config(0, reg_cntl0, 13);
udelay(5);
vdac_ctrl_config(1, reg_cntl0, 13);
}
if (get_cpu_id().family_id < MESON_CPU_MAJOR_ID_G12A)
vdac_ctrl_config(0, reg_cntl0, 10);
} else {
vdac_ctrl_config(0, reg_cntl0, 9);
vdac_ctrl_config(0, reg_cntl0, 0);
vdac_ctrl_config(0, reg_cntl1, 3);
}
}
void vdac_enable(bool on, unsigned int module_sel)
{
if (!vdac_ctrl) {
printf("%s: vdac_ctrl data is NULL\n", __func__);
return;
}
printf("%s: %d, module_sel:0x%x\n", __func__, on, module_sel);
switch (module_sel) {
case VDAC_MODULE_CVBS_OUT:
if (on) {
pri_flag |= VDAC_MODULE_CVBS_OUT;
vdac_enable_cvbs_out(1);
} else {
pri_flag &= ~VDAC_MODULE_CVBS_OUT;
vdac_enable_cvbs_out(0);
}
break;
default:
printf("%s:module_sel: 0x%x wrong module index !! ",
__func__, module_sel);
break;
}
}
int vdac_vref_adj(unsigned int value)
{
unsigned int reg = HHI_VDAC_CNTL0;
unsigned int bit = 16;
int i = 0;
int ret = -1;
if (!vdac_ctrl) {
printf("%s: vdac_ctrl data is NULL\n", __func__);
return ret;
}
while (i < VDAC_CTRL_MAX) {
if (vdac_ctrl[i].reg == VDAC_REG_MAX)
break;
if ((vdac_ctrl[i].reg == reg) && (vdac_ctrl[i].bit == bit)) {
vdac_set_hiu_bits(reg, value, bit, vdac_ctrl[i].len);
//if (vdac_debug_print) {
// printf("vdac: reg=0x%x set bit%d=0x%x, readback=0x%08x\n",
// reg, bit, value, vdac_hiu_reg_read(reg));
//}
ret = 0;
break;
}
i++;
}
return ret;
}
static void vdac_gsw_init(void)
{
unsigned int reg = HHI_VDAC_CNTL1;
unsigned int bit = 0;
int i = 0;
int ret;
if (!vdac_ctrl) {
printf("%s: vdac_ctrl is NULL\n", __func__);
return;
}
ret = efuse_get_cali_cvbs();
if (ret == -1)
return;
printf("%s: 0x%x\n", __func__, ret);
while (i < VDAC_CTRL_MAX) {
if (vdac_ctrl[i].reg == VDAC_REG_MAX)
break;
if (vdac_ctrl[i].reg == reg && vdac_ctrl[i].bit == bit) {
vdac_set_hiu_bits(reg, ret, bit, vdac_ctrl[i].len);
break;
}
i++;
}
}
static struct meson_vdac_ctrl_s vdac_ctrl_enable_gxl[] = {
{HHI_VDAC_CNTL0, 0, 9, 1},
{HHI_VDAC_CNTL0, 1, 10, 1},
{HHI_VDAC_CNTL0, 1, 0, 1},
{HHI_VDAC_CNTL0, 0, 16, 5}, /* vref adj */
{HHI_VDAC_CNTL1, 0, 0, 3}, /*gsw */
{HHI_VDAC_CNTL1, 0, 3, 1},
{VDAC_REG_MAX, 0, 0, 0},
};
static struct meson_vdac_ctrl_s vdac_ctrl_enable_txl[] = {
{HHI_VDAC_CNTL0, 1, 9, 1},
{HHI_VDAC_CNTL0, 1, 10, 1},
{HHI_VDAC_CNTL0, 1, 0, 1},
{HHI_VDAC_CNTL0, 0, 16, 5}, /* vref adj */
{HHI_VDAC_CNTL1, 0, 0, 3}, /*gsw */
{HHI_VDAC_CNTL1, 1, 3, 1},
{VDAC_REG_MAX, 0, 0, 0},
};
static struct meson_vdac_ctrl_s vdac_ctrl_enable_txlx[] = {
{HHI_VDAC_CNTL0, 1, 9, 1},
{HHI_VDAC_CNTL0, 1, 10, 1},
{HHI_VDAC_CNTL0, 1, 0, 1},
{HHI_VDAC_CNTL0, 0, 13, 1}, /* bandgap */
{HHI_VDAC_CNTL0, 0, 16, 5}, /* vref adj */
{HHI_VDAC_CNTL1, 0, 0, 3}, /*gsw */
{HHI_VDAC_CNTL1, 1, 3, 1},
{VDAC_REG_MAX, 0, 0, 0},
};
static struct meson_vdac_ctrl_s vdac_ctrl_enable_g12ab[] = {
{HHI_VDAC_CNTL0, 0, 9, 1},
{HHI_VDAC_CNTL0, 1, 0, 1},
{HHI_VDAC_CNTL0, 0, 16, 5}, /* vref adj */
{HHI_VDAC_CNTL1, 0, 0, 3}, /*gsw */
{HHI_VDAC_CNTL1, 0, 3, 1},
{VDAC_REG_MAX, 0, 0, 0},
};
static struct meson_vdac_ctrl_s vdac_ctrl_enable_tl1[] = {
{HHI_VDAC_CNTL0, 0, 9, 1},
{HHI_VDAC_CNTL0, 1, 0, 1},
{HHI_VDAC_CNTL0, 0, 16, 5}, /* vref adj */
{HHI_VDAC_CNTL1, 0, 0, 3}, /*gsw */
{HHI_VDAC_CNTL1, 0, 3, 1},
{HHI_VDAC_CNTL1, 0, 7, 1}, /* bandgap */
{VDAC_REG_MAX, 0, 0, 0},
};
static struct meson_vdac_ctrl_s vdac_ctrl_enable_t5w[] = {
{HHI_VDAC_CNTL1, 0, 0, 7}, /*gsw */
{VDAC_REG_MAX, 0, 0, 0},
};
void vdac_ctrl_config_probe(void)
{
pri_flag = 0;
switch (get_cpu_id().family_id) {
case MESON_CPU_MAJOR_ID_GXL:
case MESON_CPU_MAJOR_ID_GXM:
case MESON_CPU_MAJOR_ID_GXLX:
vdac_ctrl = vdac_ctrl_enable_gxl;
break;
case MESON_CPU_MAJOR_ID_TXL:
case MESON_CPU_MAJOR_ID_TXHD:
vdac_ctrl = vdac_ctrl_enable_txl;
break;
case MESON_CPU_MAJOR_ID_TXLX:
vdac_ctrl = vdac_ctrl_enable_txlx;
break;
case MESON_CPU_MAJOR_ID_G12A:
case MESON_CPU_MAJOR_ID_G12B:
case MESON_CPU_MAJOR_ID_SM1:
vdac_ctrl = vdac_ctrl_enable_g12ab;
break;
case MESON_CPU_MAJOR_ID_TL1:
case MESON_CPU_MAJOR_ID_TM2:
vdac_ctrl = vdac_ctrl_enable_tl1;
break;
case MESON_CPU_MAJOR_ID_T5W:
vdac_ctrl = vdac_ctrl_enable_t5w;
break;
default:
break;
}
vdac_gsw_init();
return;
}