ext_caps.c (8881B)
1// SPDX-License-Identifier: BSD-3-Clause 2/* 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/device.h> 10#include <linux/errno.h> 11#include <linux/i3c/master.h> 12#include <linux/kernel.h> 13#include <linux/io.h> 14 15#include "hci.h" 16#include "ext_caps.h" 17#include "xfer_mode_rate.h" 18 19 20/* Extended Capability Header */ 21#define CAP_HEADER_LENGTH GENMASK(23, 8) 22#define CAP_HEADER_ID GENMASK(7, 0) 23 24static int hci_extcap_hardware_id(struct i3c_hci *hci, void __iomem *base) 25{ 26 hci->vendor_mipi_id = readl(base + 0x04); 27 hci->vendor_version_id = readl(base + 0x08); 28 hci->vendor_product_id = readl(base + 0x0c); 29 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); 33 34 /* ought to go in a table if this grows too much */ 35 switch (hci->vendor_mipi_id) { 36 case MIPI_VENDOR_NXP: 37 hci->quirks |= HCI_QUIRK_RAW_CCC; 38 DBG("raw CCC quirks set"); 39 break; 40 } 41 42 return 0; 43} 44 45static int hci_extcap_master_config(struct i3c_hci *hci, void __iomem *base) 46{ 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) 54 return 0; 55 dev_err(&hci->master.dev, "only master mode is currently supported\n"); 56 return -EOPNOTSUPP; 57} 58 59static int hci_extcap_multi_bus(struct i3c_hci *hci, void __iomem *base) 60{ 61 u32 bus_instance = readl(base + 0x04); 62 unsigned int count = FIELD_GET(GENMASK(3, 0), bus_instance); 63 64 dev_info(&hci->master.dev, "%d bus instances\n", count); 65 return 0; 66} 67 68static int hci_extcap_xfer_modes(struct i3c_hci *hci, void __iomem *base) 69{ 70 u32 header = readl(base); 71 u32 entries = FIELD_GET(CAP_HEADER_LENGTH, header) - 1; 72 unsigned int index; 73 74 dev_info(&hci->master.dev, "transfer mode table has %d entries\n", 75 entries); 76 base += 4; /* skip header */ 77 for (index = 0; index < entries; index++) { 78 u32 mode_entry = readl(base); 79 80 DBG("mode %d: 0x%08x", index, mode_entry); 81 /* TODO: will be needed when I3C core does more than SDR */ 82 base += 4; 83 } 84 85 return 0; 86} 87 88static int hci_extcap_xfer_rates(struct i3c_hci *hci, void __iomem *base) 89{ 90 u32 header = readl(base); 91 u32 entries = FIELD_GET(CAP_HEADER_LENGTH, header) - 1; 92 u32 rate_entry; 93 unsigned int index, rate, rate_id, mode_id; 94 95 base += 4; /* skip header */ 96 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", 105 rate_id, 106 mode_id == XFERRATE_MODE_I3C ? "I3C" : 107 mode_id == XFERRATE_MODE_I2C ? "I2C" : 108 "unknown mode", 109 rate); 110 base += 4; 111 } 112 113 return 0; 114} 115 116static int hci_extcap_auto_command(struct i3c_hci *hci, void __iomem *base) 117{ 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); 122 123 dev_info(&hci->master.dev, "%d/%d active auto-command entries\n", 124 count, max_count); 125 /* remember auto-command register location for later use */ 126 hci->AUTOCMD_regs = base; 127 return 0; 128} 129 130static int hci_extcap_debug(struct i3c_hci *hci, void __iomem *base) 131{ 132 dev_info(&hci->master.dev, "debug registers present\n"); 133 hci->DEBUG_regs = base; 134 return 0; 135} 136 137static int hci_extcap_scheduled_cmd(struct i3c_hci *hci, void __iomem *base) 138{ 139 dev_info(&hci->master.dev, "scheduled commands available\n"); 140 /* hci->schedcmd_regs = base; */ 141 return 0; 142} 143 144static int hci_extcap_non_curr_master(struct i3c_hci *hci, void __iomem *base) 145{ 146 dev_info(&hci->master.dev, "Non-Current Master support available\n"); 147 /* hci->NCM_regs = base; */ 148 return 0; 149} 150 151static int hci_extcap_ccc_resp_conf(struct i3c_hci *hci, void __iomem *base) 152{ 153 dev_info(&hci->master.dev, "CCC Response Configuration available\n"); 154 return 0; 155} 156 157static int hci_extcap_global_DAT(struct i3c_hci *hci, void __iomem *base) 158{ 159 dev_info(&hci->master.dev, "Global DAT available\n"); 160 return 0; 161} 162 163static int hci_extcap_multilane(struct i3c_hci *hci, void __iomem *base) 164{ 165 dev_info(&hci->master.dev, "Master Multi-Lane support available\n"); 166 return 0; 167} 168 169static int hci_extcap_ncm_multilane(struct i3c_hci *hci, void __iomem *base) 170{ 171 dev_info(&hci->master.dev, "NCM Multi-Lane support available\n"); 172 return 0; 173} 174 175struct hci_ext_caps { 176 u8 id; 177 u16 min_length; 178 int (*parser)(struct i3c_hci *hci, void __iomem *base); 179}; 180 181#define EXT_CAP(_id, _highest_mandatory_reg_offset, _parser) \ 182 { .id = (_id), .parser = (_parser), \ 183 .min_length = (_highest_mandatory_reg_offset)/4 + 1 } 184 185static 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), 199}; 200 201static int hci_extcap_vendor_NXP(struct i3c_hci *hci, void __iomem *base) 202{ 203 hci->vendor_data = (__force void *)base; 204 dev_info(&hci->master.dev, "Build Date Info = %#x\n", readl(base + 1*4)); 205 /* reset the FPGA */ 206 writel(0xdeadbeef, base + 1*4); 207 return 0; 208} 209 210struct hci_ext_cap_vendor_specific { 211 u32 vendor; 212 u8 cap; 213 u16 min_length; 214 int (*parser)(struct i3c_hci *hci, void __iomem *base); 215}; 216 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 } 221 222static const struct hci_ext_cap_vendor_specific vendor_ext_caps[] = { 223 EXT_CAP_VENDOR(NXP, 0xc0, 0x20), 224}; 225 226static int hci_extcap_vendor_specific(struct i3c_hci *hci, void __iomem *base, 227 u32 cap_id, u32 cap_length) 228{ 229 const struct hci_ext_cap_vendor_specific *vendor_cap_entry; 230 int i; 231 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]; 237 break; 238 } 239 } 240 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); 245 return 0; 246 } 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); 251 return -EINVAL; 252 } 253 return vendor_cap_entry->parser(hci, base); 254} 255 256int i3c_hci_parse_ext_caps(struct i3c_hci *hci) 257{ 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; 262 int i, err = 0; 263 264 if (!curr_cap) 265 return 0; 266 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); 272 if (!cap_length) 273 break; 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", 277 cap_id, cap_length); 278 err = -EINVAL; 279 break; 280 } 281 282 if (cap_id >= 0xc0 && cap_id <= 0xcf) { 283 err = hci_extcap_vendor_specific(hci, curr_cap, 284 cap_id, cap_length); 285 continue; 286 } 287 288 cap_entry = NULL; 289 for (i = 0; i < ARRAY_SIZE(ext_capabilities); i++) { 290 if (ext_capabilities[i].id == cap_id) { 291 cap_entry = &ext_capabilities[i]; 292 break; 293 } 294 } 295 if (!cap_entry) { 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); 302 err = -EINVAL; 303 } else { 304 err = cap_entry->parser(hci, curr_cap); 305 } 306 } 307 return err; 308}