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/device.h>
10 #include <linux/errno.h>
11 #include <linux/i3c/master.h>
12 #include <linux/kernel.h>
17 #include "xfer_mode_rate.h"
20 /* Extended Capability Header */
21 #define CAP_HEADER_LENGTH GENMASK(23, 8)
22 #define CAP_HEADER_ID GENMASK(7, 0)
24 static int hci_extcap_hardware_id(struct i3c_hci
*hci
, void __iomem
*base
)
26 hci
->vendor_mipi_id
= readl(base
+ 0x04);
27 hci
->vendor_version_id
= readl(base
+ 0x08);
28 hci
->vendor_product_id
= readl(base
+ 0x0c);
30 dev_info(&hci
->master
.dev
, "vendor MIPI ID: %#x\n", hci
->vendor_mipi_id
);
31 dev_info(&hci
->master
.dev
, "vendor version ID: %#x\n", hci
->vendor_version_id
);
32 dev_info(&hci
->master
.dev
, "vendor product ID: %#x\n", hci
->vendor_product_id
);
34 /* ought to go in a table if this grows too much */
35 switch (hci
->vendor_mipi_id
) {
37 hci
->quirks
|= HCI_QUIRK_RAW_CCC
;
38 DBG("raw CCC quirks set");
45 static int hci_extcap_master_config(struct i3c_hci
*hci
, void __iomem
*base
)
47 u32 master_config
= readl(base
+ 0x04);
48 unsigned int operation_mode
= FIELD_GET(GENMASK(5, 4), master_config
);
49 static const char * const functionality
[] = {
50 "(unknown)", "master only", "target only",
51 "primary/secondary master" };
52 dev_info(&hci
->master
.dev
, "operation mode: %s\n", functionality
[operation_mode
]);
53 if (operation_mode
& 0x1)
55 dev_err(&hci
->master
.dev
, "only master mode is currently supported\n");
59 static int hci_extcap_multi_bus(struct i3c_hci
*hci
, void __iomem
*base
)
61 u32 bus_instance
= readl(base
+ 0x04);
62 unsigned int count
= FIELD_GET(GENMASK(3, 0), bus_instance
);
64 dev_info(&hci
->master
.dev
, "%d bus instances\n", count
);
68 static int hci_extcap_xfer_modes(struct i3c_hci
*hci
, void __iomem
*base
)
70 u32 header
= readl(base
);
71 u32 entries
= FIELD_GET(CAP_HEADER_LENGTH
, header
) - 1;
74 dev_info(&hci
->master
.dev
, "transfer mode table has %d entries\n",
76 base
+= 4; /* skip header */
77 for (index
= 0; index
< entries
; index
++) {
78 u32 mode_entry
= readl(base
);
80 DBG("mode %d: 0x%08x", index
, mode_entry
);
81 /* TODO: will be needed when I3C core does more than SDR */
88 static int hci_extcap_xfer_rates(struct i3c_hci
*hci
, void __iomem
*base
)
90 u32 header
= readl(base
);
91 u32 entries
= FIELD_GET(CAP_HEADER_LENGTH
, header
) - 1;
93 unsigned int index
, rate
, rate_id
, mode_id
;
95 base
+= 4; /* skip header */
97 dev_info(&hci
->master
.dev
, "available data rates:\n");
98 for (index
= 0; index
< entries
; index
++) {
99 rate_entry
= readl(base
);
100 DBG("entry %d: 0x%08x", index
, rate_entry
);
101 rate
= FIELD_GET(XFERRATE_ACTUAL_RATE_KHZ
, rate_entry
);
102 rate_id
= FIELD_GET(XFERRATE_RATE_ID
, rate_entry
);
103 mode_id
= FIELD_GET(XFERRATE_MODE_ID
, rate_entry
);
104 dev_info(&hci
->master
.dev
, "rate %d for %s = %d kHz\n",
106 mode_id
== XFERRATE_MODE_I3C
? "I3C" :
107 mode_id
== XFERRATE_MODE_I2C
? "I2C" :
116 static int hci_extcap_auto_command(struct i3c_hci
*hci
, void __iomem
*base
)
118 u32 autocmd_ext_caps
= readl(base
+ 0x04);
119 unsigned int max_count
= FIELD_GET(GENMASK(3, 0), autocmd_ext_caps
);
120 u32 autocmd_ext_config
= readl(base
+ 0x08);
121 unsigned int count
= FIELD_GET(GENMASK(3, 0), autocmd_ext_config
);
123 dev_info(&hci
->master
.dev
, "%d/%d active auto-command entries\n",
125 /* remember auto-command register location for later use */
126 hci
->AUTOCMD_regs
= base
;
130 static int hci_extcap_debug(struct i3c_hci
*hci
, void __iomem
*base
)
132 dev_info(&hci
->master
.dev
, "debug registers present\n");
133 hci
->DEBUG_regs
= base
;
137 static int hci_extcap_scheduled_cmd(struct i3c_hci
*hci
, void __iomem
*base
)
139 dev_info(&hci
->master
.dev
, "scheduled commands available\n");
140 /* hci->schedcmd_regs = base; */
144 static int hci_extcap_non_curr_master(struct i3c_hci
*hci
, void __iomem
*base
)
146 dev_info(&hci
->master
.dev
, "Non-Current Master support available\n");
147 /* hci->NCM_regs = base; */
151 static int hci_extcap_ccc_resp_conf(struct i3c_hci
*hci
, void __iomem
*base
)
153 dev_info(&hci
->master
.dev
, "CCC Response Configuration available\n");
157 static int hci_extcap_global_DAT(struct i3c_hci
*hci
, void __iomem
*base
)
159 dev_info(&hci
->master
.dev
, "Global DAT available\n");
163 static int hci_extcap_multilane(struct i3c_hci
*hci
, void __iomem
*base
)
165 dev_info(&hci
->master
.dev
, "Master Multi-Lane support available\n");
169 static int hci_extcap_ncm_multilane(struct i3c_hci
*hci
, void __iomem
*base
)
171 dev_info(&hci
->master
.dev
, "NCM Multi-Lane support available\n");
175 struct hci_ext_caps
{
178 int (*parser
)(struct i3c_hci
*hci
, void __iomem
*base
);
181 #define EXT_CAP(_id, _highest_mandatory_reg_offset, _parser) \
182 { .id = (_id), .parser = (_parser), \
183 .min_length = (_highest_mandatory_reg_offset)/4 + 1 }
185 static const struct hci_ext_caps ext_capabilities
[] = {
186 EXT_CAP(0x01, 0x0c, hci_extcap_hardware_id
),
187 EXT_CAP(0x02, 0x04, hci_extcap_master_config
),
188 EXT_CAP(0x03, 0x04, hci_extcap_multi_bus
),
189 EXT_CAP(0x04, 0x24, hci_extcap_xfer_modes
),
190 EXT_CAP(0x05, 0x08, hci_extcap_auto_command
),
191 EXT_CAP(0x08, 0x40, hci_extcap_xfer_rates
),
192 EXT_CAP(0x0c, 0x10, hci_extcap_debug
),
193 EXT_CAP(0x0d, 0x0c, hci_extcap_scheduled_cmd
),
194 EXT_CAP(0x0e, 0x80, hci_extcap_non_curr_master
), /* TODO confirm size */
195 EXT_CAP(0x0f, 0x04, hci_extcap_ccc_resp_conf
),
196 EXT_CAP(0x10, 0x08, hci_extcap_global_DAT
),
197 EXT_CAP(0x9d, 0x04, hci_extcap_multilane
),
198 EXT_CAP(0x9e, 0x04, hci_extcap_ncm_multilane
),
201 static int hci_extcap_vendor_NXP(struct i3c_hci
*hci
, void __iomem
*base
)
203 hci
->vendor_data
= (__force
void *)base
;
204 dev_info(&hci
->master
.dev
, "Build Date Info = %#x\n", readl(base
+ 1*4));
206 writel(0xdeadbeef, base
+ 1*4);
210 struct hci_ext_cap_vendor_specific
{
214 int (*parser
)(struct i3c_hci
*hci
, void __iomem
*base
);
217 #define EXT_CAP_VENDOR(_vendor, _cap, _highest_mandatory_reg_offset) \
218 { .vendor = (MIPI_VENDOR_##_vendor), .cap = (_cap), \
219 .parser = (hci_extcap_vendor_##_vendor), \
220 .min_length = (_highest_mandatory_reg_offset)/4 + 1 }
222 static const struct hci_ext_cap_vendor_specific vendor_ext_caps
[] = {
223 EXT_CAP_VENDOR(NXP
, 0xc0, 0x20),
226 static int hci_extcap_vendor_specific(struct i3c_hci
*hci
, void __iomem
*base
,
227 u32 cap_id
, u32 cap_length
)
229 const struct hci_ext_cap_vendor_specific
*vendor_cap_entry
;
232 vendor_cap_entry
= NULL
;
233 for (i
= 0; i
< ARRAY_SIZE(vendor_ext_caps
); i
++) {
234 if (vendor_ext_caps
[i
].vendor
== hci
->vendor_mipi_id
&&
235 vendor_ext_caps
[i
].cap
== cap_id
) {
236 vendor_cap_entry
= &vendor_ext_caps
[i
];
241 if (!vendor_cap_entry
) {
242 dev_notice(&hci
->master
.dev
,
243 "unknown ext_cap 0x%02x for vendor 0x%02x\n",
244 cap_id
, hci
->vendor_mipi_id
);
247 if (cap_length
< vendor_cap_entry
->min_length
) {
248 dev_err(&hci
->master
.dev
,
249 "ext_cap 0x%02x has size %d (expecting >= %d)\n",
250 cap_id
, cap_length
, vendor_cap_entry
->min_length
);
253 return vendor_cap_entry
->parser(hci
, base
);
256 int i3c_hci_parse_ext_caps(struct i3c_hci
*hci
)
258 void __iomem
*curr_cap
= hci
->EXTCAPS_regs
;
259 void __iomem
*end
= curr_cap
+ 0x1000; /* some arbitrary limit */
260 u32 cap_header
, cap_id
, cap_length
;
261 const struct hci_ext_caps
*cap_entry
;
267 for (; !err
&& curr_cap
< end
; curr_cap
+= cap_length
* 4) {
268 cap_header
= readl(curr_cap
);
269 cap_id
= FIELD_GET(CAP_HEADER_ID
, cap_header
);
270 cap_length
= FIELD_GET(CAP_HEADER_LENGTH
, cap_header
);
271 DBG("id=0x%02x length=%d", cap_id
, cap_length
);
274 if (curr_cap
+ cap_length
* 4 >= end
) {
275 dev_err(&hci
->master
.dev
,
276 "ext_cap 0x%02x has size %d (too big)\n",
282 if (cap_id
>= 0xc0 && cap_id
<= 0xcf) {
283 err
= hci_extcap_vendor_specific(hci
, curr_cap
,
289 for (i
= 0; i
< ARRAY_SIZE(ext_capabilities
); i
++) {
290 if (ext_capabilities
[i
].id
== cap_id
) {
291 cap_entry
= &ext_capabilities
[i
];
296 dev_notice(&hci
->master
.dev
,
297 "unknown ext_cap 0x%02x\n", cap_id
);
298 } else if (cap_length
< cap_entry
->min_length
) {
299 dev_err(&hci
->master
.dev
,
300 "ext_cap 0x%02x has size %d (expecting >= %d)\n",
301 cap_id
, cap_length
, cap_entry
->min_length
);
304 err
= cap_entry
->parser(hci
, curr_cap
);