Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / i3c / master / mipi-i3c-hci / dat_v1.c
blob47b9b4d4ed3fc0ff5e05ed4d4d2d5b28ae246ded
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3 * Copyright (c) 2020, MIPI Alliance, Inc.
5 * Author: Nicolas Pitre <npitre@baylibre.com>
6 */
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>
15 #include "hci.h"
16 #include "dat.h"
20 * Device Address Table Structure
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)
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)
43 static inline bool dynaddr_parity(unsigned int addr)
45 addr |= 1 << 7;
46 addr += addr >> 4;
47 addr += addr >> 2;
48 addr += addr >> 1;
49 return (addr & 1);
52 static int hci_dat_v1_init(struct i3c_hci *hci)
54 unsigned int dat_idx;
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;
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;
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;
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);
80 return 0;
83 static void hci_dat_v1_cleanup(struct i3c_hci *hci)
85 bitmap_free(hci->DAT_data);
86 hci->DAT_data = NULL;
89 static int hci_dat_v1_alloc_entry(struct i3c_hci *hci)
91 unsigned int dat_idx;
92 int ret;
94 if (!hci->DAT_data) {
95 ret = hci_dat_v1_init(hci);
96 if (ret)
97 return ret;
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);
104 /* default flags */
105 dat_w0_write(dat_idx, DAT_0_SIR_REJECT | DAT_0_MR_REJECT);
107 return dat_idx;
110 static void hci_dat_v1_free_entry(struct i3c_hci *hci, unsigned int dat_idx)
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);
118 static void hci_dat_v1_set_dynamic_addr(struct i3c_hci *hci,
119 unsigned int dat_idx, u8 address)
121 u32 dat_w0;
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);
130 static void hci_dat_v1_set_static_addr(struct i3c_hci *hci,
131 unsigned int dat_idx, u8 address)
133 u32 dat_w0;
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);
141 static void hci_dat_v1_set_flags(struct i3c_hci *hci, unsigned int dat_idx,
142 u32 w0_flags, u32 w1_flags)
144 u32 dat_w0, dat_w1;
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);
154 static void hci_dat_v1_clear_flags(struct i3c_hci *hci, unsigned int dat_idx,
155 u32 w0_flags, u32 w1_flags)
157 u32 dat_w0, dat_w1;
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);
167 static int hci_dat_v1_get_index(struct i3c_hci *hci, u8 dev_addr)
169 unsigned int dat_idx;
170 u32 dat_w0;
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;
178 return -ENODEV;
181 const 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,