/* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * * 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 . */ #include #include "hdmi.h" void init_ddc(struct hdmi *hdmi) { uint32_t ddc_speed; hdmi_write(hdmi, REG_HDMI_DDC_CTRL, HDMI_DDC_CTRL_SW_STATUS_RESET); hdmi_write(hdmi, REG_HDMI_DDC_CTRL, HDMI_DDC_CTRL_SOFT_RESET); ddc_speed = hdmi_read(hdmi, REG_HDMI_DDC_SPEED); ddc_speed |= HDMI_DDC_SPEED_THRESHOLD(2); ddc_speed |= HDMI_DDC_SPEED_PRESCALE(12); hdmi_write(hdmi, REG_HDMI_DDC_SPEED, ddc_speed); hdmi_write(hdmi, REG_HDMI_DDC_SETUP, HDMI_DDC_SETUP_TIMEOUT(0xff)); /* enable reference timer for 19us */ hdmi_write(hdmi, REG_HDMI_DDC_REF, HDMI_DDC_REF_REFTIMER_ENABLE | HDMI_DDC_REF_REFTIMER(19)); } int ddc_clear_irq(struct hdmi *hdmi) { struct hdmi_i2c_adapter *hdmi_i2c = to_hdmi_i2c_adapter(hdmi->i2c); struct drm_device *dev = hdmi->dev; uint32_t retry = 0xffff; uint32_t ddc_int_ctrl; do { --retry; hdmi_write(hdmi, REG_HDMI_DDC_INT_CTRL, HDMI_DDC_INT_CTRL_SW_DONE_ACK | HDMI_DDC_INT_CTRL_SW_DONE_MASK); ddc_int_ctrl = hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL); } while ((ddc_int_ctrl & HDMI_DDC_INT_CTRL_SW_DONE_INT) && retry); if (!retry) { dev_err(dev->dev, "timeout waiting for DDC\n"); return -ETIMEDOUT; } hdmi_i2c->sw_done = false; return 0; } int hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset, u8 *data, u16 data_len, bool self_retry) { int rc; int retry = 10; struct i2c_msg msgs[] = { { .addr = addr >> 1, .flags = 0, .len = 1, .buf = &offset, }, { .addr = addr >> 1, .flags = I2C_M_RD, .len = data_len, .buf = data, } }; DBG("Start DDC read"); retry: rc = i2c_transfer(hdmi->i2c, msgs, 2); retry--; if (rc == 2) rc = 0; else if (self_retry && (retry > 0)) goto retry; else rc = -EIO; DBG("End DDC read %d", rc); return rc; } #define HDCP_DDC_WRITE_MAX_BYTE_NUM 1024 int hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset, u8 *data, u16 data_len, bool self_retry) { int rc; int retry = 10; u8 buf[HDCP_DDC_WRITE_MAX_BYTE_NUM]; struct i2c_msg msgs[] = { { .addr = addr >> 1, .flags = 0, .len = 1, } }; pr_debug("TESTING ! REMOVE RETRY Start DDC write"); if (data_len > (HDCP_DDC_WRITE_MAX_BYTE_NUM - 1)) { pr_err("%s: write size too big\n", __func__); return -ERANGE; } buf[0] = offset; memcpy(&buf[1], data, data_len); msgs[0].buf = buf; msgs[0].len = data_len + 1; retry: rc = i2c_transfer(hdmi->i2c, msgs, 1); retry--; if (rc == 1) rc = 0; else if (self_retry && (retry > 0)) goto retry; else rc = -EIO; DBG("End DDC write %d", rc); return rc; }