blob: 174646afd866f761a699cc8d8952e45170c22de0 [file] [log] [blame]
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* arch/arm/cpu/armv8/txl/cec/cec.c
*
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
*
*/
#include <common.h>
#include <command.h>
#include <asm/cpu_id.h>
#include <asm/arch/io.h>
#include <asm/arch/cec_tx_reg.h>
#include <amlogic/aml_cec.h>
#include <asm/arch/secure_apb.h>
#include "cec.h"
static void waiting_aocec_free(void) {
do {
unsigned long cnt = 0;
while (readl(P_AO_CEC_RW_REG) & (1<<23))
{
if (5000 == cnt++)
{
break;
}
}
} while(0);
}
static unsigned long cec_rd_reg(unsigned long addr)
{
unsigned long data32;
waiting_aocec_free();
data32 = 0;
data32 |= 0 << 16; /* [16] cec_reg_wr */
data32 |= 0 << 8; /* [15:8] cec_reg_wrdata */
data32 |= addr << 0; /* [7:0] cec_reg_addr */
writel(data32, P_AO_CEC_RW_REG);
waiting_aocec_free();
data32 = ((readl(P_AO_CEC_RW_REG)) >> 24) & 0xff;
return (data32);
} /* cec_rd_reg */
static void cec_wr_reg (unsigned long addr, unsigned long data)
{
unsigned long data32;
waiting_aocec_free();
data32 = 0;
data32 |= 1 << 16; /* [16] cec_reg_wr */
data32 |= data << 8; /* [15:8] cec_reg_wrdata */
data32 |= addr << 0; /* [7:0] cec_reg_addr */
writel(data32, P_AO_CEC_RW_REG);
} /* aocec_wr_only_reg */
static inline void cec_set_bits_dwc(uint32_t reg, uint32_t bits,
uint32_t start, uint32_t len)
{
unsigned int tmp;
tmp = cec_rd_reg(reg);
tmp &= ~(((1 << len) - 1) << start);
tmp |= (bits << start);
cec_wr_reg(reg, tmp);
}
void cec_set_reg_bits(unsigned long addr, unsigned int value,
unsigned int offset, unsigned int len)
{
unsigned int data32 = 0;
data32 = readl(addr);
data32 &= ~(((1 << len) - 1) << offset);
data32 |= (value & ((1 << len) - 1)) << offset;
writel(data32, addr);
}
static void cec_arbit_bit_time_set(unsigned bit_set, unsigned time_set)
{
//11bit:bit[10:0]
switch (bit_set) {
case 3:
//3 bit
cec_wr_reg(AO_CEC_TXTIME_4BIT_BIT7_0, time_set & 0xff);
cec_wr_reg(AO_CEC_TXTIME_4BIT_BIT10_8, (time_set >> 8) & 0x7);
break;
//5 bit
case 5:
cec_wr_reg(AO_CEC_TXTIME_2BIT_BIT7_0, time_set & 0xff);
cec_wr_reg(AO_CEC_TXTIME_2BIT_BIT10_8, (time_set >> 8) & 0x7);
//7 bit
case 7:
cec_wr_reg(AO_CEC_TXTIME_17MS_BIT7_0, time_set & 0xff);
cec_wr_reg(AO_CEC_TXTIME_17MS_BIT10_8, (time_set >> 8) & 0x7);
break;
default:
break;
}
}
void cec_hw_reset(void)
{
unsigned int reg;
printf("cec a reset cmd\n");
reg = readl(P_AO_CRT_CLK_CNTL1);
/* 24MHz/ (731 + 1) = 32786.885Hz */
reg &= ~(0x7ff << 16);
reg |= (731 << 16); /* divider from 24MHz */
reg |= (0x1 << 26);
reg &= ~(0x800 << 16); /* select divider */
writel(reg, P_AO_CRT_CLK_CNTL1);
/* set up pinmux */
writel(readl(P_AO_RTI_PIN_MUX_REG) & (~(1 << 14 | 1 << 17)), P_AO_RTI_PIN_MUX_REG);
writel(readl(P_AO_RTI_PULL_UP_REG) & (~(1 << 9)), P_AO_RTI_PULL_UP_REG);
writel(readl(P_AO_RTI_PIN_MUX_REG) | (1 << 15), P_AO_RTI_PIN_MUX_REG);
// Assert SW reset AO_CEC
writel(0x1, P_AO_CEC_GEN_CNTL);
// Enable gated clock (Normal mode).
writel(readl(P_AO_CEC_GEN_CNTL) | (1<<1), P_AO_CEC_GEN_CNTL);
udelay(100);
// Release SW reset
writel(readl(P_AO_CEC_GEN_CNTL) & ~(1<<0), P_AO_CEC_GEN_CNTL);
writel(readl(P_AO_CEC_INTR_MASKN) | (0x03 << 1), P_AO_CEC_INTR_MASKN);
cec_arbit_bit_time_set(3, 0x118);
cec_arbit_bit_time_set(5, 0x000);
cec_arbit_bit_time_set(7, 0x2aa);
}
static void cec_hw_buf_clear(void)
{
cec_wr_reg(CEC_RX_MSG_CMD, RX_DISABLE);
cec_wr_reg(CEC_TX_MSG_CMD, TX_ABORT);
cec_wr_reg(CEC_RX_CLEAR_BUF, 1);
cec_wr_reg(CEC_TX_CLEAR_BUF, 1);
udelay(100);
cec_wr_reg(CEC_RX_CLEAR_BUF, 0);
cec_wr_reg(CEC_TX_CLEAR_BUF, 0);
udelay(100);
cec_wr_reg(CEC_RX_MSG_CMD, RX_NO_OP);
cec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP);
}
static void cec_set_log_addr(int l_add)
{
cec_wr_reg(CEC_LOGICAL_ADDR0, 0);
cec_hw_buf_clear();
cec_wr_reg(CEC_LOGICAL_ADDR0, (l_add & 0xf));
udelay(100);
cec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | (l_add & 0xf));
}
static unsigned int cec_get_log_addr(void)
{
return cec_rd_reg(CEC_LOGICAL_ADDR0);
}
int cec_hw_init(int logic_addr, unsigned char fun_cfg)
{
if (fun_cfg & (1 << CEC_FUNC_MASK)) {
cec_hw_reset();
cec_set_log_addr(logic_addr);
}
writel(fun_cfg, P_AO_DEBUG_REG0);
printf("cec function:%#x, log_addr:%#x,%#x\n", readl(P_AO_DEBUG_REG0),
cec_get_log_addr(), readl(AO_DEBUG_REG1));
return 0;
}