cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ao-cec-g12a.c (21305B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Driver for Amlogic Meson AO CEC G12A Controller
      4 *
      5 * Copyright (C) 2017 Amlogic, Inc. All rights reserved
      6 * Copyright (C) 2019 BayLibre, SAS
      7 * Author: Neil Armstrong <narmstrong@baylibre.com>
      8 */
      9
     10#include <linux/bitfield.h>
     11#include <linux/clk.h>
     12#include <linux/device.h>
     13#include <linux/io.h>
     14#include <linux/delay.h>
     15#include <linux/kernel.h>
     16#include <linux/module.h>
     17#include <linux/of.h>
     18#include <linux/of_platform.h>
     19#include <linux/platform_device.h>
     20#include <linux/types.h>
     21#include <linux/interrupt.h>
     22#include <linux/reset.h>
     23#include <linux/slab.h>
     24#include <linux/regmap.h>
     25#include <media/cec.h>
     26#include <media/cec-notifier.h>
     27#include <linux/clk-provider.h>
     28
     29/* CEC Registers */
     30
     31#define CECB_CLK_CNTL_REG0		0x00
     32
     33#define CECB_CLK_CNTL_N1		GENMASK(11, 0)
     34#define CECB_CLK_CNTL_N2		GENMASK(23, 12)
     35#define CECB_CLK_CNTL_DUAL_EN		BIT(28)
     36#define CECB_CLK_CNTL_OUTPUT_EN		BIT(30)
     37#define CECB_CLK_CNTL_INPUT_EN		BIT(31)
     38
     39#define CECB_CLK_CNTL_REG1		0x04
     40
     41#define CECB_CLK_CNTL_M1		GENMASK(11, 0)
     42#define CECB_CLK_CNTL_M2		GENMASK(23, 12)
     43#define CECB_CLK_CNTL_BYPASS_EN		BIT(24)
     44
     45/*
     46 * [14:12] Filter_del. For glitch-filtering CEC line, ignore signal
     47 *       change pulse width < filter_del * T(filter_tick) * 3.
     48 * [9:8] Filter_tick_sel: Select which periodical pulse for
     49 *       glitch-filtering CEC line signal.
     50 *  - 0=Use T(xtal)*3 = 125ns;
     51 *  - 1=Use once-per-1us pulse;
     52 *  - 2=Use once-per-10us pulse;
     53 *  - 3=Use once-per-100us pulse.
     54 * [3]   Sysclk_en. 0=Disable system clock; 1=Enable system clock.
     55 * [2:1] cntl_clk
     56 *  - 0 = Disable clk (Power-off mode)
     57 *  - 1 = Enable gated clock (Normal mode)
     58 *  - 2 = Enable free-run clk (Debug mode)
     59 * [0] SW_RESET 1=Apply reset; 0=No reset.
     60 */
     61#define CECB_GEN_CNTL_REG		0x08
     62
     63#define CECB_GEN_CNTL_RESET		BIT(0)
     64#define CECB_GEN_CNTL_CLK_DISABLE	0
     65#define CECB_GEN_CNTL_CLK_ENABLE	1
     66#define CECB_GEN_CNTL_CLK_ENABLE_DBG	2
     67#define CECB_GEN_CNTL_CLK_CTRL_MASK	GENMASK(2, 1)
     68#define CECB_GEN_CNTL_SYS_CLK_EN	BIT(3)
     69#define CECB_GEN_CNTL_FILTER_TICK_125NS	0
     70#define CECB_GEN_CNTL_FILTER_TICK_1US	1
     71#define CECB_GEN_CNTL_FILTER_TICK_10US	2
     72#define CECB_GEN_CNTL_FILTER_TICK_100US	3
     73#define CECB_GEN_CNTL_FILTER_TICK_SEL	GENMASK(9, 8)
     74#define CECB_GEN_CNTL_FILTER_DEL	GENMASK(14, 12)
     75
     76/*
     77 * [7:0] cec_reg_addr
     78 * [15:8] cec_reg_wrdata
     79 * [16] cec_reg_wr
     80 *  - 0 = Read
     81 *  - 1 = Write
     82 * [31:24] cec_reg_rddata
     83 */
     84#define CECB_RW_REG			0x0c
     85
     86#define CECB_RW_ADDR			GENMASK(7, 0)
     87#define CECB_RW_WR_DATA			GENMASK(15, 8)
     88#define CECB_RW_WRITE_EN		BIT(16)
     89#define CECB_RW_BUS_BUSY		BIT(23)
     90#define CECB_RW_RD_DATA			GENMASK(31, 24)
     91
     92/*
     93 * [0] DONE Interrupt
     94 * [1] End Of Message Interrupt
     95 * [2] Not Acknowlegde Interrupt
     96 * [3] Arbitration Loss Interrupt
     97 * [4] Initiator Error Interrupt
     98 * [5] Follower Error Interrupt
     99 * [6] Wake-Up Interrupt
    100 */
    101#define CECB_INTR_MASKN_REG		0x10
    102#define CECB_INTR_CLR_REG		0x14
    103#define CECB_INTR_STAT_REG		0x18
    104
    105#define CECB_INTR_DONE			BIT(0)
    106#define CECB_INTR_EOM			BIT(1)
    107#define CECB_INTR_NACK			BIT(2)
    108#define CECB_INTR_ARB_LOSS		BIT(3)
    109#define CECB_INTR_INITIATOR_ERR		BIT(4)
    110#define CECB_INTR_FOLLOWER_ERR		BIT(5)
    111#define CECB_INTR_WAKE_UP		BIT(6)
    112
    113/* CEC Commands */
    114
    115#define CECB_CTRL		0x00
    116
    117#define CECB_CTRL_SEND		BIT(0)
    118#define CECB_CTRL_TYPE		GENMASK(2, 1)
    119#define CECB_CTRL_TYPE_RETRY	0
    120#define CECB_CTRL_TYPE_NEW	1
    121#define CECB_CTRL_TYPE_NEXT	2
    122
    123#define CECB_CTRL2		0x01
    124
    125#define CECB_CTRL2_RISE_DEL_MAX	GENMASK(4, 0)
    126
    127#define CECB_INTR_MASK		0x02
    128#define CECB_LADD_LOW		0x05
    129#define CECB_LADD_HIGH		0x06
    130#define CECB_TX_CNT		0x07
    131#define CECB_RX_CNT		0x08
    132#define CECB_STAT0		0x09
    133#define CECB_TX_DATA00		0x10
    134#define CECB_TX_DATA01		0x11
    135#define CECB_TX_DATA02		0x12
    136#define CECB_TX_DATA03		0x13
    137#define CECB_TX_DATA04		0x14
    138#define CECB_TX_DATA05		0x15
    139#define CECB_TX_DATA06		0x16
    140#define CECB_TX_DATA07		0x17
    141#define CECB_TX_DATA08		0x18
    142#define CECB_TX_DATA09		0x19
    143#define CECB_TX_DATA10		0x1A
    144#define CECB_TX_DATA11		0x1B
    145#define CECB_TX_DATA12		0x1C
    146#define CECB_TX_DATA13		0x1D
    147#define CECB_TX_DATA14		0x1E
    148#define CECB_TX_DATA15		0x1F
    149#define CECB_RX_DATA00		0x20
    150#define CECB_RX_DATA01		0x21
    151#define CECB_RX_DATA02		0x22
    152#define CECB_RX_DATA03		0x23
    153#define CECB_RX_DATA04		0x24
    154#define CECB_RX_DATA05		0x25
    155#define CECB_RX_DATA06		0x26
    156#define CECB_RX_DATA07		0x27
    157#define CECB_RX_DATA08		0x28
    158#define CECB_RX_DATA09		0x29
    159#define CECB_RX_DATA10		0x2A
    160#define CECB_RX_DATA11		0x2B
    161#define CECB_RX_DATA12		0x2C
    162#define CECB_RX_DATA13		0x2D
    163#define CECB_RX_DATA14		0x2E
    164#define CECB_RX_DATA15		0x2F
    165#define CECB_LOCK_BUF		0x30
    166
    167#define CECB_LOCK_BUF_EN	BIT(0)
    168
    169#define CECB_WAKEUPCTRL		0x31
    170
    171struct meson_ao_cec_g12a_data {
    172	/* Setup the internal CECB_CTRL2 register */
    173	bool				ctrl2_setup;
    174};
    175
    176struct meson_ao_cec_g12a_device {
    177	struct platform_device		*pdev;
    178	struct regmap			*regmap;
    179	struct regmap			*regmap_cec;
    180	spinlock_t			cec_reg_lock;
    181	struct cec_notifier		*notify;
    182	struct cec_adapter		*adap;
    183	struct cec_msg			rx_msg;
    184	struct clk			*oscin;
    185	struct clk			*core;
    186	const struct meson_ao_cec_g12a_data *data;
    187};
    188
    189static const struct regmap_config meson_ao_cec_g12a_regmap_conf = {
    190	.reg_bits = 8,
    191	.val_bits = 32,
    192	.reg_stride = 4,
    193	.max_register = CECB_INTR_STAT_REG,
    194};
    195
    196/*
    197 * The AO-CECB embeds a dual/divider to generate a more precise
    198 * 32,768KHz clock for CEC core clock.
    199 *                      ______   ______
    200 *                     |      | |      |
    201 *         ______      | Div1 |-| Cnt1 |       ______
    202 *        |      |    /|______| |______|\     |      |
    203 * Xtal-->| Gate |---|  ______   ______  X-X--| Gate |-->
    204 *        |______| |  \|      | |      |/  |  |______|
    205 *                 |   | Div2 |-| Cnt2 |   |
    206 *                 |   |______| |______|   |
    207 *                 |_______________________|
    208 *
    209 * The dividing can be switched to single or dual, with a counter
    210 * for each divider to set when the switching is done.
    211 * The entire dividing mechanism can be also bypassed.
    212 */
    213
    214struct meson_ao_cec_g12a_dualdiv_clk {
    215	struct clk_hw hw;
    216	struct regmap *regmap;
    217};
    218
    219#define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw)			\
    220	container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw)	\
    221
    222static unsigned long
    223meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw *hw,
    224					  unsigned long parent_rate)
    225{
    226	struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
    227		hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
    228	unsigned long n1;
    229	u32 reg0, reg1;
    230
    231	regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &reg0);
    232	regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &reg1);
    233
    234	if (reg1 & CECB_CLK_CNTL_BYPASS_EN)
    235		return parent_rate;
    236
    237	if (reg0 & CECB_CLK_CNTL_DUAL_EN) {
    238		unsigned long n2, m1, m2, f1, f2, p1, p2;
    239
    240		n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1;
    241		n2 = FIELD_GET(CECB_CLK_CNTL_N2, reg0) + 1;
    242
    243		m1 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1;
    244		m2 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1;
    245
    246		f1 = DIV_ROUND_CLOSEST(parent_rate, n1);
    247		f2 = DIV_ROUND_CLOSEST(parent_rate, n2);
    248
    249		p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2));
    250		p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2));
    251
    252		return DIV_ROUND_UP(100000000, p1 + p2);
    253	}
    254
    255	n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1;
    256
    257	return DIV_ROUND_CLOSEST(parent_rate, n1);
    258}
    259
    260static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw *hw)
    261{
    262	struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
    263		hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
    264
    265
    266	/* Disable Input & Output */
    267	regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
    268			   CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
    269			   0);
    270
    271	/* Set N1 & N2 */
    272	regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
    273			   CECB_CLK_CNTL_N1,
    274			   FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1));
    275
    276	regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
    277			   CECB_CLK_CNTL_N2,
    278			   FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1));
    279
    280	/* Set M1 & M2 */
    281	regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
    282			   CECB_CLK_CNTL_M1,
    283			   FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1));
    284
    285	regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
    286			   CECB_CLK_CNTL_M2,
    287			   FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1));
    288
    289	/* Enable Dual divisor */
    290	regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
    291			   CECB_CLK_CNTL_DUAL_EN, CECB_CLK_CNTL_DUAL_EN);
    292
    293	/* Disable divisor bypass */
    294	regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
    295			   CECB_CLK_CNTL_BYPASS_EN, 0);
    296
    297	/* Enable Input & Output */
    298	regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
    299			   CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
    300			   CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN);
    301
    302	return 0;
    303}
    304
    305static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw *hw)
    306{
    307	struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
    308		hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
    309
    310	regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
    311			   CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
    312			   0);
    313}
    314
    315static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw *hw)
    316{
    317	struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
    318		hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
    319	int val;
    320
    321	regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val);
    322
    323	return !!(val & (CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN));
    324}
    325
    326static const struct clk_ops meson_ao_cec_g12a_dualdiv_clk_ops = {
    327	.recalc_rate	= meson_ao_cec_g12a_dualdiv_clk_recalc_rate,
    328	.is_enabled	= meson_ao_cec_g12a_dualdiv_clk_is_enabled,
    329	.enable		= meson_ao_cec_g12a_dualdiv_clk_enable,
    330	.disable	= meson_ao_cec_g12a_dualdiv_clk_disable,
    331};
    332
    333static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device *ao_cec)
    334{
    335	struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk;
    336	struct device *dev = &ao_cec->pdev->dev;
    337	struct clk_init_data init;
    338	const char *parent_name;
    339	struct clk *clk;
    340	char *name;
    341
    342	dualdiv_clk = devm_kzalloc(dev, sizeof(*dualdiv_clk), GFP_KERNEL);
    343	if (!dualdiv_clk)
    344		return -ENOMEM;
    345
    346	name = kasprintf(GFP_KERNEL, "%s#dualdiv_clk", dev_name(dev));
    347	if (!name)
    348		return -ENOMEM;
    349
    350	parent_name = __clk_get_name(ao_cec->oscin);
    351
    352	init.name = name;
    353	init.ops = &meson_ao_cec_g12a_dualdiv_clk_ops;
    354	init.flags = 0;
    355	init.parent_names = &parent_name;
    356	init.num_parents = 1;
    357	dualdiv_clk->regmap = ao_cec->regmap;
    358	dualdiv_clk->hw.init = &init;
    359
    360	clk = devm_clk_register(dev, &dualdiv_clk->hw);
    361	kfree(name);
    362	if (IS_ERR(clk)) {
    363		dev_err(dev, "failed to register clock\n");
    364		return PTR_ERR(clk);
    365	}
    366
    367	ao_cec->core = clk;
    368
    369	return 0;
    370}
    371
    372static int meson_ao_cec_g12a_read(void *context, unsigned int addr,
    373				  unsigned int *data)
    374{
    375	struct meson_ao_cec_g12a_device *ao_cec = context;
    376	u32 reg = FIELD_PREP(CECB_RW_ADDR, addr);
    377	int ret = 0;
    378
    379	ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
    380	if (ret)
    381		return ret;
    382
    383	ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg,
    384				       !(reg & CECB_RW_BUS_BUSY),
    385				       5, 1000);
    386	if (ret)
    387		return ret;
    388
    389	ret = regmap_read(ao_cec->regmap, CECB_RW_REG, &reg);
    390
    391	*data = FIELD_GET(CECB_RW_RD_DATA, reg);
    392
    393	return ret;
    394}
    395
    396static int meson_ao_cec_g12a_write(void *context, unsigned int addr,
    397				   unsigned int data)
    398{
    399	struct meson_ao_cec_g12a_device *ao_cec = context;
    400	u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) |
    401		  FIELD_PREP(CECB_RW_WR_DATA, data) |
    402		  CECB_RW_WRITE_EN;
    403
    404	return regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
    405}
    406
    407static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = {
    408	.reg_bits = 8,
    409	.val_bits = 8,
    410	.reg_read = meson_ao_cec_g12a_read,
    411	.reg_write = meson_ao_cec_g12a_write,
    412	.max_register = 0xffff,
    413};
    414
    415static inline void
    416meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec,
    417			    bool enable)
    418{
    419	u32 cfg = CECB_INTR_DONE | CECB_INTR_EOM | CECB_INTR_NACK |
    420		  CECB_INTR_ARB_LOSS | CECB_INTR_INITIATOR_ERR |
    421		  CECB_INTR_FOLLOWER_ERR;
    422
    423	regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG,
    424		     enable ? cfg : 0);
    425}
    426
    427static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec)
    428{
    429	int i, ret = 0;
    430	u32 val;
    431
    432	ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val);
    433
    434	ao_cec->rx_msg.len = val;
    435	if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE)
    436		ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE;
    437
    438	for (i = 0; i < ao_cec->rx_msg.len; i++) {
    439		ret |= regmap_read(ao_cec->regmap_cec,
    440				   CECB_RX_DATA00 + i, &val);
    441
    442		ao_cec->rx_msg.msg[i] = val & 0xff;
    443	}
    444
    445	ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0);
    446	if (ret)
    447		return;
    448
    449	cec_received_msg(ao_cec->adap, &ao_cec->rx_msg);
    450}
    451
    452static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data)
    453{
    454	struct meson_ao_cec_g12a_device *ao_cec = data;
    455	u32 stat;
    456
    457	regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat);
    458	if (stat)
    459		return IRQ_WAKE_THREAD;
    460
    461	return IRQ_NONE;
    462}
    463
    464static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data)
    465{
    466	struct meson_ao_cec_g12a_device *ao_cec = data;
    467	u32 stat;
    468
    469	regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat);
    470	regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat);
    471
    472	if (stat & CECB_INTR_DONE)
    473		cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK);
    474
    475	if (stat & CECB_INTR_EOM)
    476		meson_ao_cec_g12a_irq_rx(ao_cec);
    477
    478	if (stat & CECB_INTR_NACK)
    479		cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK);
    480
    481	if (stat & CECB_INTR_ARB_LOSS) {
    482		regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0);
    483		regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL,
    484				   CECB_CTRL_SEND | CECB_CTRL_TYPE, 0);
    485		cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST);
    486	}
    487
    488	/* Initiator reports an error on the CEC bus */
    489	if (stat & CECB_INTR_INITIATOR_ERR)
    490		cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR);
    491
    492	/* Follower reports a receive error, just reset RX buffer */
    493	if (stat & CECB_INTR_FOLLOWER_ERR)
    494		regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0);
    495
    496	return IRQ_HANDLED;
    497}
    498
    499static int
    500meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
    501{
    502	struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
    503	int ret = 0;
    504
    505	if (logical_addr == CEC_LOG_ADDR_INVALID) {
    506		/* Assume this will allways succeed */
    507		regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0);
    508		regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0);
    509
    510		return 0;
    511	} else if (logical_addr < 8) {
    512		ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW,
    513					 BIT(logical_addr),
    514					 BIT(logical_addr));
    515	} else {
    516		ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH,
    517					 BIT(logical_addr - 8),
    518					 BIT(logical_addr - 8));
    519	}
    520
    521	/* Always set Broadcast/Unregistered 15 address */
    522	ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH,
    523				  BIT(CEC_LOG_ADDR_UNREGISTERED - 8),
    524				  BIT(CEC_LOG_ADDR_UNREGISTERED - 8));
    525
    526	return ret ? -EIO : 0;
    527}
    528
    529static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts,
    530				 u32 signal_free_time, struct cec_msg *msg)
    531{
    532	struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
    533	unsigned int type;
    534	int ret = 0;
    535	u32 val;
    536	int i;
    537
    538	/* Check if RX is in progress */
    539	ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val);
    540	if (ret)
    541		return ret;
    542	if (val & CECB_LOCK_BUF_EN)
    543		return -EBUSY;
    544
    545	/* Check if TX Busy */
    546	ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val);
    547	if (ret)
    548		return ret;
    549	if (val & CECB_CTRL_SEND)
    550		return -EBUSY;
    551
    552	switch (signal_free_time) {
    553	case CEC_SIGNAL_FREE_TIME_RETRY:
    554		type = CECB_CTRL_TYPE_RETRY;
    555		break;
    556	case CEC_SIGNAL_FREE_TIME_NEXT_XFER:
    557		type = CECB_CTRL_TYPE_NEXT;
    558		break;
    559	case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR:
    560	default:
    561		type = CECB_CTRL_TYPE_NEW;
    562		break;
    563	}
    564
    565	for (i = 0; i < msg->len; i++)
    566		ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i,
    567				    msg->msg[i]);
    568
    569	ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len);
    570	if (ret)
    571		return -EIO;
    572
    573	ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL,
    574				 CECB_CTRL_SEND |
    575				 CECB_CTRL_TYPE,
    576				 CECB_CTRL_SEND |
    577				 FIELD_PREP(CECB_CTRL_TYPE, type));
    578
    579	return ret;
    580}
    581
    582static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable)
    583{
    584	struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
    585
    586	meson_ao_cec_g12a_irq_setup(ao_cec, false);
    587
    588	regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
    589			   CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET);
    590
    591	if (!enable)
    592		return 0;
    593
    594	/* Setup Filter */
    595	regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
    596			   CECB_GEN_CNTL_FILTER_TICK_SEL |
    597			   CECB_GEN_CNTL_FILTER_DEL,
    598			   FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL,
    599				      CECB_GEN_CNTL_FILTER_TICK_1US) |
    600			   FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL, 7));
    601
    602	/* Enable System Clock */
    603	regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
    604			   CECB_GEN_CNTL_SYS_CLK_EN,
    605			   CECB_GEN_CNTL_SYS_CLK_EN);
    606
    607	/* Enable gated clock (Normal mode). */
    608	regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
    609			   CECB_GEN_CNTL_CLK_CTRL_MASK,
    610			    FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK,
    611				       CECB_GEN_CNTL_CLK_ENABLE));
    612
    613	/* Release Reset */
    614	regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
    615			   CECB_GEN_CNTL_RESET, 0);
    616
    617	if (ao_cec->data->ctrl2_setup)
    618		regmap_write(ao_cec->regmap_cec, CECB_CTRL2,
    619			     FIELD_PREP(CECB_CTRL2_RISE_DEL_MAX, 2));
    620
    621	meson_ao_cec_g12a_irq_setup(ao_cec, true);
    622
    623	return 0;
    624}
    625
    626static const struct cec_adap_ops meson_ao_cec_g12a_ops = {
    627	.adap_enable = meson_ao_cec_g12a_adap_enable,
    628	.adap_log_addr = meson_ao_cec_g12a_set_log_addr,
    629	.adap_transmit = meson_ao_cec_g12a_transmit,
    630};
    631
    632static int meson_ao_cec_g12a_probe(struct platform_device *pdev)
    633{
    634	struct meson_ao_cec_g12a_device *ao_cec;
    635	struct device *hdmi_dev;
    636	void __iomem *base;
    637	int ret, irq;
    638
    639	hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev);
    640	if (IS_ERR(hdmi_dev))
    641		return PTR_ERR(hdmi_dev);
    642
    643	ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL);
    644	if (!ao_cec)
    645		return -ENOMEM;
    646
    647	ao_cec->data = of_device_get_match_data(&pdev->dev);
    648	if (!ao_cec->data) {
    649		dev_err(&pdev->dev, "failed to get match data\n");
    650		return -ENODEV;
    651	}
    652
    653	spin_lock_init(&ao_cec->cec_reg_lock);
    654	ao_cec->pdev = pdev;
    655
    656	ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec,
    657					    "meson_g12a_ao_cec",
    658					    CEC_CAP_DEFAULTS |
    659					    CEC_CAP_CONNECTOR_INFO,
    660					    CEC_MAX_LOG_ADDRS);
    661	if (IS_ERR(ao_cec->adap))
    662		return PTR_ERR(ao_cec->adap);
    663
    664	ao_cec->adap->owner = THIS_MODULE;
    665
    666	base = devm_platform_ioremap_resource(pdev, 0);
    667	if (IS_ERR(base)) {
    668		ret = PTR_ERR(base);
    669		goto out_probe_adapter;
    670	}
    671
    672	ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
    673					       &meson_ao_cec_g12a_regmap_conf);
    674	if (IS_ERR(ao_cec->regmap)) {
    675		ret = PTR_ERR(ao_cec->regmap);
    676		goto out_probe_adapter;
    677	}
    678
    679	ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec,
    680					   &meson_ao_cec_g12a_cec_regmap_conf);
    681	if (IS_ERR(ao_cec->regmap_cec)) {
    682		ret = PTR_ERR(ao_cec->regmap_cec);
    683		goto out_probe_adapter;
    684	}
    685
    686	irq = platform_get_irq(pdev, 0);
    687	ret = devm_request_threaded_irq(&pdev->dev, irq,
    688					meson_ao_cec_g12a_irq,
    689					meson_ao_cec_g12a_irq_thread,
    690					0, NULL, ao_cec);
    691	if (ret) {
    692		dev_err(&pdev->dev, "irq request failed\n");
    693		goto out_probe_adapter;
    694	}
    695
    696	ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin");
    697	if (IS_ERR(ao_cec->oscin)) {
    698		dev_err(&pdev->dev, "oscin clock request failed\n");
    699		ret = PTR_ERR(ao_cec->oscin);
    700		goto out_probe_adapter;
    701	}
    702
    703	ret = meson_ao_cec_g12a_setup_clk(ao_cec);
    704	if (ret)
    705		goto out_probe_adapter;
    706
    707	ret = clk_prepare_enable(ao_cec->core);
    708	if (ret) {
    709		dev_err(&pdev->dev, "core clock enable failed\n");
    710		goto out_probe_adapter;
    711	}
    712
    713	device_reset_optional(&pdev->dev);
    714
    715	platform_set_drvdata(pdev, ao_cec);
    716
    717	ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL,
    718							ao_cec->adap);
    719	if (!ao_cec->notify) {
    720		ret = -ENOMEM;
    721		goto out_probe_core_clk;
    722	}
    723
    724	ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
    725	if (ret < 0)
    726		goto out_probe_notify;
    727
    728	/* Setup Hardware */
    729	regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET);
    730
    731	return 0;
    732
    733out_probe_notify:
    734	cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap);
    735
    736out_probe_core_clk:
    737	clk_disable_unprepare(ao_cec->core);
    738
    739out_probe_adapter:
    740	cec_delete_adapter(ao_cec->adap);
    741
    742	dev_err(&pdev->dev, "CEC controller registration failed\n");
    743
    744	return ret;
    745}
    746
    747static int meson_ao_cec_g12a_remove(struct platform_device *pdev)
    748{
    749	struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev);
    750
    751	clk_disable_unprepare(ao_cec->core);
    752
    753	cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap);
    754
    755	cec_unregister_adapter(ao_cec->adap);
    756
    757	return 0;
    758}
    759
    760static const struct meson_ao_cec_g12a_data ao_cec_g12a_data = {
    761	.ctrl2_setup = false,
    762};
    763
    764static const struct meson_ao_cec_g12a_data ao_cec_sm1_data = {
    765	.ctrl2_setup = true,
    766};
    767
    768static const struct of_device_id meson_ao_cec_g12a_of_match[] = {
    769	{
    770		.compatible = "amlogic,meson-g12a-ao-cec",
    771		.data = &ao_cec_g12a_data,
    772	},
    773	{
    774		.compatible = "amlogic,meson-sm1-ao-cec",
    775		.data = &ao_cec_sm1_data,
    776	},
    777	{ /* sentinel */ }
    778};
    779MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match);
    780
    781static struct platform_driver meson_ao_cec_g12a_driver = {
    782	.probe   = meson_ao_cec_g12a_probe,
    783	.remove  = meson_ao_cec_g12a_remove,
    784	.driver  = {
    785		.name = "meson-ao-cec-g12a",
    786		.of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match),
    787	},
    788};
    789
    790module_platform_driver(meson_ao_cec_g12a_driver);
    791
    792MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver");
    793MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
    794MODULE_LICENSE("GPL");