soundwire: debugfs: add interface for BPT/BRA transfers

Add code to show what codec drivers will need to do to enable BPT/BRA
transfers. The only difference is to set the 'command_type' file to
'1'. A zero-value will rely on regular read/write commands in Column0.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Tested-by: shumingf@realtek.com
Link: https://lore.kernel.org/r/20250227140615.8147-16-yung-chuan.liao@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by Pierre-Louis Bossart and committed by Vinod Koul bb5cb09e 3394e2b1

+70 -18
+70 -18
drivers/soundwire/debugfs.c
··· 136 136 } 137 137 DEFINE_SHOW_ATTRIBUTE(sdw_slave_reg); 138 138 139 - #define MAX_CMD_BYTES 256 139 + #define MAX_CMD_BYTES (1024 * 1024) 140 140 141 141 static int cmd; 142 + static int cmd_type; 142 143 static u32 start_addr; 143 144 static size_t num_bytes; 144 145 static u8 read_buffer[MAX_CMD_BYTES]; ··· 162 161 } 163 162 DEFINE_DEBUGFS_ATTRIBUTE(set_command_fops, NULL, 164 163 set_command, "%llu\n"); 164 + 165 + static int set_command_type(void *data, u64 value) 166 + { 167 + struct sdw_slave *slave = data; 168 + 169 + if (value > 1) 170 + return -EINVAL; 171 + 172 + /* Userspace changed the hardware state behind the kernel's back */ 173 + add_taint(TAINT_USER, LOCKDEP_STILL_OK); 174 + 175 + dev_dbg(&slave->dev, "command type: %s\n", value ? "BRA" : "Column0"); 176 + 177 + cmd_type = (int)value; 178 + 179 + return 0; 180 + } 181 + DEFINE_DEBUGFS_ATTRIBUTE(set_command_type_fops, NULL, 182 + set_command_type, "%llu\n"); 165 183 166 184 static int set_start_address(void *data, u64 value) 167 185 { ··· 217 197 DEFINE_DEBUGFS_ATTRIBUTE(set_num_bytes_fops, NULL, 218 198 set_num_bytes, "%llu\n"); 219 199 200 + static int do_bpt_sequence(struct sdw_slave *slave, bool write, u8 *buffer) 201 + { 202 + struct sdw_bpt_msg msg = {0}; 203 + 204 + msg.addr = start_addr; 205 + msg.len = num_bytes; 206 + msg.dev_num = slave->dev_num; 207 + if (write) 208 + msg.flags = SDW_MSG_FLAG_WRITE; 209 + else 210 + msg.flags = SDW_MSG_FLAG_READ; 211 + msg.buf = buffer; 212 + 213 + return sdw_bpt_send_sync(slave->bus, slave, &msg); 214 + } 215 + 220 216 static int cmd_go(void *data, u64 value) 221 217 { 218 + const struct firmware *fw = NULL; 222 219 struct sdw_slave *slave = data; 220 + ktime_t start_t; 221 + ktime_t finish_t; 223 222 int ret; 224 223 225 224 if (value != 1) ··· 255 216 return ret; 256 217 } 257 218 258 - /* Userspace changed the hardware state behind the kernel's back */ 259 - add_taint(TAINT_USER, LOCKDEP_STILL_OK); 260 - 261 - dev_dbg(&slave->dev, "starting command\n"); 262 - 263 219 if (cmd == 0) { 264 - const struct firmware *fw; 265 - 266 220 ret = request_firmware(&fw, firmware_file, &slave->dev); 267 221 if (ret < 0) { 268 222 dev_err(&slave->dev, "firmware %s not found\n", firmware_file); 269 223 goto out; 270 224 } 271 - 272 - if (fw->size != num_bytes) { 225 + if (fw->size < num_bytes) { 273 226 dev_err(&slave->dev, 274 - "firmware %s: unexpected size %zd, desired %zd\n", 227 + "firmware %s: firmware size %zd, desired %zd\n", 275 228 firmware_file, fw->size, num_bytes); 276 - release_firmware(fw); 277 229 goto out; 278 230 } 279 - 280 - ret = sdw_nwrite_no_pm(slave, start_addr, num_bytes, fw->data); 281 - release_firmware(fw); 282 - } else { 283 - ret = sdw_nread_no_pm(slave, start_addr, num_bytes, read_buffer); 284 231 } 285 232 286 - dev_dbg(&slave->dev, "command completed %d\n", ret); 233 + /* Userspace changed the hardware state behind the kernel's back */ 234 + add_taint(TAINT_USER, LOCKDEP_STILL_OK); 235 + 236 + dev_dbg(&slave->dev, "starting command\n"); 237 + start_t = ktime_get(); 238 + 239 + if (cmd == 0) { 240 + if (cmd_type) 241 + ret = do_bpt_sequence(slave, true, (u8 *)fw->data); 242 + else 243 + ret = sdw_nwrite_no_pm(slave, start_addr, num_bytes, fw->data); 244 + } else { 245 + memset(read_buffer, 0, sizeof(read_buffer)); 246 + 247 + if (cmd_type) 248 + ret = do_bpt_sequence(slave, false, read_buffer); 249 + else 250 + ret = sdw_nread_no_pm(slave, start_addr, num_bytes, read_buffer); 251 + } 252 + 253 + finish_t = ktime_get(); 287 254 288 255 out: 256 + if (fw) 257 + release_firmware(fw); 258 + 289 259 pm_runtime_mark_last_busy(&slave->dev); 290 260 pm_runtime_put(&slave->dev); 261 + 262 + dev_dbg(&slave->dev, "command completed, num_byte %zu status %d, time %lld ms\n", 263 + num_bytes, ret, div_u64(finish_t - start_t, NSEC_PER_MSEC)); 291 264 292 265 return ret; 293 266 } ··· 342 291 343 292 /* interface to send arbitrary commands */ 344 293 debugfs_create_file("command", 0200, d, slave, &set_command_fops); 294 + debugfs_create_file("command_type", 0200, d, slave, &set_command_type_fops); 345 295 debugfs_create_file("start_address", 0200, d, slave, &set_start_address_fops); 346 296 debugfs_create_file("num_bytes", 0200, d, slave, &set_num_bytes_fops); 347 297 debugfs_create_file("go", 0200, d, slave, &cmd_go_fops);