| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| */ |
| |
| #include <common.h> |
| #include <asm/arch/cpu.h> |
| #include <amlogic/cpu_id.h> |
| #include "vdac.h" |
| #include "cvbs_reg.h" |
| |
| static struct vdac_data_s *vdac_data; |
| static unsigned int pri_flag; |
| |
| #define REG_ADDR_VDAC(reg) (reg + 0L) |
| |
| static void vdac_write_reg(unsigned int addr, unsigned int val) |
| { |
| *(volatile unsigned int *)REG_ADDR_VDAC(addr) = (val); |
| } |
| |
| static unsigned int vdac_read_reg(unsigned int addr) |
| { |
| return *(volatile unsigned int *)(REG_ADDR_VDAC(addr)); |
| } |
| |
| static void vdac_set_reg_bits(unsigned int addr, unsigned int val, |
| unsigned int start, unsigned int len) |
| { |
| vdac_write_reg(addr, ((vdac_read_reg(addr) & |
| ~(((1L << (len))-1) << (start))) | |
| (((val)&((1L<<(len))-1)) << (start)))); |
| } |
| |
| static inline unsigned int vdac_get_reg_bits(unsigned int reg, |
| unsigned int start, unsigned int len) |
| { |
| unsigned int val; |
| |
| val = ((vdac_read_reg(reg) >> (start)) & ((1L << (len)) - 1)); |
| |
| return val; |
| } |
| |
| static int vdac_ctrl_config(bool on, unsigned int reg, unsigned int bit) |
| { |
| struct meson_vdac_ctrl_s *vdac_ctrl; |
| unsigned int val; |
| int i = 0; |
| int ret = -1; |
| |
| if (!vdac_data) { |
| printf("%s: vdac_data is NULL\n", __func__); |
| return ret; |
| } |
| |
| if (!vdac_data->vdac_ctrl) { |
| printf("%s: vdac_ctrl is NULL\n", __func__); |
| return ret; |
| } |
| |
| vdac_ctrl = vdac_data->vdac_ctrl; |
| 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_reg_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_dac_input(unsigned int reg_cntl0) |
| { |
| vdac_set_reg_bits(reg_cntl0, 0x2, 0, 3); |
| vdac_set_reg_bits(reg_cntl0, 0x1, 4, 1); |
| vdac_set_reg_bits(reg_cntl0, 0x1, 6, 1); |
| vdac_set_reg_bits(reg_cntl0, 0x3, 13, 3); |
| vdac_set_reg_bits(reg_cntl0, 0x10, 18, 5); |
| } |
| |
| static void vdac_enable_cvbs_out(bool on) |
| { |
| unsigned int reg_cntl0; |
| unsigned int reg_cntl1; |
| |
| if (!vdac_data) { |
| printf("%s: vdac_data is NULL\n", __func__); |
| return; |
| } |
| |
| reg_cntl0 = vdac_data->reg_ctrl0; |
| reg_cntl1 = vdac_data->reg_ctrl1; |
| |
| if (on) { |
| if (vdac_data->cpu_id == VDAC_CPU_S4) { |
| vdac_enable_dac_input(reg_cntl0); |
| vdac_ctrl_config(1, reg_cntl1, 7); |
| } else { |
| vdac_set_reg_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); |
| } |
| } else { |
| if (vdac_data->cpu_id == VDAC_CPU_S4) { |
| vdac_set_reg_bits(reg_cntl0, 0x0, 4, 1); |
| vdac_ctrl_config(0, reg_cntl1, 7); |
| } 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_data) { |
| printf("%s: vdac_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; |
| } |
| |
| if (vdac_data->cpu_id == VDAC_CPU_S4) { |
| if (!vdac_get_reg_bits(vdac_data->reg_ctrl0, 11, 1)) |
| vdac_set_reg_bits(vdac_data->reg_ctrl0, 1, 11, 1); |
| } |
| } |
| |
| int vdac_ctrl_vref_adj(unsigned int value) |
| { |
| struct meson_vdac_ctrl_s *vdac_ctrl; |
| unsigned int reg; |
| unsigned int bit = 16; |
| int i = 0; |
| int ret = -1; |
| |
| if (!vdac_data) { |
| printf("%s: vdac_data is NULL\n", __func__); |
| return ret; |
| } |
| |
| if (!vdac_data->vdac_ctrl) { |
| printf("%s: vdac_ctrl is NULL\n", __func__); |
| return ret; |
| } |
| |
| vdac_ctrl = vdac_data->vdac_ctrl; |
| reg = vdac_data->reg_ctrl0; |
| 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_reg_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 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_sc2[] = { |
| {ANACTRL_VDAC_CTRL0, 0, 9, 1}, |
| {ANACTRL_VDAC_CTRL0, 1, 0, 1}, |
| {ANACTRL_VDAC_CTRL0, 0, 16, 5}, /* vref adj */ |
| {ANACTRL_VDAC_CTRL1, 0, 0, 3}, /*gsw */ |
| {ANACTRL_VDAC_CTRL1, 0, 3, 1}, |
| {ANACTRL_VDAC_CTRL1, 0, 7, 1}, /* bandgap */ |
| {VDAC_REG_MAX, 0, 0, 0}, |
| }; |
| |
| static struct meson_vdac_ctrl_s vdac_ctrl_enable_s4[] = { |
| {ANACTRL_VDAC_CTRL0, 0, 9, 1}, |
| {ANACTRL_VDAC_CTRL0, 1, 0, 1}, |
| {ANACTRL_VDAC_CTRL1, 1, 7, 1}, /* cdac_pwd */ |
| {VDAC_REG_MAX, 0, 0, 0}, |
| }; |
| |
| struct vdac_data_s vdac_data_g12ab = { |
| .cpu_id = VDAC_CPU_G12AB, |
| .reg_ctrl0 = HHI_VDAC_CNTL0, |
| .reg_ctrl1 = HHI_VDAC_CNTL1, |
| .vdac_ctrl = vdac_ctrl_enable_g12ab, |
| }; |
| |
| struct vdac_data_s vdac_data_sc2 = { |
| .cpu_id = VDAC_CPU_SC2, |
| .reg_ctrl0 = ANACTRL_VDAC_CTRL0, |
| .reg_ctrl1 = ANACTRL_VDAC_CTRL1, |
| .vdac_ctrl = vdac_ctrl_enable_sc2, |
| }; |
| |
| struct vdac_data_s vdac_data_s4 = { |
| .cpu_id = VDAC_CPU_S4, |
| .reg_ctrl0 = ANACTRL_VDAC_CTRL0, |
| .reg_ctrl1 = ANACTRL_VDAC_CTRL1, |
| .vdac_ctrl = vdac_ctrl_enable_s4, |
| }; |
| |
| void vdac_ctrl_config_probe(void) |
| { |
| pri_flag = 0; |
| |
| switch (get_cpu_id().family_id) { |
| case MESON_CPU_MAJOR_ID_G12A: |
| case MESON_CPU_MAJOR_ID_G12B: |
| vdac_data = &vdac_data_g12ab; |
| break; |
| case MESON_CPU_MAJOR_ID_SC2: |
| vdac_data = &vdac_data_sc2; |
| break; |
| case MESON_CPU_MAJOR_ID_S4: |
| vdac_data = &vdac_data_s4; |
| default: |
| vdac_data = &vdac_data_s4; |
| break; |
| } |
| |
| return; |
| } |