Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

soundwire: amd: refactor bandwidth calculation logic

For current platforms(ACP6.3/ACP7.0/ACP7.1/ACP7.2), AMD SoundWire manager
doesn't have banked registers for data port programming on Manager's side.
Need to use fixed block offsets, hstart & hstop for manager ports.

Earlier amd manager driver has support for 12 MHz as a bus clock frequency
where frame rate is 48000 and number of bits is 500, frame shape as
50 x 10 with fixed block offset mapping based on port number.

Got a new requirement to support 6 MHz as a bus clock frequency.
For 6 MHz bus clock frequency amd manager driver needs to support two
different frame shapes i.e number of bits as 250 with frame rate as 48000
and frame shape as 125 x 2 and for the second combination number of bits as
500 where frame rate is 24000 and frame shape is 50 x 10.

Few SoundWire peripherals doesn't support 125 x 2 as a frame shape for
6 MHz bus clock frequency. They have explicit requirement for the frame
shape. In this scenario, amd manager driver needs to use 50 x 10 as a frame
shape where frame rate is 24000. Based on the platform and SoundWire
topology for 6Mhz support frame shape will be decided which is part of
SoundWire manager DisCo tables.

For current platforms, amd manager driver supports only two bus clock
frequencies(12 MHz & 6 MHz). Refactor bandwidth logic to support different
bus clock frequencies.

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Link: https://patch.msgid.link/20260226065638.1251771-3-Vijendar.Mukunda@amd.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Vijendar Mukunda and committed by
Vinod Koul
27ab4f1e 2a267a84

+57 -4
+53 -4
drivers/soundwire/amd_manager.c
··· 467 467 468 468 static int amd_sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) 469 469 { 470 + struct amd_sdw_manager *amd_manager = to_amd_sdw(bus); 470 471 struct sdw_transport_data t_data = {0}; 471 472 struct sdw_master_runtime *m_rt; 472 473 struct sdw_port_runtime *p_rt; 473 474 struct sdw_bus_params *b_params = &bus->params; 474 475 int port_bo, hstart, hstop, sample_int; 475 - unsigned int rate, bps; 476 + unsigned int rate, bps, channels; 477 + unsigned int stream_slot_size, max_slots; 478 + static unsigned int next_offset[AMD_SDW_MAX_MANAGER_COUNT] = {1}; 479 + unsigned int inst_id = amd_manager->instance; 476 480 477 481 port_bo = 0; 478 482 hstart = 1; ··· 487 483 list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { 488 484 rate = m_rt->stream->params.rate; 489 485 bps = m_rt->stream->params.bps; 486 + channels = m_rt->stream->params.ch_count; 490 487 sample_int = (bus->params.curr_dr_freq / rate); 488 + 489 + /* Compute slots required for this stream dynamically */ 490 + stream_slot_size = bps * channels; 491 + 491 492 list_for_each_entry(p_rt, &m_rt->port_list, port_node) { 492 - port_bo = (p_rt->num * 64) + 1; 493 - dev_dbg(bus->dev, "p_rt->num=%d hstart=%d hstop=%d port_bo=%d\n", 494 - p_rt->num, hstart, hstop, port_bo); 493 + if (p_rt->num >= amd_manager->max_ports) { 494 + dev_err(bus->dev, "Port %d exceeds max ports %d\n", 495 + p_rt->num, amd_manager->max_ports); 496 + return -EINVAL; 497 + } 498 + 499 + if (!amd_manager->port_offset_map[p_rt->num]) { 500 + /* 501 + * port block offset calculation for 6MHz bus clock frequency with 502 + * different frame sizes 50 x 10 and 125 x 2 503 + */ 504 + if (bus->params.curr_dr_freq == 12000000) { 505 + max_slots = bus->params.row * (bus->params.col - 1); 506 + if (next_offset[inst_id] + stream_slot_size <= 507 + (max_slots - 1)) { 508 + amd_manager->port_offset_map[p_rt->num] = 509 + next_offset[inst_id]; 510 + next_offset[inst_id] += stream_slot_size; 511 + } else { 512 + dev_err(bus->dev, 513 + "No space for port %d\n", p_rt->num); 514 + return -ENOMEM; 515 + } 516 + } else { 517 + /* 518 + * port block offset calculation for 12MHz bus clock 519 + * frequency 520 + */ 521 + amd_manager->port_offset_map[p_rt->num] = 522 + (p_rt->num * 64) + 1; 523 + } 524 + } 525 + port_bo = amd_manager->port_offset_map[p_rt->num]; 526 + dev_dbg(bus->dev, 527 + "Port=%d hstart=%d hstop=%d port_bo=%d slots=%d max_ports=%d\n", 528 + p_rt->num, hstart, hstop, port_bo, stream_slot_size, 529 + amd_manager->max_ports); 530 + 495 531 sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, 496 532 false, SDW_BLK_GRP_CNT_1, sample_int, 497 533 port_bo, port_bo >> 8, hstart, hstop, ··· 1123 1079 default: 1124 1080 return -EINVAL; 1125 1081 } 1082 + amd_manager->max_ports = amd_manager->num_dout_ports + amd_manager->num_din_ports; 1083 + amd_manager->port_offset_map = devm_kcalloc(dev, amd_manager->max_ports, 1084 + sizeof(int), GFP_KERNEL); 1085 + if (!amd_manager->port_offset_map) 1086 + return -ENOMEM; 1126 1087 1127 1088 prop = &amd_manager->bus.prop; 1128 1089 prop->mclk_freq = AMD_SDW_BUS_BASE_FREQ;
+4
include/linux/soundwire/sdw_amd.h
··· 66 66 * @status: peripheral devices status array 67 67 * @num_din_ports: number of input ports 68 68 * @num_dout_ports: number of output ports 69 + * @max_ports: total number of input ports and output ports 69 70 * @cols_index: Column index in frame shape 70 71 * @rows_index: Rows index in frame shape 72 + * @port_offset_map: dynamic array to map port block offset 71 73 * @instance: SoundWire manager instance 72 74 * @quirks: SoundWire manager quirks 73 75 * @wake_en_mask: wake enable mask per SoundWire manager ··· 94 92 95 93 int num_din_ports; 96 94 int num_dout_ports; 95 + int max_ports; 97 96 98 97 int cols_index; 99 98 int rows_index; 100 99 100 + int *port_offset_map; 101 101 u32 instance; 102 102 u32 quirks; 103 103 u32 wake_en_mask;