Path: blob/master/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
26516 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* adv7511_cec.c - Analog Devices ADV7511/33 cec driver3*4* Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.5*/67#include <linux/device.h>8#include <linux/module.h>9#include <linux/slab.h>10#include <linux/clk.h>1112#include <media/cec.h>1314#include <drm/display/drm_hdmi_cec_helper.h>1516#include "adv7511.h"1718static const u8 ADV7511_REG_CEC_RX_FRAME_HDR[] = {19ADV7511_REG_CEC_RX1_FRAME_HDR,20ADV7511_REG_CEC_RX2_FRAME_HDR,21ADV7511_REG_CEC_RX3_FRAME_HDR,22};2324static const u8 ADV7511_REG_CEC_RX_FRAME_LEN[] = {25ADV7511_REG_CEC_RX1_FRAME_LEN,26ADV7511_REG_CEC_RX2_FRAME_LEN,27ADV7511_REG_CEC_RX3_FRAME_LEN,28};2930#define ADV7511_INT1_CEC_MASK \31(ADV7511_INT1_CEC_TX_READY | ADV7511_INT1_CEC_TX_ARBIT_LOST | \32ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1 | \33ADV7511_INT1_CEC_RX_READY2 | ADV7511_INT1_CEC_RX_READY3)3435static void adv_cec_tx_raw_status(struct adv7511 *adv7511, u8 tx_raw_status)36{37unsigned int offset = adv7511->info->reg_cec_offset;38unsigned int val;3940if (regmap_read(adv7511->regmap_cec,41ADV7511_REG_CEC_TX_ENABLE + offset, &val))42return;4344if ((val & 0x01) == 0)45return;4647if (tx_raw_status & ADV7511_INT1_CEC_TX_ARBIT_LOST) {48drm_connector_hdmi_cec_transmit_attempt_done(adv7511->cec_connector,49CEC_TX_STATUS_ARB_LOST);50return;51}52if (tx_raw_status & ADV7511_INT1_CEC_TX_RETRY_TIMEOUT) {53u8 status;54u8 err_cnt = 0;55u8 nack_cnt = 0;56u8 low_drive_cnt = 0;57unsigned int cnt;5859/*60* We set this status bit since this hardware performs61* retransmissions.62*/63status = CEC_TX_STATUS_MAX_RETRIES;64if (regmap_read(adv7511->regmap_cec,65ADV7511_REG_CEC_TX_LOW_DRV_CNT + offset, &cnt)) {66err_cnt = 1;67status |= CEC_TX_STATUS_ERROR;68} else {69nack_cnt = cnt & 0xf;70if (nack_cnt)71status |= CEC_TX_STATUS_NACK;72low_drive_cnt = cnt >> 4;73if (low_drive_cnt)74status |= CEC_TX_STATUS_LOW_DRIVE;75}76drm_connector_hdmi_cec_transmit_done(adv7511->cec_connector, status,770, nack_cnt, low_drive_cnt,78err_cnt);79return;80}81if (tx_raw_status & ADV7511_INT1_CEC_TX_READY) {82drm_connector_hdmi_cec_transmit_attempt_done(adv7511->cec_connector,83CEC_TX_STATUS_OK);84return;85}86}8788static void adv7511_cec_rx(struct adv7511 *adv7511, int rx_buf)89{90unsigned int offset = adv7511->info->reg_cec_offset;91struct cec_msg msg = {};92unsigned int len;93unsigned int val;94u8 i;9596if (regmap_read(adv7511->regmap_cec,97ADV7511_REG_CEC_RX_FRAME_LEN[rx_buf] + offset, &len))98return;99100msg.len = len & 0x1f;101102if (msg.len > 16)103msg.len = 16;104105if (!msg.len)106return;107108for (i = 0; i < msg.len; i++) {109regmap_read(adv7511->regmap_cec,110i + ADV7511_REG_CEC_RX_FRAME_HDR[rx_buf] + offset,111&val);112msg.msg[i] = val;113}114115/* Toggle RX Ready Clear bit to re-enable this RX buffer */116regmap_update_bits(adv7511->regmap_cec,117ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf),118BIT(rx_buf));119regmap_update_bits(adv7511->regmap_cec,120ADV7511_REG_CEC_RX_BUFFERS + offset, BIT(rx_buf), 0);121122drm_connector_hdmi_cec_received_msg(adv7511->cec_connector, &msg);123}124125int adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)126{127unsigned int offset = adv7511->info->reg_cec_offset;128const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY |129ADV7511_INT1_CEC_TX_ARBIT_LOST |130ADV7511_INT1_CEC_TX_RETRY_TIMEOUT;131const u32 irq_rx_mask = ADV7511_INT1_CEC_RX_READY1 |132ADV7511_INT1_CEC_RX_READY2 |133ADV7511_INT1_CEC_RX_READY3;134unsigned int rx_status;135int rx_order[3] = { -1, -1, -1 };136int i;137int irq_status = IRQ_NONE;138139if (irq1 & irq_tx_mask) {140adv_cec_tx_raw_status(adv7511, irq1);141irq_status = IRQ_HANDLED;142}143144if (!(irq1 & irq_rx_mask))145return irq_status;146147if (regmap_read(adv7511->regmap_cec,148ADV7511_REG_CEC_RX_STATUS + offset, &rx_status))149return irq_status;150151/*152* ADV7511_REG_CEC_RX_STATUS[5:0] contains the reception order of RX153* buffers 0, 1, and 2 in bits [1:0], [3:2], and [5:4] respectively.154* The values are to be interpreted as follows:155*156* 0 = buffer unused157* 1 = buffer contains oldest received frame (if applicable)158* 2 = buffer contains second oldest received frame (if applicable)159* 3 = buffer contains third oldest received frame (if applicable)160*161* Fill rx_order with the sequence of RX buffer indices to162* read from in order, where -1 indicates that there are no163* more buffers to process.164*/165for (i = 0; i < 3; i++) {166unsigned int timestamp = (rx_status >> (2 * i)) & 0x3;167168if (timestamp)169rx_order[timestamp - 1] = i;170}171172/* Read CEC RX buffers in the appropriate order as prescribed above */173for (i = 0; i < 3; i++) {174int rx_buf = rx_order[i];175176if (rx_buf < 0)177break;178179adv7511_cec_rx(adv7511, rx_buf);180}181182return IRQ_HANDLED;183}184185int adv7511_cec_enable(struct drm_bridge *bridge, bool enable)186{187struct adv7511 *adv7511 = bridge_to_adv7511(bridge);188unsigned int offset = adv7511->info->reg_cec_offset;189190if (adv7511->i2c_cec == NULL)191return -EIO;192193if (!adv7511->cec_enabled_adap && enable) {194/* power up cec section */195regmap_update_bits(adv7511->regmap_cec,196ADV7511_REG_CEC_CLK_DIV + offset,1970x03, 0x01);198/* non-legacy mode and clear all rx buffers */199regmap_write(adv7511->regmap_cec,200ADV7511_REG_CEC_RX_BUFFERS + offset, 0x0f);201regmap_write(adv7511->regmap_cec,202ADV7511_REG_CEC_RX_BUFFERS + offset, 0x08);203/* initially disable tx */204regmap_update_bits(adv7511->regmap_cec,205ADV7511_REG_CEC_TX_ENABLE + offset, 1, 0);206/* enabled irqs: */207/* tx: ready */208/* tx: arbitration lost */209/* tx: retry timeout */210/* rx: ready 1-3 */211regmap_update_bits(adv7511->regmap,212ADV7511_REG_INT_ENABLE(1), 0x3f,213ADV7511_INT1_CEC_MASK);214} else if (adv7511->cec_enabled_adap && !enable) {215regmap_update_bits(adv7511->regmap,216ADV7511_REG_INT_ENABLE(1), 0x3f, 0);217/* disable address mask 1-3 */218regmap_update_bits(adv7511->regmap_cec,219ADV7511_REG_CEC_LOG_ADDR_MASK + offset,2200x70, 0x00);221/* power down cec section */222regmap_update_bits(adv7511->regmap_cec,223ADV7511_REG_CEC_CLK_DIV + offset,2240x03, 0x00);225adv7511->cec_valid_addrs = 0;226}227adv7511->cec_enabled_adap = enable;228return 0;229}230231int adv7511_cec_log_addr(struct drm_bridge *bridge, u8 addr)232{233struct adv7511 *adv7511 = bridge_to_adv7511(bridge);234unsigned int offset = adv7511->info->reg_cec_offset;235unsigned int i, free_idx = ADV7511_MAX_ADDRS;236237if (!adv7511->cec_enabled_adap)238return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;239240if (addr == CEC_LOG_ADDR_INVALID) {241regmap_update_bits(adv7511->regmap_cec,242ADV7511_REG_CEC_LOG_ADDR_MASK + offset,2430x70, 0);244adv7511->cec_valid_addrs = 0;245return 0;246}247248for (i = 0; i < ADV7511_MAX_ADDRS; i++) {249bool is_valid = adv7511->cec_valid_addrs & (1 << i);250251if (free_idx == ADV7511_MAX_ADDRS && !is_valid)252free_idx = i;253if (is_valid && adv7511->cec_addr[i] == addr)254return 0;255}256if (i == ADV7511_MAX_ADDRS) {257i = free_idx;258if (i == ADV7511_MAX_ADDRS)259return -ENXIO;260}261adv7511->cec_addr[i] = addr;262adv7511->cec_valid_addrs |= 1 << i;263264switch (i) {265case 0:266/* enable address mask 0 */267regmap_update_bits(adv7511->regmap_cec,268ADV7511_REG_CEC_LOG_ADDR_MASK + offset,2690x10, 0x10);270/* set address for mask 0 */271regmap_update_bits(adv7511->regmap_cec,272ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,2730x0f, addr);274break;275case 1:276/* enable address mask 1 */277regmap_update_bits(adv7511->regmap_cec,278ADV7511_REG_CEC_LOG_ADDR_MASK + offset,2790x20, 0x20);280/* set address for mask 1 */281regmap_update_bits(adv7511->regmap_cec,282ADV7511_REG_CEC_LOG_ADDR_0_1 + offset,2830xf0, addr << 4);284break;285case 2:286/* enable address mask 2 */287regmap_update_bits(adv7511->regmap_cec,288ADV7511_REG_CEC_LOG_ADDR_MASK + offset,2890x40, 0x40);290/* set address for mask 1 */291regmap_update_bits(adv7511->regmap_cec,292ADV7511_REG_CEC_LOG_ADDR_2 + offset,2930x0f, addr);294break;295}296return 0;297}298299int adv7511_cec_transmit(struct drm_bridge *bridge, u8 attempts,300u32 signal_free_time, struct cec_msg *msg)301{302struct adv7511 *adv7511 = bridge_to_adv7511(bridge);303unsigned int offset = adv7511->info->reg_cec_offset;304u8 len = msg->len;305unsigned int i;306307/*308* The number of retries is the number of attempts - 1, but retry309* at least once. It's not clear if a value of 0 is allowed, so310* let's do at least one retry.311*/312regmap_update_bits(adv7511->regmap_cec,313ADV7511_REG_CEC_TX_RETRY + offset,3140x70, max(1, attempts - 1) << 4);315316/* blocking, clear cec tx irq status */317regmap_update_bits(adv7511->regmap, ADV7511_REG_INT(1), 0x38, 0x38);318319/* write data */320for (i = 0; i < len; i++)321regmap_write(adv7511->regmap_cec,322i + ADV7511_REG_CEC_TX_FRAME_HDR + offset,323msg->msg[i]);324325/* set length (data + header) */326regmap_write(adv7511->regmap_cec,327ADV7511_REG_CEC_TX_FRAME_LEN + offset, len);328/* start transmit, enable tx */329regmap_write(adv7511->regmap_cec,330ADV7511_REG_CEC_TX_ENABLE + offset, 0x01);331return 0;332}333334static int adv7511_cec_parse_dt(struct device *dev, struct adv7511 *adv7511)335{336adv7511->cec_clk = devm_clk_get(dev, "cec");337if (IS_ERR(adv7511->cec_clk)) {338int ret = PTR_ERR(adv7511->cec_clk);339340adv7511->cec_clk = NULL;341return ret;342}343clk_prepare_enable(adv7511->cec_clk);344adv7511->cec_clk_freq = clk_get_rate(adv7511->cec_clk);345return 0;346}347348int adv7511_cec_init(struct drm_bridge *bridge,349struct drm_connector *connector)350{351struct adv7511 *adv7511 = bridge_to_adv7511(bridge);352struct device *dev = &adv7511->i2c_main->dev;353unsigned int offset = adv7511->info->reg_cec_offset;354int ret = adv7511_cec_parse_dt(dev, adv7511);355356if (ret)357goto err_cec_parse_dt;358359adv7511->cec_connector = connector;360361regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, 0);362/* cec soft reset */363regmap_write(adv7511->regmap_cec,364ADV7511_REG_CEC_SOFT_RESET + offset, 0x01);365regmap_write(adv7511->regmap_cec,366ADV7511_REG_CEC_SOFT_RESET + offset, 0x00);367368/* non-legacy mode - use all three RX buffers */369regmap_write(adv7511->regmap_cec,370ADV7511_REG_CEC_RX_BUFFERS + offset, 0x08);371372regmap_write(adv7511->regmap_cec,373ADV7511_REG_CEC_CLK_DIV + offset,374((adv7511->cec_clk_freq / 750000) - 1) << 2);375376return 0;377378err_cec_parse_dt:379regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL,380ADV7511_CEC_CTRL_POWER_DOWN);381return ret == -EPROBE_DEFER ? ret : 0;382}383384385