mn: add M/N dividers to sof context

Adds pointer to mn struct to sof context. Also implements
getter, so it can be retrieved through one point of access.

Signed-off-by: Tomasz Lauda <tomasz.lauda@linux.intel.com>
This commit is contained in:
Tomasz Lauda 2020-01-21 12:48:09 +01:00 committed by Liam Girdwood
parent bd6467b707
commit eab1cab174
4 changed files with 70 additions and 35 deletions

View File

@ -8,6 +8,7 @@
#include <sof/drivers/ssp.h>
#include <sof/lib/shim.h>
#include <sof/math/numbers.h>
#include <sof/sof.h>
#include <sof/spinlock.h>
#include <sof/trace/trace.h>
#include <stdbool.h>
@ -53,14 +54,16 @@ struct mn {
struct mn mn;
void mn_init(void)
void mn_init(struct sof *sof)
{
int i;
for (i = 0; i < ARRAY_SIZE(mn.bclk_sources); i++)
mn.bclk_sources[i] = MN_BCLK_SOURCE_NONE;
sof->mn = &mn;
spinlock_init(&mn.lock);
for (i = 0; i < ARRAY_SIZE(sof->mn->bclk_sources); i++)
sof->mn->bclk_sources[i] = MN_BCLK_SOURCE_NONE;
spinlock_init(&sof->mn->lock);
}
/**
@ -70,10 +73,11 @@ void mn_init(void)
*/
static inline bool is_mclk_source_in_use(void)
{
struct mn *mn = mn_get();
int i;
for (i = 0; i < ARRAY_SIZE(mn.mclk_sources_used); i++)
if (mn.mclk_sources_used[i])
for (i = 0; i < ARRAY_SIZE(mn->mclk_sources_used); i++)
if (mn->mclk_sources_used[i])
return true;
return false;
}
@ -87,6 +91,7 @@ static inline bool is_mclk_source_in_use(void)
*/
static inline int setup_initial_mclk_source(uint32_t mclk_rate)
{
struct mn *mn = mn_get();
int i;
int clk_index = -1;
uint32_t mdivc = mn_reg_read(MN_MDIVCTRL);
@ -106,7 +111,7 @@ static inline int setup_initial_mclk_source(uint32_t mclk_rate)
return -EINVAL;
}
mn.mclk_source_clock = clk_index;
mn->mclk_source_clock = clk_index;
/* enable MCLK divider */
mdivc |= MN_MDIVCTRL_M_DIV_ENABLE;
@ -125,9 +130,11 @@ static inline int setup_initial_mclk_source(uint32_t mclk_rate)
*/
static inline int check_current_mclk_source(uint32_t mclk_rate)
{
if (ssp_freq[mn.mclk_source_clock].freq % mclk_rate != 0) {
struct mn *mn = mn_get();
if (ssp_freq[mn->mclk_source_clock].freq % mclk_rate != 0) {
trace_mn_error("error: MCLK %d, no valid configuration for already selected source = %d",
mclk_rate, mn.mclk_source_clock);
mclk_rate, mn->mclk_source_clock);
return -EINVAL;
}
return 0;
@ -167,6 +174,7 @@ static inline int set_mclk_divider(uint16_t mclk_id, uint32_t mdivr_val)
int mn_set_mclk(uint16_t mclk_id, uint32_t mclk_rate)
{
struct mn *mn = mn_get();
int ret = 0;
if (mclk_id >= DAI_NUM_SSP_MCLK) {
@ -175,9 +183,9 @@ int mn_set_mclk(uint16_t mclk_id, uint32_t mclk_rate)
return -EINVAL;
}
spin_lock(&mn.lock);
spin_lock(&mn->lock);
mn.mclk_sources_used[mclk_id] = false;
mn->mclk_sources_used[mclk_id] = false;
if (is_mclk_source_in_use())
ret = check_current_mclk_source(mclk_rate);
@ -187,22 +195,25 @@ int mn_set_mclk(uint16_t mclk_id, uint32_t mclk_rate)
if (ret < 0)
goto out;
mn.mclk_sources_used[mclk_id] = true;
mn->mclk_sources_used[mclk_id] = true;
ret = set_mclk_divider(mclk_id,
ssp_freq[mn.mclk_source_clock].freq / mclk_rate);
ssp_freq[mn->mclk_source_clock].freq /
mclk_rate);
out:
spin_unlock(&mn.lock);
spin_unlock(&mn->lock);
return ret;
}
void mn_release_mclk(uint32_t mclk_id)
{
spin_lock(&mn.lock);
mn.mclk_sources_used[mclk_id] = false;
spin_unlock(&mn.lock);
struct mn *mn = mn_get();
spin_lock(&mn->lock);
mn->mclk_sources_used[mclk_id] = false;
spin_unlock(&mn->lock);
}
/**
@ -299,10 +310,11 @@ static int find_bclk_source(uint32_t bclk,
*/
static inline bool is_bclk_source_in_use(enum bclk_source clk_src)
{
struct mn *mn = mn_get();
int i;
for (i = 0; i < ARRAY_SIZE(mn.bclk_sources); i++)
if (mn.bclk_sources[i] == clk_src)
for (i = 0; i < ARRAY_SIZE(mn->bclk_sources); i++)
if (mn->bclk_sources[i] == clk_src)
return true;
return false;
}
@ -320,6 +332,7 @@ static inline bool is_bclk_source_in_use(enum bclk_source clk_src)
static inline int setup_initial_bclk_mn_source(uint32_t bclk, uint32_t *scr_div,
uint32_t *m, uint32_t *n)
{
struct mn *mn = mn_get();
int clk_index = find_bclk_source(bclk, scr_div, m, n);
if (clk_index < 0) {
@ -327,7 +340,7 @@ static inline int setup_initial_bclk_mn_source(uint32_t bclk, uint32_t *scr_div,
return -EINVAL;
}
mn.bclk_source_mn_clock = clk_index;
mn->bclk_source_mn_clock = clk_index;
mn_reg_write(MN_MDIVCTRL, (mn_reg_read(MN_MDIVCTRL) |
MNDSS(ssp_freq_sources[clk_index])));
@ -346,13 +359,15 @@ static inline int setup_initial_bclk_mn_source(uint32_t bclk, uint32_t *scr_div,
static inline int setup_current_bclk_mn_source(uint32_t bclk, uint32_t *scr_div,
uint32_t *m, uint32_t *n)
{
struct mn *mn = mn_get();
/* source for M/N is already set, no need to do it */
if (find_mn(ssp_freq[mn.bclk_source_mn_clock].freq, bclk, scr_div, m,
if (find_mn(ssp_freq[mn->bclk_source_mn_clock].freq, bclk, scr_div, m,
n))
return 0;
trace_mn_error("error: BCLK %d, no valid configuration for already selected source = %d",
bclk, mn.bclk_source_mn_clock);
bclk, mn->bclk_source_mn_clock);
return -EINVAL;
}
@ -376,6 +391,7 @@ static inline bool check_bclk_xtal_source(uint32_t bclk, bool mn_in_use,
static inline bool check_bclk_xtal_source(uint32_t bclk, bool mn_in_use,
uint32_t *scr_div)
{
struct mn *mn = mn_get();
int i;
for (i = 0; i <= MAX_SSP_FREQ_INDEX; i++) {
@ -393,7 +409,7 @@ static inline bool check_bclk_xtal_source(uint32_t bclk, bool mn_in_use,
/* if M/N is already set up for desired clock,
* we can quit and let M/N logic handle it
*/
if (!mn_in_use || mn.bclk_source_mn_clock == i)
if (!mn_in_use || mn->bclk_source_mn_clock == i)
return false;
}
@ -404,19 +420,20 @@ static inline bool check_bclk_xtal_source(uint32_t bclk, bool mn_in_use,
int mn_set_bclk(uint32_t dai_index, uint32_t bclk_rate,
uint32_t *out_scr_div, bool *out_need_ecs)
{
struct mn *mn = mn_get();
uint32_t m = 1;
uint32_t n = 1;
int ret = 0;
bool mn_in_use;
spin_lock(&mn.lock);
spin_lock(&mn->lock);
mn.bclk_sources[dai_index] = MN_BCLK_SOURCE_NONE;
mn->bclk_sources[dai_index] = MN_BCLK_SOURCE_NONE;
mn_in_use = is_bclk_source_in_use(MN_BCLK_SOURCE_MN);
if (check_bclk_xtal_source(bclk_rate, mn_in_use, out_scr_div)) {
mn.bclk_sources[dai_index] = MN_BCLK_SOURCE_XTAL;
mn->bclk_sources[dai_index] = MN_BCLK_SOURCE_XTAL;
*out_need_ecs = false;
goto out;
}
@ -431,29 +448,33 @@ int mn_set_bclk(uint32_t dai_index, uint32_t bclk_rate,
out_scr_div, &m, &n);
if (ret >= 0) {
mn.bclk_sources[dai_index] = MN_BCLK_SOURCE_MN;
mn->bclk_sources[dai_index] = MN_BCLK_SOURCE_MN;
mn_reg_write(MN_MDIV_M_VAL(dai_index), m);
mn_reg_write(MN_MDIV_N_VAL(dai_index), n);
}
out:
spin_unlock(&mn.lock);
spin_unlock(&mn->lock);
return ret;
}
void mn_release_bclk(uint32_t dai_index)
{
spin_lock(&mn.lock);
mn.bclk_sources[dai_index] = MN_BCLK_SOURCE_NONE;
spin_unlock(&mn.lock);
struct mn *mn = mn_get();
spin_lock(&mn->lock);
mn->bclk_sources[dai_index] = MN_BCLK_SOURCE_NONE;
spin_unlock(&mn->lock);
}
void mn_reset_bclk_divider(uint32_t dai_index)
{
spin_lock(&mn.lock);
struct mn *mn = mn_get();
spin_lock(&mn->lock);
mn_reg_write(MN_MDIV_M_VAL(dai_index), 1);
mn_reg_write(MN_MDIV_N_VAL(dai_index), 1);
spin_unlock(&mn.lock);
spin_unlock(&mn->lock);
}

View File

@ -8,6 +8,7 @@
#ifndef __SOF_DRIVERS_MN_H__
#define __SOF_DRIVERS_MN_H__
#include <sof/sof.h>
#include <stdbool.h>
#include <stdint.h>
@ -29,7 +30,7 @@
/**
* \brief Initializes MN driver.
*/
void mn_init(void);
void mn_init(struct sof *sof);
/**
* \brief Finds and sets valid combination of MCLK source and divider to
@ -77,4 +78,13 @@ void mn_release_bclk(uint32_t dai_index);
*/
void mn_reset_bclk_divider(uint32_t dai_index);
/**
* \brief Retrieves M/N dividers structure.
* \return Pointer to M/N dividers structure.
*/
static inline struct mn *mn_get(void)
{
return sof_get()->mn;
}
#endif /* __SOF_DRIVERS_MN_H__ */

View File

@ -21,6 +21,7 @@ struct dma_trace_data;
struct ipc;
struct ll_schedule_domain;
struct mm;
struct mn;
struct notify_data;
struct pm_runtime_data;
struct sa;
@ -87,6 +88,9 @@ struct sof {
/* list of registered component drivers */
struct comp_driver_list *comp_drivers;
/* M/N dividers */
struct mn *mn;
__aligned(PLATFORM_DCACHE_ALIGN) int alignment[0];
} __aligned(PLATFORM_DCACHE_ALIGN);

View File

@ -155,7 +155,7 @@ int dai_init(struct sof *sof)
#endif
#if CONFIG_CAVS_MN
mn_init();
mn_init(sof);
#endif
dai = cache_to_uncache((struct dai *)hda);