FILE
dat_v1.c
File preview with syntax highlighting.
linux-6.19.14/drivers/i3c/master/mipi-i3c-hci/dat_v1.c
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/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 Structure 21 */ 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 int hci_dat_v1_init(struct i3c_hci *hci) 44{ 45 unsigned int dat_idx; 46 47 if (!hci->DAT_regs) { 48 dev_err(&hci->master.dev, 49 "only DAT in register space is supported at the moment\n"); 50 return -EOPNOTSUPP; 51 } 52 if (hci->DAT_entry_size != 8) { 53 dev_err(&hci->master.dev, 54 "only 8-bytes DAT entries are supported at the moment\n"); 55 return -EOPNOTSUPP; 56 } 57 58 if (!hci->DAT_data) { 59 /* use a bitmap for faster free slot search */ 60 hci->DAT_data = bitmap_zalloc(hci->DAT_entries, GFP_KERNEL); 61 if (!hci->DAT_data) 62 return -ENOMEM; 63 64 /* clear them */ 65 for (dat_idx = 0; dat_idx < hci->DAT_entries; dat_idx++) { 66 dat_w0_write(dat_idx, 0); 67 dat_w1_write(dat_idx, 0); 68 } 69 } 70 71 return 0; 72} 73 74static void hci_dat_v1_cleanup(struct i3c_hci *hci) 75{ 76 bitmap_free(hci->DAT_data); 77 hci->DAT_data = NULL; 78} 79 80static int hci_dat_v1_alloc_entry(struct i3c_hci *hci) 81{ 82 unsigned int dat_idx; 83 int ret; 84 85 if (!hci->DAT_data) { 86 ret = hci_dat_v1_init(hci); 87 if (ret) 88 return ret; 89 } 90 dat_idx = find_first_zero_bit(hci->DAT_data, hci->DAT_entries); 91 if (dat_idx >= hci->DAT_entries) 92 return -ENOENT; 93 __set_bit(dat_idx, hci->DAT_data); 94 95 /* default flags */ 96 dat_w0_write(dat_idx, DAT_0_SIR_REJECT | DAT_0_MR_REJECT); 97 98 return dat_idx; 99} 100 101static void hci_dat_v1_free_entry(struct i3c_hci *hci, unsigned int dat_idx) 102{ 103 dat_w0_write(dat_idx, 0); 104 dat_w1_write(dat_idx, 0); 105 if (hci->DAT_data) 106 __clear_bit(dat_idx, hci->DAT_data); 107} 108 109static void hci_dat_v1_set_dynamic_addr(struct i3c_hci *hci, 110 unsigned int dat_idx, u8 address) 111{ 112 u32 dat_w0; 113 114 dat_w0 = dat_w0_read(dat_idx); 115 dat_w0 &= ~(DAT_0_DYNAMIC_ADDRESS | DAT_0_DYNADDR_PARITY); 116 dat_w0 |= FIELD_PREP(DAT_0_DYNAMIC_ADDRESS, address) | 117 (parity8(address) ? 0 : DAT_0_DYNADDR_PARITY); 118 dat_w0_write(dat_idx, dat_w0); 119} 120 121static void hci_dat_v1_set_static_addr(struct i3c_hci *hci, 122 unsigned int dat_idx, u8 address) 123{ 124 u32 dat_w0; 125 126 dat_w0 = dat_w0_read(dat_idx); 127 dat_w0 &= ~DAT_0_STATIC_ADDRESS; 128 dat_w0 |= FIELD_PREP(DAT_0_STATIC_ADDRESS, address); 129 dat_w0_write(dat_idx, dat_w0); 130} 131 132static void hci_dat_v1_set_flags(struct i3c_hci *hci, unsigned int dat_idx, 133 u32 w0_flags, u32 w1_flags) 134{ 135 u32 dat_w0, dat_w1; 136 137 dat_w0 = dat_w0_read(dat_idx); 138 dat_w1 = dat_w1_read(dat_idx); 139 dat_w0 |= w0_flags; 140 dat_w1 |= w1_flags; 141 dat_w0_write(dat_idx, dat_w0); 142 dat_w1_write(dat_idx, dat_w1); 143} 144 145static void hci_dat_v1_clear_flags(struct i3c_hci *hci, unsigned int dat_idx, 146 u32 w0_flags, u32 w1_flags) 147{ 148 u32 dat_w0, dat_w1; 149 150 dat_w0 = dat_w0_read(dat_idx); 151 dat_w1 = dat_w1_read(dat_idx); 152 dat_w0 &= ~w0_flags; 153 dat_w1 &= ~w1_flags; 154 dat_w0_write(dat_idx, dat_w0); 155 dat_w1_write(dat_idx, dat_w1); 156} 157 158static int hci_dat_v1_get_index(struct i3c_hci *hci, u8 dev_addr) 159{ 160 unsigned int dat_idx; 161 u32 dat_w0; 162 163 for_each_set_bit(dat_idx, hci->DAT_data, hci->DAT_entries) { 164 dat_w0 = dat_w0_read(dat_idx); 165 if (FIELD_GET(DAT_0_DYNAMIC_ADDRESS, dat_w0) == dev_addr) 166 return dat_idx; 167 } 168 169 return -ENODEV; 170} 171 172const struct hci_dat_ops mipi_i3c_hci_dat_v1 = { 173 .init = hci_dat_v1_init, 174 .cleanup = hci_dat_v1_cleanup, 175 .alloc_entry = hci_dat_v1_alloc_entry, 176 .free_entry = hci_dat_v1_free_entry, 177 .set_dynamic_addr = hci_dat_v1_set_dynamic_addr, 178 .set_static_addr = hci_dat_v1_set_static_addr, 179 .set_flags = hci_dat_v1_set_flags, 180 .clear_flags = hci_dat_v1_clear_flags, 181 .get_index = hci_dat_v1_get_index, 182};
~/
Read-only file preview.