soc: soundwire: Update bus clock frequency based on usecase

Some usecases need soundwire bus clock frequency to run at
lower clock rate for better power and performance. Update
soundwire bus clock frequency based on usecase.

Change-Id: I2e786d9f5d5d2ec3841daa934802eeafa79a8f6c
Signed-off-by: Sudheer Papothi <spapothi@codeaurora.org>
Šī revīzija ir iekļauta:
Sudheer Papothi
2019-11-27 06:52:06 +05:30
vecāks b30560f219
revīzija cdeb593d01
4 mainīti faili ar 122 papildinājumiem un 15 dzēšanām

Parādīt failu

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _LINUX_SOUNDWIRE_H
@@ -11,6 +11,13 @@
#include <linux/regmap.h>
#include "audio_mod_devicetable.h"
#define SWR_CLK_RATE_0P6MHZ 600000
#define SWR_CLK_RATE_1P2MHZ 1200000
#define SWR_CLK_RATE_2P4MHZ 2400000
#define SWR_CLK_RATE_4P8MHZ 4800000
#define SWR_CLK_RATE_9P6MHZ 9600000
#define SWR_CLK_RATE_11P2896MHZ 1128960
extern struct bus_type soundwire_type;
struct swr_device;

Parādīt failu

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015, 2017-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2015, 2017-2020 The Linux Foundation. All rights reserved.
*/
#ifndef _LINUX_SWR_WCD_H
@@ -32,6 +32,7 @@ struct swr_mstr_port {
};
#define MCLK_FREQ 9600000
#define MCLK_FREQ_LP 600000
#define MCLK_FREQ_NATIVE 11289600
#if (IS_ENABLED(CONFIG_SOUNDWIRE_WCD_CTRL) || \

Parādīt failu

@@ -26,6 +26,8 @@
#include "swr-slave-registers.h"
#include "swr-mstr-ctrl.h"
#define SWR_NUM_PORTS 4 /* TODO - Get this info from DT */
#define SWRM_FRAME_SYNC_SEL 4000 /* 4KHz */
#define SWRM_FRAME_SYNC_SEL_NATIVE 3675 /* 3.675KHz */
@@ -65,10 +67,12 @@
#define SWRM_MCP_SLV_STATUS_MASK 0x03
#define SWRM_ROW_CTRL_MASK 0xF8
#define SWRM_COL_CTRL_MASK 0x07
#define SWRM_CLK_DIV_MASK 0x700
#define SWRM_SSP_PERIOD_MASK 0xff0000
#define SWRM_NUM_PINGS_MASK 0x3E0000
#define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT 3
#define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT 0
#define SWRM_MCP_FRAME_CTRL_BANK_CLK_DIV_VALUE_SHFT 8
#define SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT 16
#define SWRM_NUM_PINGS_POS 0x11
@@ -117,6 +121,42 @@ static void swrm_unlock_sleep(struct swr_mstr_ctrl *swrm);
static u32 swr_master_read(struct swr_mstr_ctrl *swrm, unsigned int reg_addr);
static void swr_master_write(struct swr_mstr_ctrl *swrm, u16 reg_addr, u32 val);
static u8 swrm_get_clk_div(int mclk_freq, int bus_clk_freq)
{
int clk_div = 0;
u8 div_val = 0;
if (!mclk_freq || !bus_clk_freq)
return 0;
clk_div = (mclk_freq / bus_clk_freq);
switch (clk_div) {
case 32:
div_val = 5;
break;
case 16:
div_val = 4;
break;
case 8:
div_val = 3;
break;
case 4:
div_val = 2;
break;
case 2:
div_val = 1;
break;
case 1:
default:
div_val = 0;
break;
}
return div_val;
}
static bool swrm_is_msm_variant(int val)
{
return (val == SWRM_VERSION_1_3);
@@ -996,6 +1036,49 @@ end:
return is_removed;
}
int swrm_get_clk_div_rate(int mclk_freq, int bus_clk_freq)
{
if (!bus_clk_freq)
return mclk_freq;
if (mclk_freq == SWR_CLK_RATE_9P6MHZ) {
if (bus_clk_freq <= SWR_CLK_RATE_0P6MHZ)
bus_clk_freq = SWR_CLK_RATE_0P6MHZ;
else if (bus_clk_freq <= SWR_CLK_RATE_1P2MHZ)
bus_clk_freq = SWR_CLK_RATE_1P2MHZ;
else if (bus_clk_freq <= SWR_CLK_RATE_2P4MHZ)
bus_clk_freq = SWR_CLK_RATE_2P4MHZ;
else if(bus_clk_freq <= SWR_CLK_RATE_4P8MHZ)
bus_clk_freq = SWR_CLK_RATE_4P8MHZ;
else if(bus_clk_freq <= SWR_CLK_RATE_9P6MHZ)
bus_clk_freq = SWR_CLK_RATE_9P6MHZ;
} else if (mclk_freq == SWR_CLK_RATE_11P2896MHZ)
bus_clk_freq = SWR_CLK_RATE_11P2896MHZ;
return bus_clk_freq;
}
static int swrm_update_bus_clk(struct swr_mstr_ctrl *swrm)
{
int ret = 0;
int agg_clk = 0;
int i;
for (i = 0; i < SWR_MSTR_PORT_LEN; i++)
agg_clk += swrm->mport_cfg[i].ch_rate;
if (agg_clk)
swrm->bus_clk = swrm_get_clk_div_rate(swrm->mclk_freq,
agg_clk);
else
swrm->bus_clk = swrm->mclk_freq;
dev_dbg(swrm->dev, "%s: all_port_clk: %d, bus_clk: %d\n",
__func__, agg_clk, swrm->bus_clk);
return ret;
}
static void swrm_disable_ports(struct swr_master *master,
u8 bank)
{
@@ -1268,13 +1351,14 @@ static void swrm_apply_port_config(struct swr_master *master)
static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable)
{
u8 bank;
u32 value, n_row, n_col;
u32 value = 0, n_row = 0, n_col = 0;
u32 row = 0, col = 0;
int bus_clk_div_factor;
int ret;
u8 ssp_period = 0;
struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master);
int mask = (SWRM_ROW_CTRL_MASK | SWRM_COL_CTRL_MASK |
SWRM_SSP_PERIOD_MASK);
SWRM_CLK_DIV_MASK | SWRM_SSP_PERIOD_MASK);
u8 inactive_bank;
int frame_sync = SWRM_FRAME_SYNC_SEL;
@@ -1334,13 +1418,17 @@ static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable)
clear_bit(DISABLE_PENDING, &swrm->port_req_pending);
swrm_disable_ports(master, bank);
}
dev_dbg(swrm->dev, "%s: enable: %d, cfg_devs: %d\n",
__func__, enable, swrm->num_cfg_devs);
dev_dbg(swrm->dev, "%s: enable: %d, cfg_devs: %d freq %d\n",
__func__, enable, swrm->num_cfg_devs, swrm->mclk_freq);
if (enable) {
/* set col = 16 */
n_col = SWR_MAX_COL;
col = SWRM_COL_16;
if (swrm->bus_clk == MCLK_FREQ_LP) {
n_col = SWR_MIN_COL;
col = SWRM_COL_02;
}
} else {
/*
* Do not change to col = 2 if there are still active ports
@@ -1355,25 +1443,26 @@ static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable)
}
/* Use default 50 * x, frame shape. Change based on mclk */
if (swrm->mclk_freq == MCLK_FREQ_NATIVE) {
dev_dbg(swrm->dev, "setting 64 x %d frameshape\n",
n_col ? 16 : 2);
dev_dbg(swrm->dev, "setting 64 x %d frameshape\n", col);
n_row = SWR_ROW_64;
row = SWRM_ROW_64;
frame_sync = SWRM_FRAME_SYNC_SEL_NATIVE;
} else {
dev_dbg(swrm->dev, "setting 50 x %d frameshape\n",
n_col ? 16 : 2);
dev_dbg(swrm->dev, "setting 50 x %d frameshape\n", col);
n_row = SWR_ROW_50;
row = SWRM_ROW_50;
frame_sync = SWRM_FRAME_SYNC_SEL;
}
ssp_period = swrm_get_ssp_period(swrm, row, col, frame_sync);
dev_dbg(swrm->dev, "%s: ssp_period: %d\n", __func__, ssp_period);
bus_clk_div_factor = swrm_get_clk_div(swrm->mclk_freq, swrm->bus_clk);
dev_dbg(swrm->dev, "%s: ssp_period: %d, bus_clk_div:%d \n", __func__,
ssp_period, bus_clk_div_factor);
value = swr_master_read(swrm, SWRM_MCP_FRAME_CTRL_BANK(bank));
value &= (~mask);
value |= ((n_row << SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_SHFT) |
(n_col << SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_SHFT) |
(bus_clk_div_factor <<
SWRM_MCP_FRAME_CTRL_BANK_CLK_DIV_VALUE_SHFT) |
((ssp_period - 1) << SWRM_MCP_FRAME_CTRL_BANK_SSP_PERIOD_SHFT));
swr_master_write(swrm, SWRM_MCP_FRAME_CTRL_BANK(bank), value);
@@ -1477,6 +1566,11 @@ static int swrm_connect_port(struct swr_master *master,
mport->port_en = true;
mport->req_ch |= mstr_ch_msk;
master->port_en_mask |= (1 << mstr_port_id);
if (swrm->clk_stop_mode0_supp &&
(mport->ch_rate < portinfo->ch_rate[i])) {
mport->ch_rate = portinfo->ch_rate[i];
swrm_update_bus_clk(swrm);
}
}
master->num_port += portinfo->num_port;
set_bit(ENABLE_PENDING, &swrm->port_req_pending);
@@ -1539,6 +1633,10 @@ static int swrm_disconnect_port(struct swr_master *master,
}
port_req->req_ch &= ~portinfo->ch_en[i];
mport->req_ch &= ~mstr_ch_mask;
if (swrm->clk_stop_mode0_supp && !mport->req_ch) {
mport->ch_rate = 0;
swrm_update_bus_clk(swrm);
}
}
master->num_port -= portinfo->num_port;
set_bit(DISABLE_PENDING, &swrm->port_req_pending);

Parādīt failu

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _SWR_WCD_CTRL_H
@@ -26,6 +26,7 @@
#define SWR_ROW_48 0
#define SWR_ROW_50 1
#define SWR_ROW_64 3
#define SWR_COL_04 1 /* Cols = 4 */
#define SWR_MAX_COL 7 /* Cols = 16 */
#define SWR_MIN_COL 0 /* Cols = 2 */
@@ -42,7 +43,7 @@
#define SWR_MAX_CH_PER_PORT 8
#define SWR_MAX_SLAVE_DEVICES 11
#define SWRM_NUM_AUTO_ENUM_SLAVES 6
enum {
SWR_MSTR_PAUSE,
@@ -86,7 +87,6 @@ struct swrm_mports {
bool port_en;
u8 ch_en;
u8 req_ch;
u8 ch_rate;
u8 offset1;
u8 offset2;
u8 sinterval;
@@ -98,6 +98,7 @@ struct swrm_mports {
u8 lane_ctrl;
u8 dir;
u8 stream_type;
u32 ch_rate;
};
struct swrm_port_type {