soundwire: bus: initialize bus clock base and scale registers
The SoundWire 1.2 specification adds new registers to allow for seamless clock changes while audio transfers are on-going. Program them following the specification. Note that dynamic clock changes are not supported for now, this only adds the register initialization. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Link: https://lore.kernel.org/r/20200608205436.2402-5-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
b5924268d6
commit
29d158f906
@ -1070,12 +1070,119 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sdw_slave_set_frequency(struct sdw_slave *slave)
|
||||
{
|
||||
u32 mclk_freq = slave->bus->prop.mclk_freq;
|
||||
u32 curr_freq = slave->bus->params.curr_dr_freq >> 1;
|
||||
unsigned int scale;
|
||||
u8 scale_index;
|
||||
u8 base;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* frequency base and scale registers are required for SDCA
|
||||
* devices. They may also be used for 1.2+/non-SDCA devices,
|
||||
* but we will need a DisCo property to cover this case
|
||||
*/
|
||||
if (!slave->id.class_id)
|
||||
return 0;
|
||||
|
||||
if (!mclk_freq) {
|
||||
dev_err(&slave->dev,
|
||||
"no bus MCLK, cannot set SDW_SCP_BUS_CLOCK_BASE\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* map base frequency using Table 89 of SoundWire 1.2 spec.
|
||||
* The order of the tests just follows the specification, this
|
||||
* is not a selection between possible values or a search for
|
||||
* the best value but just a mapping. Only one case per platform
|
||||
* is relevant.
|
||||
* Some BIOS have inconsistent values for mclk_freq but a
|
||||
* correct root so we force the mclk_freq to avoid variations.
|
||||
*/
|
||||
if (!(19200000 % mclk_freq)) {
|
||||
mclk_freq = 19200000;
|
||||
base = SDW_SCP_BASE_CLOCK_19200000_HZ;
|
||||
} else if (!(24000000 % mclk_freq)) {
|
||||
mclk_freq = 24000000;
|
||||
base = SDW_SCP_BASE_CLOCK_24000000_HZ;
|
||||
} else if (!(24576000 % mclk_freq)) {
|
||||
mclk_freq = 24576000;
|
||||
base = SDW_SCP_BASE_CLOCK_24576000_HZ;
|
||||
} else if (!(22579200 % mclk_freq)) {
|
||||
mclk_freq = 22579200;
|
||||
base = SDW_SCP_BASE_CLOCK_22579200_HZ;
|
||||
} else if (!(32000000 % mclk_freq)) {
|
||||
mclk_freq = 32000000;
|
||||
base = SDW_SCP_BASE_CLOCK_32000000_HZ;
|
||||
} else {
|
||||
dev_err(&slave->dev,
|
||||
"Unsupported clock base, mclk %d\n",
|
||||
mclk_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mclk_freq % curr_freq) {
|
||||
dev_err(&slave->dev,
|
||||
"mclk %d is not multiple of bus curr_freq %d\n",
|
||||
mclk_freq, curr_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
scale = mclk_freq / curr_freq;
|
||||
|
||||
/*
|
||||
* map scale to Table 90 of SoundWire 1.2 spec - and check
|
||||
* that the scale is a power of two and maximum 64
|
||||
*/
|
||||
scale_index = ilog2(scale);
|
||||
|
||||
if (BIT(scale_index) != scale || scale_index > 6) {
|
||||
dev_err(&slave->dev,
|
||||
"No match found for scale %d, bus mclk %d curr_freq %d\n",
|
||||
scale, mclk_freq, curr_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
scale_index++;
|
||||
|
||||
ret = sdw_write(slave, SDW_SCP_BUS_CLOCK_BASE, base);
|
||||
if (ret < 0) {
|
||||
dev_err(&slave->dev,
|
||||
"SDW_SCP_BUS_CLOCK_BASE write failed:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* initialize scale for both banks */
|
||||
ret = sdw_write(slave, SDW_SCP_BUSCLOCK_SCALE_B0, scale_index);
|
||||
if (ret < 0) {
|
||||
dev_err(&slave->dev,
|
||||
"SDW_SCP_BUSCLOCK_SCALE_B0 write failed:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = sdw_write(slave, SDW_SCP_BUSCLOCK_SCALE_B1, scale_index);
|
||||
if (ret < 0)
|
||||
dev_err(&slave->dev,
|
||||
"SDW_SCP_BUSCLOCK_SCALE_B1 write failed:%d\n", ret);
|
||||
|
||||
dev_dbg(&slave->dev,
|
||||
"Configured bus base %d, scale %d, mclk %d, curr_freq %d\n",
|
||||
base, scale_index, mclk_freq, curr_freq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sdw_initialize_slave(struct sdw_slave *slave)
|
||||
{
|
||||
struct sdw_slave_prop *prop = &slave->prop;
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
ret = sdw_slave_set_frequency(slave);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set bus clash, parity and SCP implementation
|
||||
* defined interrupt mask
|
||||
|
@ -109,8 +109,18 @@
|
||||
#define SDW_SCP_KEEPEREN 0x4A
|
||||
#define SDW_SCP_BANKDELAY 0x4B
|
||||
#define SDW_SCP_COMMIT 0x4C
|
||||
|
||||
#define SDW_SCP_BUS_CLOCK_BASE 0x4D
|
||||
#define SDW_SCP_BASE_CLOCK_FREQ GENMASK(2, 0)
|
||||
#define SDW_SCP_BASE_CLOCK_UNKNOWN 0x0
|
||||
#define SDW_SCP_BASE_CLOCK_19200000_HZ 0x1
|
||||
#define SDW_SCP_BASE_CLOCK_24000000_HZ 0x2
|
||||
#define SDW_SCP_BASE_CLOCK_24576000_HZ 0x3
|
||||
#define SDW_SCP_BASE_CLOCK_22579200_HZ 0x4
|
||||
#define SDW_SCP_BASE_CLOCK_32000000_HZ 0x5
|
||||
#define SDW_SCP_BASE_CLOCK_RESERVED 0x6
|
||||
#define SDW_SCP_BASE_CLOCK_IMP_DEF 0x7
|
||||
|
||||
/* 0x4E is not allocated in SoundWire specification 1.2 */
|
||||
#define SDW_SCP_TESTMODE 0x4F
|
||||
#define SDW_SCP_DEVID_0 0x50
|
||||
|
Loading…
x
Reference in New Issue
Block a user