Loading drivers/platform/msm/qcom-geni-se.c +110 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ #define GENI_SE_IOMMU_VA_SIZE (0xC0000000) #define NUM_LOG_PAGES 2 #define MAX_CLK_PERF_LEVEL 32 static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000, 100000000}; /** Loading @@ -52,6 +52,8 @@ static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000, 100000000}; * @cur_ib: Current Bus Instantaneous BW request value. * @bus_bw_set: Clock plan for the bus driver. * @cur_bus_bw_idx: Current index within the bus clock plan. * @num_clk_levels: Number of valid clock levels in clk_perf_tbl. * @clk_perf_tbl: Table of clock frequency input to Serial Engine clock. * @log_ctx: Logging context to hold the debug information */ struct geni_se_device { Loading @@ -72,6 +74,8 @@ struct geni_se_device { int bus_bw_set_size; unsigned long *bus_bw_set; int cur_bus_bw_idx; unsigned int num_clk_levels; unsigned long *clk_perf_tbl; void *log_ctx; }; Loading Loading @@ -808,6 +812,111 @@ int geni_se_resources_init(struct se_geni_rsc *rsc, } EXPORT_SYMBOL(geni_se_resources_init); /** * geni_se_clk_tbl_get() - Get the clock table to program DFS * @rsc: Resource for which the clock table is requested. * @tbl: Table in which the output is returned. * * This function is called by the protocol drivers to determine the different * clock frequencies supported by Serail Engine Core Clock. The protocol * drivers use the output to determine the clock frequency index to be * programmed into DFS. * * Return: number of valid performance levels in the table on success, * standard Linux error codes on failure. */ int geni_se_clk_tbl_get(struct se_geni_rsc *rsc, unsigned long **tbl) { struct geni_se_device *geni_se_dev; int i; unsigned long prev_freq = 0; if (unlikely(!rsc || !rsc->wrapper_dev || !rsc->se_clk || !tbl)) return -EINVAL; *tbl = NULL; geni_se_dev = dev_get_drvdata(rsc->wrapper_dev); if (unlikely(!geni_se_dev)) return -EPROBE_DEFER; if (geni_se_dev->clk_perf_tbl) { *tbl = geni_se_dev->clk_perf_tbl; return geni_se_dev->num_clk_levels; } geni_se_dev->clk_perf_tbl = kzalloc(sizeof(*geni_se_dev->clk_perf_tbl) * MAX_CLK_PERF_LEVEL, GFP_KERNEL); if (!geni_se_dev->clk_perf_tbl) return -ENOMEM; for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { geni_se_dev->clk_perf_tbl[i] = clk_round_rate(rsc->se_clk, prev_freq + 1); if (geni_se_dev->clk_perf_tbl[i] == prev_freq) { geni_se_dev->clk_perf_tbl[i] = 0; break; } prev_freq = geni_se_dev->clk_perf_tbl[i]; } geni_se_dev->num_clk_levels = i; *tbl = geni_se_dev->clk_perf_tbl; return geni_se_dev->num_clk_levels; } EXPORT_SYMBOL(geni_se_clk_tbl_get); /** * geni_se_clk_freq_match() - Get the matching or closest SE clock frequency * @rsc: Resource for which the clock frequency is requested. * @req_freq: Requested clock frequency. * @index: Index of the resultant frequency in the table. * @res_freq: Resultant frequency which matches or is closer to the * requested frequency. * @exact: Flag to indicate exact multiple requirement of the requested * frequency . * * This function is called by the protocol drivers to determine the matching * or closest frequency of the Serial Engine clock to be selected in order * to meet the performance requirements. * * Return: 0 on success, standard Linux error codes on failure. */ int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq, unsigned int *index, unsigned long *res_freq, bool exact) { unsigned long *tbl; int num_clk_levels; int i; num_clk_levels = geni_se_clk_tbl_get(rsc, &tbl); if (num_clk_levels < 0) return num_clk_levels; if (num_clk_levels == 0) return -EFAULT; *res_freq = 0; for (i = 0; i < num_clk_levels; i++) { if (!(tbl[i] % req_freq)) { *index = i; *res_freq = tbl[i]; return 0; } if (!(*res_freq) || ((tbl[i] > *res_freq) && (tbl[i] < req_freq))) { *index = i; *res_freq = tbl[i]; } } if (exact || !(*res_freq)) return -ENOKEY; return 0; } EXPORT_SYMBOL(geni_se_clk_freq_match); /** * geni_se_tx_dma_prep() - Prepare the Serial Engine for TX DMA transfer * @wrapper_dev: QUPv3 Wrapper Device to which the TX buffer is mapped. Loading drivers/spi/spi-geni-qcom.c +10 −12 Original line number Diff line number Diff line Loading @@ -110,14 +110,6 @@ static struct spi_master *get_spi_master(struct device *dev) return spi; } static int get_sclk(u32 speed_hz, unsigned long *sclk_freq) { u32 root_freq[] = { 19200000 }; *sclk_freq = root_freq[0]; return 0; } static int do_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas) { unsigned long sclk_freq; Loading @@ -131,14 +123,20 @@ static int do_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas) clk_sel &= ~CLK_SEL_MSK; m_clk_cfg &= ~CLK_DIV_MSK; idx = get_sclk(speed_hz, &sclk_freq); if (idx < 0) return -EINVAL; ret = geni_se_clk_freq_match(&mas->spi_rsc, speed_hz, &idx, &sclk_freq, true); if (ret) { dev_err(mas->dev, "%s: Failed(%d) to find src clk for 0x%x\n", __func__, ret, speed_hz); return ret; } div = ((sclk_freq / SPI_OVERSAMPLING) / speed_hz); if (!div) return -EINVAL; dev_dbg(mas->dev, "%s: req %u sclk %lu, idx %d, div %d\n", __func__, speed_hz, sclk_freq, idx, div); clk_sel |= (idx & CLK_SEL_MSK); m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN); ret = clk_set_rate(rsc->se_clk, sclk_freq); Loading Loading @@ -362,13 +360,13 @@ static int spi_geni_transfer_one(struct spi_master *spi, reinit_completion(&mas->xfer_done); /* Speed and bits per word can be overridden per transfer */ if (xfer->speed_hz != mas->cur_speed_hz) { mas->cur_speed_hz = xfer->speed_hz; ret = do_spi_clk_cfg(mas->cur_speed_hz, mas); if (ret) { dev_err(mas->dev, "%s:Err setting clks:%d\n", __func__, ret); goto geni_transfer_one_exit; } mas->cur_speed_hz = xfer->speed_hz; } setup_fifo_xfer(xfer, mas, slv->mode, spi); Loading include/linux/qcom-geni-se.h +48 −0 Original line number Diff line number Diff line Loading @@ -564,6 +564,41 @@ int se_geni_resources_on(struct se_geni_rsc *rsc); int geni_se_resources_init(struct se_geni_rsc *rsc, unsigned long ab, unsigned long ib); /** * geni_se_clk_tbl_get() - Get the clock table to program DFS * @rsc: Resource for which the clock table is requested. * @tbl: Table in which the output is returned. * * This function is called by the protocol drivers to determine the different * clock frequencies supported by Serail Engine Core Clock. The protocol * drivers use the output to determine the clock frequency index to be * programmed into DFS. * * Return: number of valid performance levels in the table on success, * standard Linux error codes on failure. */ int geni_se_clk_tbl_get(struct se_geni_rsc *rsc, unsigned long **tbl); /** * geni_se_clk_freq_match() - Get the matching or closest SE clock frequency * @rsc: Resource for which the clock frequency is requested. * @req_freq: Requested clock frequency. * @index: Index of the resultant frequency in the table. * @res_freq: Resultant frequency which matches or is closer to the * requested frequency. * @exact: Flag to indicate exact multiple requirement of the requested * frequency . * * This function is called by the protocol drivers to determine the matching * or closest frequency of the Serial Engine clock to be selected in order * to meet the performance requirements. * * Return: 0 on success, standard Linux error codes on failure. */ int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq, unsigned int *index, unsigned long *res_freq, bool exact); /** * geni_se_tx_dma_prep() - Prepare the Serial Engine for TX DMA transfer * @wrapper_dev: QUPv3 Wrapper Device to which the TX buffer is mapped. Loading Loading @@ -796,6 +831,19 @@ static inline int geni_se_resources_init(struct se_geni_rsc *rsc, return -ENXIO; } static inline int geni_se_clk_tbl_get(struct se_geni_rsc *rsc, unsigned long **tbl) { return -ENXIO; } static inline int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq, unsigned int *index, unsigned long *res_freq, bool exact) { return -ENXIO; } static inline int geni_se_tx_dma_prep(struct device *wrapper_dev, void __iomem *base, void *tx_buf, int tx_len, dma_addr_t *tx_dma) { Loading Loading
drivers/platform/msm/qcom-geni-se.c +110 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ #define GENI_SE_IOMMU_VA_SIZE (0xC0000000) #define NUM_LOG_PAGES 2 #define MAX_CLK_PERF_LEVEL 32 static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000, 100000000}; /** Loading @@ -52,6 +52,8 @@ static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000, 100000000}; * @cur_ib: Current Bus Instantaneous BW request value. * @bus_bw_set: Clock plan for the bus driver. * @cur_bus_bw_idx: Current index within the bus clock plan. * @num_clk_levels: Number of valid clock levels in clk_perf_tbl. * @clk_perf_tbl: Table of clock frequency input to Serial Engine clock. * @log_ctx: Logging context to hold the debug information */ struct geni_se_device { Loading @@ -72,6 +74,8 @@ struct geni_se_device { int bus_bw_set_size; unsigned long *bus_bw_set; int cur_bus_bw_idx; unsigned int num_clk_levels; unsigned long *clk_perf_tbl; void *log_ctx; }; Loading Loading @@ -808,6 +812,111 @@ int geni_se_resources_init(struct se_geni_rsc *rsc, } EXPORT_SYMBOL(geni_se_resources_init); /** * geni_se_clk_tbl_get() - Get the clock table to program DFS * @rsc: Resource for which the clock table is requested. * @tbl: Table in which the output is returned. * * This function is called by the protocol drivers to determine the different * clock frequencies supported by Serail Engine Core Clock. The protocol * drivers use the output to determine the clock frequency index to be * programmed into DFS. * * Return: number of valid performance levels in the table on success, * standard Linux error codes on failure. */ int geni_se_clk_tbl_get(struct se_geni_rsc *rsc, unsigned long **tbl) { struct geni_se_device *geni_se_dev; int i; unsigned long prev_freq = 0; if (unlikely(!rsc || !rsc->wrapper_dev || !rsc->se_clk || !tbl)) return -EINVAL; *tbl = NULL; geni_se_dev = dev_get_drvdata(rsc->wrapper_dev); if (unlikely(!geni_se_dev)) return -EPROBE_DEFER; if (geni_se_dev->clk_perf_tbl) { *tbl = geni_se_dev->clk_perf_tbl; return geni_se_dev->num_clk_levels; } geni_se_dev->clk_perf_tbl = kzalloc(sizeof(*geni_se_dev->clk_perf_tbl) * MAX_CLK_PERF_LEVEL, GFP_KERNEL); if (!geni_se_dev->clk_perf_tbl) return -ENOMEM; for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { geni_se_dev->clk_perf_tbl[i] = clk_round_rate(rsc->se_clk, prev_freq + 1); if (geni_se_dev->clk_perf_tbl[i] == prev_freq) { geni_se_dev->clk_perf_tbl[i] = 0; break; } prev_freq = geni_se_dev->clk_perf_tbl[i]; } geni_se_dev->num_clk_levels = i; *tbl = geni_se_dev->clk_perf_tbl; return geni_se_dev->num_clk_levels; } EXPORT_SYMBOL(geni_se_clk_tbl_get); /** * geni_se_clk_freq_match() - Get the matching or closest SE clock frequency * @rsc: Resource for which the clock frequency is requested. * @req_freq: Requested clock frequency. * @index: Index of the resultant frequency in the table. * @res_freq: Resultant frequency which matches or is closer to the * requested frequency. * @exact: Flag to indicate exact multiple requirement of the requested * frequency . * * This function is called by the protocol drivers to determine the matching * or closest frequency of the Serial Engine clock to be selected in order * to meet the performance requirements. * * Return: 0 on success, standard Linux error codes on failure. */ int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq, unsigned int *index, unsigned long *res_freq, bool exact) { unsigned long *tbl; int num_clk_levels; int i; num_clk_levels = geni_se_clk_tbl_get(rsc, &tbl); if (num_clk_levels < 0) return num_clk_levels; if (num_clk_levels == 0) return -EFAULT; *res_freq = 0; for (i = 0; i < num_clk_levels; i++) { if (!(tbl[i] % req_freq)) { *index = i; *res_freq = tbl[i]; return 0; } if (!(*res_freq) || ((tbl[i] > *res_freq) && (tbl[i] < req_freq))) { *index = i; *res_freq = tbl[i]; } } if (exact || !(*res_freq)) return -ENOKEY; return 0; } EXPORT_SYMBOL(geni_se_clk_freq_match); /** * geni_se_tx_dma_prep() - Prepare the Serial Engine for TX DMA transfer * @wrapper_dev: QUPv3 Wrapper Device to which the TX buffer is mapped. Loading
drivers/spi/spi-geni-qcom.c +10 −12 Original line number Diff line number Diff line Loading @@ -110,14 +110,6 @@ static struct spi_master *get_spi_master(struct device *dev) return spi; } static int get_sclk(u32 speed_hz, unsigned long *sclk_freq) { u32 root_freq[] = { 19200000 }; *sclk_freq = root_freq[0]; return 0; } static int do_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas) { unsigned long sclk_freq; Loading @@ -131,14 +123,20 @@ static int do_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas) clk_sel &= ~CLK_SEL_MSK; m_clk_cfg &= ~CLK_DIV_MSK; idx = get_sclk(speed_hz, &sclk_freq); if (idx < 0) return -EINVAL; ret = geni_se_clk_freq_match(&mas->spi_rsc, speed_hz, &idx, &sclk_freq, true); if (ret) { dev_err(mas->dev, "%s: Failed(%d) to find src clk for 0x%x\n", __func__, ret, speed_hz); return ret; } div = ((sclk_freq / SPI_OVERSAMPLING) / speed_hz); if (!div) return -EINVAL; dev_dbg(mas->dev, "%s: req %u sclk %lu, idx %d, div %d\n", __func__, speed_hz, sclk_freq, idx, div); clk_sel |= (idx & CLK_SEL_MSK); m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN); ret = clk_set_rate(rsc->se_clk, sclk_freq); Loading Loading @@ -362,13 +360,13 @@ static int spi_geni_transfer_one(struct spi_master *spi, reinit_completion(&mas->xfer_done); /* Speed and bits per word can be overridden per transfer */ if (xfer->speed_hz != mas->cur_speed_hz) { mas->cur_speed_hz = xfer->speed_hz; ret = do_spi_clk_cfg(mas->cur_speed_hz, mas); if (ret) { dev_err(mas->dev, "%s:Err setting clks:%d\n", __func__, ret); goto geni_transfer_one_exit; } mas->cur_speed_hz = xfer->speed_hz; } setup_fifo_xfer(xfer, mas, slv->mode, spi); Loading
include/linux/qcom-geni-se.h +48 −0 Original line number Diff line number Diff line Loading @@ -564,6 +564,41 @@ int se_geni_resources_on(struct se_geni_rsc *rsc); int geni_se_resources_init(struct se_geni_rsc *rsc, unsigned long ab, unsigned long ib); /** * geni_se_clk_tbl_get() - Get the clock table to program DFS * @rsc: Resource for which the clock table is requested. * @tbl: Table in which the output is returned. * * This function is called by the protocol drivers to determine the different * clock frequencies supported by Serail Engine Core Clock. The protocol * drivers use the output to determine the clock frequency index to be * programmed into DFS. * * Return: number of valid performance levels in the table on success, * standard Linux error codes on failure. */ int geni_se_clk_tbl_get(struct se_geni_rsc *rsc, unsigned long **tbl); /** * geni_se_clk_freq_match() - Get the matching or closest SE clock frequency * @rsc: Resource for which the clock frequency is requested. * @req_freq: Requested clock frequency. * @index: Index of the resultant frequency in the table. * @res_freq: Resultant frequency which matches or is closer to the * requested frequency. * @exact: Flag to indicate exact multiple requirement of the requested * frequency . * * This function is called by the protocol drivers to determine the matching * or closest frequency of the Serial Engine clock to be selected in order * to meet the performance requirements. * * Return: 0 on success, standard Linux error codes on failure. */ int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq, unsigned int *index, unsigned long *res_freq, bool exact); /** * geni_se_tx_dma_prep() - Prepare the Serial Engine for TX DMA transfer * @wrapper_dev: QUPv3 Wrapper Device to which the TX buffer is mapped. Loading Loading @@ -796,6 +831,19 @@ static inline int geni_se_resources_init(struct se_geni_rsc *rsc, return -ENXIO; } static inline int geni_se_clk_tbl_get(struct se_geni_rsc *rsc, unsigned long **tbl) { return -ENXIO; } static inline int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq, unsigned int *index, unsigned long *res_freq, bool exact) { return -ENXIO; } static inline int geni_se_tx_dma_prep(struct device *wrapper_dev, void __iomem *base, void *tx_buf, int tx_len, dma_addr_t *tx_dma) { Loading