1 // SPDX-License-Identifier: BSD-3-Clause
3 * Copyright (c) 2020, MIPI Alliance, Inc.
5 * Author: Nicolas Pitre <npitre@baylibre.com>
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>
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
)
52 static int hci_dat_v1_init(struct i3c_hci
*hci
)
57 dev_err(&hci
->master
.dev
,
58 "only DAT in register space is supported at the moment\n");
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");
68 /* use a bitmap for faster free slot search */
69 hci
->DAT_data
= bitmap_zalloc(hci
->DAT_entries
, GFP_KERNEL
);
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);
83 static void hci_dat_v1_cleanup(struct i3c_hci
*hci
)
85 bitmap_free(hci
->DAT_data
);
89 static int hci_dat_v1_alloc_entry(struct i3c_hci
*hci
)
95 ret
= hci_dat_v1_init(hci
);
99 dat_idx
= find_first_zero_bit(hci
->DAT_data
, hci
->DAT_entries
);
100 if (dat_idx
>= hci
->DAT_entries
)
102 __set_bit(dat_idx
, hci
->DAT_data
);
105 dat_w0_write(dat_idx
, DAT_0_SIR_REJECT
| DAT_0_MR_REJECT
);
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);
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
)
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
)
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
)
146 dat_w0
= dat_w0_read(dat_idx
);
147 dat_w1
= dat_w1_read(dat_idx
);
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
)
159 dat_w0
= dat_w0_read(dat_idx
);
160 dat_w1
= dat_w1_read(dat_idx
);
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
;
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
)
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
,