brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · 47b9b4d Raw
192 lines · c
1// SPDX-License-Identifier: BSD-3-Clause2/*3 * Copyright (c) 2020, MIPI Alliance, Inc.4 *5 * Author: Nicolas Pitre <npitre@baylibre.com>6 */7 8#include <linux/bitfield.h>9#include <linux/bitmap.h>10#include <linux/device.h>11#include <linux/errno.h>12#include <linux/i3c/master.h>13#include <linux/io.h>14 15#include "hci.h"16#include "dat.h"17 18 19/*20 * Device Address Table Structure21 */22 23#define DAT_1_AUTOCMD_HDR_CODE		W1_MASK(58, 51)24#define DAT_1_AUTOCMD_MODE		W1_MASK(50, 48)25#define DAT_1_AUTOCMD_VALUE		W1_MASK(47, 40)26#define DAT_1_AUTOCMD_MASK		W1_MASK(39, 32)27/*	DAT_0_I2C_DEVICE		W0_BIT_(31) */28#define DAT_0_DEV_NACK_RETRY_CNT	W0_MASK(30, 29)29#define DAT_0_RING_ID			W0_MASK(28, 26)30#define DAT_0_DYNADDR_PARITY		W0_BIT_(23)31#define DAT_0_DYNAMIC_ADDRESS		W0_MASK(22, 16)32#define DAT_0_TS			W0_BIT_(15)33#define DAT_0_MR_REJECT			W0_BIT_(14)34/*	DAT_0_SIR_REJECT		W0_BIT_(13) */35/*	DAT_0_IBI_PAYLOAD		W0_BIT_(12) */36#define DAT_0_STATIC_ADDRESS		W0_MASK(6, 0)37 38#define dat_w0_read(i)		readl(hci->DAT_regs + (i) * 8)39#define dat_w1_read(i)		readl(hci->DAT_regs + (i) * 8 + 4)40#define dat_w0_write(i, v)	writel(v, hci->DAT_regs + (i) * 8)41#define dat_w1_write(i, v)	writel(v, hci->DAT_regs + (i) * 8 + 4)42 43static inline bool dynaddr_parity(unsigned int addr)44{45	addr |= 1 << 7;46	addr += addr >> 4;47	addr += addr >> 2;48	addr += addr >> 1;49	return (addr & 1);50}51 52static int hci_dat_v1_init(struct i3c_hci *hci)53{54	unsigned int dat_idx;55 56	if (!hci->DAT_regs) {57		dev_err(&hci->master.dev,58			"only DAT in register space is supported at the moment\n");59		return -EOPNOTSUPP;60	}61	if (hci->DAT_entry_size != 8) {62		dev_err(&hci->master.dev,63			"only 8-bytes DAT entries are supported at the moment\n");64		return -EOPNOTSUPP;65	}66 67	if (!hci->DAT_data) {68		/* use a bitmap for faster free slot search */69		hci->DAT_data = bitmap_zalloc(hci->DAT_entries, GFP_KERNEL);70		if (!hci->DAT_data)71			return -ENOMEM;72 73		/* clear them */74		for (dat_idx = 0; dat_idx < hci->DAT_entries; dat_idx++) {75			dat_w0_write(dat_idx, 0);76			dat_w1_write(dat_idx, 0);77		}78	}79 80	return 0;81}82 83static void hci_dat_v1_cleanup(struct i3c_hci *hci)84{85	bitmap_free(hci->DAT_data);86	hci->DAT_data = NULL;87}88 89static int hci_dat_v1_alloc_entry(struct i3c_hci *hci)90{91	unsigned int dat_idx;92	int ret;93 94	if (!hci->DAT_data) {95		ret = hci_dat_v1_init(hci);96		if (ret)97			return ret;98	}99	dat_idx = find_first_zero_bit(hci->DAT_data, hci->DAT_entries);100	if (dat_idx >= hci->DAT_entries)101		return -ENOENT;102	__set_bit(dat_idx, hci->DAT_data);103 104	/* default flags */105	dat_w0_write(dat_idx, DAT_0_SIR_REJECT | DAT_0_MR_REJECT);106 107	return dat_idx;108}109 110static void hci_dat_v1_free_entry(struct i3c_hci *hci, unsigned int dat_idx)111{112	dat_w0_write(dat_idx, 0);113	dat_w1_write(dat_idx, 0);114	if (hci->DAT_data)115		__clear_bit(dat_idx, hci->DAT_data);116}117 118static void hci_dat_v1_set_dynamic_addr(struct i3c_hci *hci,119					unsigned int dat_idx, u8 address)120{121	u32 dat_w0;122 123	dat_w0 = dat_w0_read(dat_idx);124	dat_w0 &= ~(DAT_0_DYNAMIC_ADDRESS | DAT_0_DYNADDR_PARITY);125	dat_w0 |= FIELD_PREP(DAT_0_DYNAMIC_ADDRESS, address) |126		  (dynaddr_parity(address) ? DAT_0_DYNADDR_PARITY : 0);127	dat_w0_write(dat_idx, dat_w0);128}129 130static void hci_dat_v1_set_static_addr(struct i3c_hci *hci,131				       unsigned int dat_idx, u8 address)132{133	u32 dat_w0;134 135	dat_w0 = dat_w0_read(dat_idx);136	dat_w0 &= ~DAT_0_STATIC_ADDRESS;137	dat_w0 |= FIELD_PREP(DAT_0_STATIC_ADDRESS, address);138	dat_w0_write(dat_idx, dat_w0);139}140 141static void hci_dat_v1_set_flags(struct i3c_hci *hci, unsigned int dat_idx,142				 u32 w0_flags, u32 w1_flags)143{144	u32 dat_w0, dat_w1;145 146	dat_w0 = dat_w0_read(dat_idx);147	dat_w1 = dat_w1_read(dat_idx);148	dat_w0 |= w0_flags;149	dat_w1 |= w1_flags;150	dat_w0_write(dat_idx, dat_w0);151	dat_w1_write(dat_idx, dat_w1);152}153 154static void hci_dat_v1_clear_flags(struct i3c_hci *hci, unsigned int dat_idx,155				   u32 w0_flags, u32 w1_flags)156{157	u32 dat_w0, dat_w1;158 159	dat_w0 = dat_w0_read(dat_idx);160	dat_w1 = dat_w1_read(dat_idx);161	dat_w0 &= ~w0_flags;162	dat_w1 &= ~w1_flags;163	dat_w0_write(dat_idx, dat_w0);164	dat_w1_write(dat_idx, dat_w1);165}166 167static int hci_dat_v1_get_index(struct i3c_hci *hci, u8 dev_addr)168{169	unsigned int dat_idx;170	u32 dat_w0;171 172	for_each_set_bit(dat_idx, hci->DAT_data, hci->DAT_entries) {173		dat_w0 = dat_w0_read(dat_idx);174		if (FIELD_GET(DAT_0_DYNAMIC_ADDRESS, dat_w0) == dev_addr)175			return dat_idx;176	}177 178	return -ENODEV;179}180 181const struct hci_dat_ops mipi_i3c_hci_dat_v1 = {182	.init			= hci_dat_v1_init,183	.cleanup		= hci_dat_v1_cleanup,184	.alloc_entry		= hci_dat_v1_alloc_entry,185	.free_entry		= hci_dat_v1_free_entry,186	.set_dynamic_addr	= hci_dat_v1_set_dynamic_addr,187	.set_static_addr	= hci_dat_v1_set_static_addr,188	.set_flags		= hci_dat_v1_set_flags,189	.clear_flags		= hci_dat_v1_clear_flags,190	.get_index		= hci_dat_v1_get_index,191};192