[coreboot-gerrit] New patch to review for coreboot: 96365e7 ipq806x: add LPASS clock control driver

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Thu Apr 16 14:52:20 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/9758

-gerrit

commit 96365e7118c1161a5942d2b40068aca4377f68d8
Author: Vadim Bendebury <vbendeb at chromium.org>
Date:   Wed Feb 11 15:13:04 2015 -0800

    ipq806x: add LPASS clock control driver
    
    Add a clock control driver to initialize the clock tree inside the
    low-power audio subsystem. Depthcharge builds up on this to enable
    audio function on storm.
    
    The clock is hardcoded for 48KHz frame rate, two 16 bit channels.
    
    BRANCH=storm
    BUG=chrome-os-partner:35247
    
    TEST=with depthcharge patches applied and Using depthcharge CLI audio
         test program verified that the target generates sensible sounds
    
         audio 100 100
         audio 1000 5000
    
    Change-Id: I56513fc782657ade99b6e43b2d5d3141d27ecc4e
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: 0d4f408408aa38b2f0ee19b83ed490de39074760
    Original-Change-Id: If8ffc326698fcea17e05d536930d927ca553481f
    Original-Signed-off-by: Kenneth Westfield <kwestfie at codeaurora.org>
    Original-Signed-off-by: Vadim Bendebury <vbendeb at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/248830
    Original-Reviewed-by: Dylan Reid <dgreid at chromium.org>
---
 src/mainboard/google/storm/mainboard.c         |   8 +
 src/soc/qualcomm/ipq806x/Makefile.inc          |   1 +
 src/soc/qualcomm/ipq806x/include/soc/clock.h   |   1 +
 src/soc/qualcomm/ipq806x/include/soc/lcc-reg.h | 341 +++++++++++++++++++++++++
 src/soc/qualcomm/ipq806x/lcc.c                 | 316 +++++++++++++++++++++++
 5 files changed, 667 insertions(+)

diff --git a/src/mainboard/google/storm/mainboard.c b/src/mainboard/google/storm/mainboard.c
index f83cfe9..db743cf 100644
--- a/src/mainboard/google/storm/mainboard.c
+++ b/src/mainboard/google/storm/mainboard.c
@@ -98,6 +98,14 @@ static void mainboard_init(device_t dev)
 	/* Copy WIFI calibration data into CBMEM. */
 	cbmem_add_vpd_calibration_data();
 #endif
+
+	/*
+	 * Make sure bootloader can issue sounds The frequency is calculated
+	 * as "<frame_rate> * <bit_width> * <channels> * 4", i.e.
+	 *
+	 * 48000 * 2 * 16 * 4 = 6144000
+	 */
+	audio_clock_config(6144000);
 }
 
 static void mainboard_enable(device_t dev)
diff --git a/src/soc/qualcomm/ipq806x/Makefile.inc b/src/soc/qualcomm/ipq806x/Makefile.inc
index e0f014a..80bd058 100644
--- a/src/soc/qualcomm/ipq806x/Makefile.inc
+++ b/src/soc/qualcomm/ipq806x/Makefile.inc
@@ -44,6 +44,7 @@ ramstage-y += blobs_init.c
 ramstage-y += cbmem.c
 ramstage-y += clock.c
 ramstage-y += gpio.c
+ramstage-y += lcc.c
 ramstage-y += soc.c
 ramstage-$(CONFIG_SPI_FLASH) += spi.c
 ramstage-y += timer.c
diff --git a/src/soc/qualcomm/ipq806x/include/soc/clock.h b/src/soc/qualcomm/ipq806x/include/soc/clock.h
index 837b831..ab50d3f 100644
--- a/src/soc/qualcomm/ipq806x/include/soc/clock.h
+++ b/src/soc/qualcomm/ipq806x/include/soc/clock.h
@@ -192,5 +192,6 @@ void uart_clock_config(unsigned int gsbi_port, unsigned int m, unsigned int n,
 		unsigned int d, unsigned int clk_dummy);
 void nand_clock_config(void);
 void usb_clock_config(void);
+int audio_clock_config(unsigned frequency);
 
 #endif  /*  __PLATFORM_IPQ860X_CLOCK_H_ */
diff --git a/src/soc/qualcomm/ipq806x/include/soc/lcc-reg.h b/src/soc/qualcomm/ipq806x/include/soc/lcc-reg.h
new file mode 100644
index 0000000..2827ac9
--- /dev/null
+++ b/src/soc/qualcomm/ipq806x/include/soc/lcc-reg.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_CLOCK_IPQ806X_LCC_REG_H__
+#define __DRIVERS_CLOCK_IPQ806X_LCC_REG_H__
+
+#define MSM_GCC_BASE			0x00900000
+#define MSM_LPASS_LCC_BASE		0x28000000
+
+/* GCC APCS Configuration/Control */
+
+#define GCC_PLL_APCS_REG		0x34C0
+
+#define GCC_PLL_APCS_PLL4_MASK		0x10
+#define GCC_PLL_APCS_PLL4_SHIFT		4
+#define GCC_PLL_APCS_PLL4_ENABLE	(1 << GCC_PLL_APCS_PLL4_SHIFT)
+
+/* LCC PLL0 Configuration/Control */
+
+#define LCC_PLL0_MODE_REG		0x00
+#define LCC_PLL0_L_REG			0x04
+#define LCC_PLL0_M_REG			0x08
+#define LCC_PLL0_N_REG			0x0C
+#define LCC_PLL0_CFG_REG		0x14
+#define LCC_PLL0_STAT_REG		0x18
+
+#define LCC_PLL0_MODE_FSM_RESET_MASK	0x200000
+#define LCC_PLL0_MODE_FSM_RESET_SHIFT	21
+#define LCC_PLL0_MODE_FSM_RESET_ASSERT	(1 << LCC_PLL0_MODE_FSM_RESET_SHIFT)
+
+#define LCC_PLL0_MODE_FSM_VOTE_MASK	0x100000
+#define LCC_PLL0_MODE_FSM_VOTE_SHIFT	20
+#define LCC_PLL0_MODE_FSM_VOTE_ENABLE	(1 << LCC_PLL0_MODE_FSM_VOTE_SHIFT)
+
+#define LCC_PLL0_MODE_BIAS_CNT_MASK	0xFC000
+#define LCC_PLL0_MODE_BIAS_CNT_SHIFT	14
+
+#define LCC_PLL0_MODE_LOCK_CNT_MASK	0x3F00
+#define LCC_PLL0_MODE_LOCK_CNT_SHIFT	8
+
+#define LCC_PLL0_MODE_XO_SEL_MASK	0x30
+#define LCC_PLL0_MODE_XO_SEL_SHIFT	4
+#define LCC_PLL0_MODE_XO_SEL_PXO	(0 << LCC_PLL0_MODE_XO_SEL_SHIFT)
+#define LCC_PLL0_MODE_XO_SEL_MXO	(1 << LCC_PLL0_MODE_XO_SEL_SHIFT)
+#define LCC_PLL0_MODE_XO_SEL_CXO	(2 << LCC_PLL0_MODE_XO_SEL_SHIFT)
+
+#define LCC_PLL0_MODE_TEST_MASK		0x8
+#define LCC_PLL0_MODE_TEST_SHIFT	3
+#define LCC_PLL0_MODE_TEST_ENABLE	(1 << LCC_PLL0_MODE_TEST_SHIFT)
+
+#define LCC_PLL0_MODE_RESET_MASK	0x4
+#define LCC_PLL0_MODE_RESET_SHIFT	2
+#define LCC_PLL0_MODE_RESET_DEASSERT	(1 << LCC_PLL0_MODE_RESET_SHIFT)
+
+#define LCC_PLL0_MODE_BYPASS_MASK	0x2
+#define LCC_PLL0_MODE_BYPASS_SHIFT	1
+#define LCC_PLL0_MODE_BYPASS_DISABLE	(1 << LCC_PLL0_MODE_BYPASS_SHIFT)
+
+#define LCC_PLL0_MODE_OUTPUT_MASK	0x1
+#define LCC_PLL0_MODE_OUTPUT_SHIFT	0
+#define LCC_PLL0_MODE_OUTPUT_ENABLE	(1 << LCC_PLL0_MODE_OUTPUT_SHIFT)
+
+#define LCC_PLL0_L_MASK			0x3FF
+#define LCC_PLL0_L_SHIFT		0
+
+#define LCC_PLL0_M_MASK			0x7FFFF
+#define LCC_PLL0_M_SHIFT		0
+
+#define LCC_PLL0_N_MASK			0x7FFFF
+#define LCC_PLL0_N_SHIFT		0
+
+#define LCC_PLL0_CFG_LV_MAIN_MASK	0x800000
+#define LCC_PLL0_CFG_LV_MAIN_SHIFT	23
+#define LCC_PLL0_CFG_LV_MAIN_ENABLE	(1 << LCC_PLL0_CFG_LV_MAIN_SHIFT)
+
+#define LCC_PLL0_CFG_FRAC_MASK		0x400000
+#define LCC_PLL0_CFG_FRAC_SHIFT		22
+#define LCC_PLL0_CFG_FRAC_ENABLE	(1 << LCC_PLL0_CFG_FRAC_SHIFT)
+
+#define LCC_PLL0_CFG_POSTDIV_MASK	0x300000
+#define LCC_PLL0_CFG_POSTDIV_SHIFT	20
+#define LCC_PLL0_CFG_POSTDIV_DIV1	(0 << LCC_PLL0_CFG_POSTDIV_SHIFT)
+#define LCC_PLL0_CFG_POSTDIV_DIV2	(1 << LCC_PLL0_CFG_POSTDIV_SHIFT)
+#define LCC_PLL0_CFG_POSTDIV_DIV4	(2 << LCC_PLL0_CFG_POSTDIV_SHIFT)
+
+#define LCC_PLL0_CFG_PREDIV_MASK	0x80000
+#define LCC_PLL0_CFG_PREDIV_SHIFT	19
+#define LCC_PLL0_CFG_PREDIV_DIV1	(0 << LCC_PLL0_CFG_PREDIV_SHIFT)
+#define LCC_PLL0_CFG_PREDIV_DIV2	(1 << LCC_PLL0_CFG_PREDIV_SHIFT)
+
+#define LCC_PLL0_CFG_VCO_SEL_MASK	0x30000
+#define LCC_PLL0_CFG_VCO_SEL_SHIFT	16
+#define LCC_PLL0_CFG_VCO_SEL_LOW	(0 << LCC_PLL0_CFG_VCO_SEL_SHIFT)
+#define LCC_PLL0_CFG_VCO_SEL_MED	(1 << LCC_PLL0_CFG_VCO_SEL_SHIFT)
+#define LCC_PLL0_CFG_VCO_SEL_HIGH	(2 << LCC_PLL0_CFG_VCO_SEL_SHIFT)
+
+#define LCC_PLL0_STAT_ACTIVE_MASK	0x10000
+#define LCC_PLL0_STAT_ACTIVE_SHIFT	16
+#define LCC_PLL0_STAT_ACTIVE_SET	(1 << LCC_PLL0_STAT_ACTIVE_SHIFT)
+
+#define LCC_PLL0_STAT_NOCLK_MASK	0x1
+#define LCC_PLL0_STAT_NOCLK_SHIFT	0
+#define LCC_PLL0_STAT_NOCLK_SET		(1 << LCC_PLL0_STAT_NOCLK_SHIFT)
+
+/* LCC AHBIX Configuration/Control */
+
+#define LCC_AHBIX_NS_REG		0x38
+#define LCC_AHBIX_MD_REG		0x3C
+#define LCC_AHBIX_STAT_REG		0x44
+
+#define LCC_AHBIX_NS_N_VAL_MASK		0xFF000000
+#define LCC_AHBIX_NS_N_VAL_SHIFT	24
+
+#define LCC_AHBIX_NS_CRC_MASK		0x800
+#define LCC_AHBIX_NS_CRC_SHIFT		11
+#define LCC_AHBIX_NS_CRC_ENABLE		(1 << LCC_AHBIX_NS_CRC_SHIFT)
+
+#define LCC_AHBIX_NS_GFM_SEL_MASK	0x400
+#define LCC_AHBIX_NS_GFM_SEL_SHIFT	10
+#define LCC_AHBIX_NS_GFM_SEL_PXO	(0 << LCC_AHBIX_NS_GFM_SEL_SHIFT)
+#define LCC_AHBIX_NS_GFM_SEL_MNC	(1 << LCC_AHBIX_NS_GFM_SEL_SHIFT)
+
+#define LCC_AHBIX_NS_MNC_CLK_MASK	0x200
+#define LCC_AHBIX_NS_MNC_CLK_SHIFT	9
+#define LCC_AHBIX_NS_MNC_CLK_ENABLE	(1 << LCC_AHBIX_NS_MNC_CLK_SHIFT)
+
+#define LCC_AHBIX_NS_MNC_MASK		0x100
+#define LCC_AHBIX_NS_MNC_SHIFT		8
+#define LCC_AHBIX_NS_MNC_ENABLE		(1 << LCC_AHBIX_NS_MNC_SHIFT)
+
+#define LCC_AHBIX_NS_MNC_RESET_MASK	0x80
+#define LCC_AHBIX_NS_MNC_RESET_SHIFT	7
+#define LCC_AHBIX_NS_MNC_RESET_ASSERT	(1 << LCC_AHBIX_NS_MNC_RESET_SHIFT)
+
+#define LCC_AHBIX_NS_MNC_MODE_MASK	0x60
+#define LCC_AHBIX_NS_MNC_MODE_SHIFT	5
+#define LCC_AHBIX_NS_MNC_MODE_BYPASS	(0 << LCC_AHBIX_NS_MNC_MODE_SHIFT)
+#define LCC_AHBIX_NS_MNC_MODE_SWALLOW	(1 << LCC_AHBIX_NS_MNC_MODE_SHIFT)
+#define LCC_AHBIX_NS_MNC_MODE_DUAL	(2 << LCC_AHBIX_NS_MNC_MODE_SHIFT)
+#define LCC_AHBIX_NS_MNC_MODE_SINGLE	(3 << LCC_AHBIX_NS_MNC_MODE_SHIFT)
+
+#define LCC_AHBIX_NS_PREDIV_MASK	0x18
+#define LCC_AHBIX_NS_PREDIV_SHIFT	3
+#define LCC_AHBIX_NS_PREDIV_BYPASS	(0 << LCC_AHBIX_NS_PREDIV_SHIFT)
+#define LCC_AHBIX_NS_PREDIV_DIV2	(1 << LCC_AHBIX_NS_PREDIV_SHIFT)
+#define LCC_AHBIX_NS_PREDIV_DIV4	(3 << LCC_AHBIX_NS_PREDIV_SHIFT)
+
+#define LCC_AHBIX_NS_MN_SRC_MASK	0x7
+#define LCC_AHBIX_NS_MN_SRC_SHIFT	0
+#define LCC_AHBIX_NS_MN_SRC_PXO		(0 << LCC_AHBIX_NS_MN_SRC_SHIFT)
+#define LCC_AHBIX_NS_MN_SRC_CXO		(1 << LCC_AHBIX_NS_MN_SRC_SHIFT)
+#define LCC_AHBIX_NS_MN_SRC_LPA		(2 << LCC_AHBIX_NS_MN_SRC_SHIFT)
+#define LCC_AHBIX_NS_MN_SRC_SEC		(3 << LCC_AHBIX_NS_MN_SRC_SHIFT)
+#define LCC_AHBIX_NS_MN_SRC_CTEST	(6 << LCC_AHBIX_NS_MN_SRC_SHIFT)
+#define LCC_AHBIX_NS_MN_SRC_PTEST	(7 << LCC_AHBIX_NS_MN_SRC_SHIFT)
+
+#define LCC_AHBIX_MD_M_VAL_MASK		0xFF00
+#define LCC_AHBIX_MD_M_VAL_SHIFT	8
+
+#define LCC_AHBIX_MD_NOT_2D_VAL_MASK	0xFF
+#define LCC_AHBIX_MD_NOT_2D_VAL_SHIFT	0
+
+#define LCC_AHBIX_STAT_AHB_CLK_MASK	0x400
+#define LCC_AHBIX_STAT_AHB_CLK_SHIFT	10
+#define LCC_AHBIX_STAT_AHB_CLK_ON	(1 << LCC_AHBIX_STAT_AHB_CLK_SHIFT)
+
+#define LCC_AHBIX_STAT_AIF_CLK_MASK	0x200
+#define LCC_AHBIX_STAT_AIF_CLK_SHIFT	9
+#define LCC_AHBIX_STAT_AIF_CLK_ON	(1 << LCC_AHBIX_STAT_AIF_CLK_SHIFT)
+
+#define LCC_AHBIX_STAT_FAB2_CLK_MASK	0x40
+#define LCC_AHBIX_STAT_FAB2_CLK_SHIFT	6
+#define LCC_AHBIX_STAT_FAB2_CLK_ON	(1 << LCC_AHBIX_STAT_FAB2_CLK_SHIFT)
+
+#define LCC_AHBIX_STAT_2FAB_CLK_MASK	0x20
+#define LCC_AHBIX_STAT_2FAB_CLK_SHIFT	5
+#define LCC_AHBIX_STAT_2FAB_CLK_ON	(1 << LCC_AHBIX_STAT_2FAB_CLK_SHIFT)
+
+/* LCC MI2S Configuration/Control */
+
+#define LCC_MI2S_NS_REG			0x48
+#define LCC_MI2S_MD_REG			0x4C
+#define LCC_MI2S_STAT_REG		0x50
+
+#define LCC_MI2S_NS_N_VAL_MASK		0xFF000000
+#define LCC_MI2S_NS_N_VAL_SHIFT		24
+
+#define LCC_MI2S_NS_RESET_MASK		0x80000
+#define LCC_MI2S_NS_RESET_SHIFT		19
+#define LCC_MI2S_NS_RESET_ASSERT	(1 << LCC_MI2S_NS_RESET_SHIFT)
+
+#define LCC_MI2S_NS_OSR_INV_MASK	0x40000
+#define LCC_MI2S_NS_OSR_INV_SHIFT	18
+#define LCC_MI2S_NS_OSR_INV_ENABLE	(1 << LCC_MI2S_NS_OSR_INV_SHIFT)
+
+#define LCC_MI2S_NS_OSR_CXC_MASK	0x20000
+#define LCC_MI2S_NS_OSR_CXC_SHIFT	17
+#define LCC_MI2S_NS_OSR_CXC_ENABLE	(1 << LCC_MI2S_NS_OSR_CXC_SHIFT)
+
+#define LCC_MI2S_NS_BIT_INV_MASK	0x10000
+#define LCC_MI2S_NS_BIT_INV_SHIFT	16
+#define LCC_MI2S_NS_BIT_INV_ENABLE	(1 << LCC_MI2S_NS_BIT_INV_SHIFT)
+
+#define LCC_MI2S_NS_BIT_CXC_MASK	0x8000
+#define LCC_MI2S_NS_BIT_CXC_SHIFT	15
+#define LCC_MI2S_NS_BIT_CXC_ENABLE	(1 << LCC_MI2S_NS_BIT_CXC_SHIFT)
+
+#define LCC_MI2S_NS_BIT_SRC_MASK	0x4000
+#define LCC_MI2S_NS_BIT_SRC_SHIFT	14
+#define LCC_MI2S_NS_BIT_SRC_MASTER	(0 << LCC_MI2S_NS_BIT_SRC_SHIFT)
+#define LCC_MI2S_NS_BIT_SRC_SLAVE	(1 << LCC_MI2S_NS_BIT_SRC_SHIFT)
+
+#define LCC_MI2S_NS_BIT_DIV_MASK	0x3C00
+#define LCC_MI2S_NS_BIT_DIV_SHIFT	10
+#define LCC_MI2S_NS_BIT_DIV_BYPASS	(0  << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV2	(1  << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV3	(2  << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV4	(3  << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV5	(4  << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV6	(5  << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV7	(6  << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV8	(7  << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV9	(8  << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV10	(9  << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV11	(10 << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV12	(11 << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV13	(12 << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV14	(13 << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV15	(14 << LCC_MI2S_NS_BIT_DIV_SHIFT)
+#define LCC_MI2S_NS_BIT_DIV_DIV16	(15 << LCC_MI2S_NS_BIT_DIV_SHIFT)
+
+#define LCC_MI2S_NS_MNC_CLK_MASK	0x200
+#define LCC_MI2S_NS_MNC_CLK_SHIFT	9
+#define LCC_MI2S_NS_MNC_CLK_ENABLE	(1 << LCC_MI2S_NS_MNC_CLK_SHIFT)
+
+#define LCC_MI2S_NS_MNC_MASK		0x100
+#define LCC_MI2S_NS_MNC_SHIFT		8
+#define LCC_MI2S_NS_MNC_ENABLE		(1 << LCC_MI2S_NS_MNC_SHIFT)
+
+#define LCC_MI2S_NS_MNC_RESET_MASK	0x80
+#define LCC_MI2S_NS_MNC_RESET_SHIFT	7
+#define LCC_MI2S_NS_MNC_RESET_ASSERT	(1 << LCC_MI2S_NS_MNC_RESET_SHIFT)
+
+#define LCC_MI2S_NS_MNC_MODE_MASK	0x60
+#define LCC_MI2S_NS_MNC_MODE_SHIFT	5
+#define LCC_MI2S_NS_MNC_MODE_BYPASS	(0 << LCC_MI2S_NS_MNC_MODE_SHIFT)
+#define LCC_MI2S_NS_MNC_MODE_SWALLOW	(1 << LCC_MI2S_NS_MNC_MODE_SHIFT)
+#define LCC_MI2S_NS_MNC_MODE_DUAL	(2 << LCC_MI2S_NS_MNC_MODE_SHIFT)
+#define LCC_MI2S_NS_MNC_MODE_SINGLE	(3 << LCC_MI2S_NS_MNC_MODE_SHIFT)
+
+#define LCC_MI2S_NS_PREDIV_MASK		0x18
+#define LCC_MI2S_NS_PREDIV_SHIFT	3
+#define LCC_MI2S_NS_PREDIV_BYPASS	(0 << LCC_MI2S_NS_PREDIV_SHIFT)
+#define LCC_MI2S_NS_PREDIV_DIV2		(1 << LCC_MI2S_NS_PREDIV_SHIFT)
+#define LCC_MI2S_NS_PREDIV_DIV4		(3 << LCC_MI2S_NS_PREDIV_SHIFT)
+
+#define LCC_MI2S_NS_MN_SRC_MASK		0x7
+#define LCC_MI2S_NS_MN_SRC_SHIFT	0
+#define LCC_MI2S_NS_MN_SRC_PXO		(0 << LCC_MI2S_NS_MN_SRC_SHIFT)
+#define LCC_MI2S_NS_MN_SRC_CXO		(1 << LCC_MI2S_NS_MN_SRC_SHIFT)
+#define LCC_MI2S_NS_MN_SRC_LPA		(2 << LCC_MI2S_NS_MN_SRC_SHIFT)
+#define LCC_MI2S_NS_MN_SRC_SEC		(3 << LCC_MI2S_NS_MN_SRC_SHIFT)
+#define LCC_MI2S_NS_MN_SRC_CTEST	(6 << LCC_MI2S_NS_MN_SRC_SHIFT)
+#define LCC_MI2S_NS_MN_SRC_PTEST	(7 << LCC_MI2S_NS_MN_SRC_SHIFT)
+
+#define LCC_MI2S_MD_M_VAL_MASK		0xFF00
+#define LCC_MI2S_MD_M_VAL_SHIFT		8
+
+#define LCC_MI2S_MD_NOT_2D_VAL_MASK	0xFF
+#define LCC_MI2S_MD_NOT_2D_VAL_SHIFT	0
+
+#define LCC_MI2S_STAT_OSR_CLK_MASK	0x2
+#define LCC_MI2S_STAT_OSR_CLK_SHIFT	1
+#define LCC_MI2S_STAT_OSR_CLK_ON	(1 << LCC_MI2S_STAT_OSR_CLK_SHIFT)
+
+#define LCC_MI2S_STAT_BIT_CLK_MASK	0x1
+#define LCC_MI2S_STAT_BIT_CLK_SHIFT	0
+#define LCC_MI2S_STAT_BIT_CLK_ON	(1 << LCC_MI2S_STAT_BIT_CLK_SHIFT)
+
+/* LCC PLL Configuration/Control */
+
+#define LCC_PLL_PCLK_REG		0xC4
+#define LCC_PLL_SCLK_REG		0xC8
+
+#define LCC_PLL_PCLK_RESET_MASK		0x2
+#define LCC_PLL_PCLK_RESET_SHIFT	1
+#define LCC_PLL_PCLK_RESET_ASSERT	(1 << LCC_PLL_PCLK_RESET_SHIFT)
+
+#define LCC_PLL_PCLK_SRC_MASK		0x1
+#define LCC_PLL_PCLK_SRC_SHIFT		0
+#define LCC_PLL_PCLK_SRC_PXO		(0 << LCC_PLL_PCLK_SRC_SHIFT)
+#define LCC_PLL_PCLK_SRC_PRI		(1 << LCC_PLL_PCLK_SRC_SHIFT)
+
+#define LCC_PLL_SCLK_RESET_MASK		0x10
+#define LCC_PLL_SCLK_RESET_SHIFT	4
+#define LCC_PLL_SCLK_RESET_ASSERT	(1 << LCC_PLL_SCLK_RESET_SHIFT)
+
+#define LCC_PLL_SCLK_DIV_MASK		0xC
+#define LCC_PLL_SCLK_DIV_SHIFT		2
+#define LCC_PLL_SCLK_DIV_BYPASS		(0 << LCC_PLL_SCLK_DIV_SHIFT)
+#define LCC_PLL_SCLK_DIV_DIV2		(1 << LCC_PLL_SCLK_DIV_SHIFT)
+#define LCC_PLL_SCLK_DIV_DIV3		(2 << LCC_PLL_SCLK_DIV_SHIFT)
+#define LCC_PLL_SCLK_DIV_DIV4		(3 << LCC_PLL_SCLK_DIV_SHIFT)
+
+#define LCC_PLL_SCLK_XO_MASK		0x2
+#define LCC_PLL_SCLK_XO_SHIFT		1
+#define LCC_PLL_SCLK_XO_PXO		(0 << LCC_PLL_SCLK_XO_SHIFT)
+#define LCC_PLL_SCLK_XO_SEC		(1 << LCC_PLL_SCLK_XO_SHIFT)
+
+#define LCC_PLL_SCLK_MUX_MASK		0x1
+#define LCC_PLL_SCLK_MUX_SHIFT		0
+#define LCC_PLL_SCLK_MUX_PLL1		(0 << LCC_PLL_SCLK_MUX_SHIFT)
+#define LCC_PLL_SCLK_MUX_PLL0		(1 << LCC_PLL_SCLK_MUX_SHIFT)
+
+#endif /* __DRIVERS_CLOCK_IPQ806X_LCC_REG_H__ */
diff --git a/src/soc/qualcomm/ipq806x/lcc.c b/src/soc/qualcomm/ipq806x/lcc.c
new file mode 100644
index 0000000..978526d
--- /dev/null
+++ b/src/soc/qualcomm/ipq806x/lcc.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <delay.h>
+#include <console/console.h>
+#include <soc/clock.h>
+#include <soc/lcc-reg.h>
+#include <arch/io.h>
+
+typedef struct {
+	void *gcc_apcs_regs;
+	void *lcc_pll0_regs;
+	void *lcc_ahbix_regs;
+	void *lcc_mi2s_regs;
+	void *lcc_pll_regs;
+} Ipq806xLccClocks;
+
+typedef struct __attribute__((packed)) {
+	uint32_t apcs;
+} Ipq806xLccGccRegs;
+
+typedef struct __attribute__((packed)) {
+	uint32_t mode;
+	uint32_t l_val;
+	uint32_t m_val;
+	uint32_t n_val;
+	uint32_t UNUSED;
+	uint32_t config;
+	uint32_t status;
+} Ipq806xLccPll0Regs;
+
+typedef struct __attribute__((packed)) {
+	uint32_t ns;
+	uint32_t md;
+	uint32_t UNUSED;
+	uint32_t status;
+} Ipq806xLccAhbixRegs;
+
+typedef struct __attribute__((packed)) {
+	uint32_t ns;
+	uint32_t md;
+	uint32_t status;
+} Ipq806xLccMi2sRegs;
+
+typedef struct __attribute__((packed)) {
+	uint32_t pri;
+	uint32_t sec;
+} Ipq806xLccPllRegs;
+
+struct lcc_freq_tbl {
+	unsigned freq;
+	unsigned pd;
+	unsigned m;
+	unsigned n;
+	unsigned d;
+};
+
+static const struct lcc_freq_tbl lcc_mi2s_freq_tbl[] = {
+	{  1024000, 4,  1,  96, 8 },
+	{  1411200, 4,  2, 139, 8 },
+	{  1536000, 4,  1,  64, 8 },
+	{  2048000, 4,  1,  48, 8 },
+	{  2116800, 4,  2,  93, 8 },
+	{  2304000, 4,  2,  85, 8 },
+	{  2822400, 4,  6, 209, 8 },
+	{  3072000, 4,  1,  32, 8 },
+	{  3175200, 4,  1,  31, 8 },
+	{  4096000, 4,  1,  24, 8 },
+	{  4233600, 4,  9, 209, 8 },
+	{  4608000, 4,  3,  64, 8 },
+	{  5644800, 4, 12, 209, 8 },
+	{  6144000, 4,  1,  16, 8 },
+	{  6350400, 4,  2,  31, 8 },
+	{  8192000, 4,  1,  12, 8 },
+	{  8467200, 4, 18, 209, 8 },
+	{  9216000, 4,  3,  32, 8 },
+	{ 11289600, 4, 24, 209, 8 },
+	{ 12288000, 4,  1,   8, 8 },
+	{ 12700800, 4, 27, 209, 8 },
+	{ 13824000, 4,  9,  64, 8 },
+	{ 16384000, 4,  1,   6, 8 },
+	{ 16934400, 4, 41, 238, 8 },
+	{ 18432000, 4,  3,  16, 8 },
+	{ 22579200, 2, 24, 209, 8 },
+	{ 24576000, 4,  1,   4, 8 },
+	{ 27648000, 4,  9,  32, 8 },
+	{ 33868800, 4, 41, 119, 8 },
+	{ 36864000, 4,  3,   8, 8 },
+	{ 45158400, 1, 24, 209, 8 },
+	{ 49152000, 4,  1,   2, 8 },
+	{ 50803200, 1, 27, 209, 8 },
+	{ }
+};
+
+static int lcc_init_enable_pll0(Ipq806xLccClocks *bus)
+{
+	Ipq806xLccGccRegs *gcc_regs = bus->gcc_apcs_regs;
+	Ipq806xLccPll0Regs *pll0_regs = bus->lcc_pll0_regs;
+	Ipq806xLccPllRegs *pll_regs = bus->lcc_pll_regs;
+	uint32_t regval;
+
+	regval = 0;
+	regval = 15 << LCC_PLL0_L_SHIFT & LCC_PLL0_L_MASK;
+	writel(regval, &pll0_regs->l_val);
+
+	regval = 0;
+	regval = 145 << LCC_PLL0_M_SHIFT & LCC_PLL0_M_MASK;
+	writel(regval, &pll0_regs->m_val);
+
+	regval = 0;
+	regval = 199 << LCC_PLL0_N_SHIFT & LCC_PLL0_N_MASK;
+	writel(regval, &pll0_regs->n_val);
+
+	regval = 0;
+	regval |= LCC_PLL0_CFG_LV_MAIN_ENABLE;
+	regval |= LCC_PLL0_CFG_FRAC_ENABLE;
+	writel(regval, &pll0_regs->config);
+
+	regval = 0;
+	regval |= LCC_PLL_PCLK_SRC_PRI;
+	writel(regval, &pll_regs->pri);
+
+	regval = 0;
+	regval |= 1 << LCC_PLL0_MODE_BIAS_CNT_SHIFT &
+			LCC_PLL0_MODE_BIAS_CNT_MASK;
+	regval |= 8 << LCC_PLL0_MODE_LOCK_CNT_SHIFT &
+			LCC_PLL0_MODE_LOCK_CNT_MASK;
+	writel(regval, &pll0_regs->mode);
+
+	regval = readl(&gcc_regs->apcs);
+	regval |= GCC_PLL_APCS_PLL4_ENABLE;
+	writel(regval, &gcc_regs->apcs);
+
+	regval = readl(&pll0_regs->mode);
+	regval |= LCC_PLL0_MODE_FSM_VOTE_ENABLE;
+	writel(regval, &pll0_regs->mode);
+
+	mdelay(1);
+
+	regval = readl(&pll0_regs->status);
+	if (regval & LCC_PLL0_STAT_ACTIVE_MASK)
+		return 0;
+
+	printk(BIOS_ERR, "%s: error enabling PLL4 clock\n", __func__);
+	return 1;
+}
+
+static int lcc_init_enable_ahbix(Ipq806xLccClocks *bus)
+{
+	Ipq806xLccAhbixRegs *ahbix_regs = bus->lcc_ahbix_regs;
+	uint32_t regval;
+
+	regval = 0;
+	regval |= 1 << LCC_AHBIX_MD_M_VAL_SHIFT & LCC_AHBIX_MD_M_VAL_MASK;
+	regval |= 252 << LCC_AHBIX_MD_NOT_2D_VAL_SHIFT &
+			LCC_AHBIX_MD_NOT_2D_VAL_MASK;
+	writel(regval, &ahbix_regs->md);
+
+	regval = 0;
+	regval |= 253 << LCC_AHBIX_NS_N_VAL_SHIFT & LCC_AHBIX_NS_N_VAL_MASK;
+	regval |= LCC_AHBIX_NS_CRC_ENABLE;
+	regval |= LCC_AHBIX_NS_GFM_SEL_MNC;
+	regval |= LCC_AHBIX_NS_MNC_CLK_ENABLE;
+	regval |= LCC_AHBIX_NS_MNC_ENABLE;
+	regval |= LCC_AHBIX_NS_MNC_MODE_DUAL;
+	regval |= LCC_AHBIX_NS_PREDIV_BYPASS;
+	regval |= LCC_AHBIX_NS_MN_SRC_LPA;
+	writel(regval, &ahbix_regs->ns);
+
+	mdelay(1);
+
+	regval = readl(&ahbix_regs->status);
+	if (regval & LCC_AHBIX_STAT_AIF_CLK_MASK)
+		return 0;
+
+	printk(BIOS_ERR, "%s: error enabling AHBIX clock\n", __func__);
+	return 1;
+}
+
+static int lcc_init_mi2s(Ipq806xLccClocks *bus, unsigned freq)
+{
+	Ipq806xLccMi2sRegs *mi2s_regs = bus->lcc_mi2s_regs;
+	uint32_t regval;
+	uint8_t pd, m, n, d;
+	unsigned i;
+
+	i = 0;
+	while (lcc_mi2s_freq_tbl[i].freq != 0) {
+		if (lcc_mi2s_freq_tbl[i].freq == freq)
+			break;
+		++i;
+	}
+	if (lcc_mi2s_freq_tbl[i].freq == 0) {
+		printk(BIOS_ERR, "%s: invalid frequency given: %u\n",
+		       __func__, freq);
+		return 1;
+	}
+
+	switch (lcc_mi2s_freq_tbl[i].pd) {
+	case 1:
+		pd = LCC_MI2S_NS_PREDIV_BYPASS;
+		break;
+	case 2:
+		pd = LCC_MI2S_NS_PREDIV_DIV2;
+		break;
+	case 4:
+		pd = LCC_MI2S_NS_PREDIV_DIV4;
+		break;
+	default:
+		printk(BIOS_ERR, "%s: invalid prediv found: %u\n", __func__,
+				lcc_mi2s_freq_tbl[i].pd);
+		return 1;
+	}
+
+	m = lcc_mi2s_freq_tbl[i].m;
+	n = ~(lcc_mi2s_freq_tbl[i].n - m);
+	d = ~(lcc_mi2s_freq_tbl[i].d * 2);
+
+	regval = 0;
+	regval |= m << LCC_MI2S_MD_M_VAL_SHIFT & LCC_MI2S_MD_M_VAL_MASK;
+	regval |= d << LCC_MI2S_MD_NOT_2D_VAL_SHIFT &
+			LCC_MI2S_MD_NOT_2D_VAL_MASK;
+	writel(regval, &mi2s_regs->md);
+
+	regval = 0;
+	regval |= n << LCC_MI2S_NS_N_VAL_SHIFT & LCC_MI2S_NS_N_VAL_MASK;
+	regval |= LCC_MI2S_NS_BIT_DIV_DIV4;
+	regval |= LCC_MI2S_NS_MNC_CLK_ENABLE;
+	regval |= LCC_MI2S_NS_MNC_ENABLE;
+	regval |= LCC_MI2S_NS_MNC_MODE_DUAL;
+	regval |= pd;
+	regval |= LCC_MI2S_NS_MN_SRC_LPA;
+	writel(regval, &mi2s_regs->ns);
+
+	return 0;
+}
+
+static int lcc_enable_mi2s(Ipq806xLccClocks *bus)
+{
+	Ipq806xLccMi2sRegs *mi2s_regs = bus->lcc_mi2s_regs;
+	uint32_t regval;
+
+	regval = readl(&mi2s_regs->ns);
+	regval |= LCC_MI2S_NS_OSR_CXC_ENABLE;
+	regval |= LCC_MI2S_NS_BIT_CXC_ENABLE;
+	writel(regval, &mi2s_regs->ns);
+
+	udelay(10);
+
+	regval = readl(&mi2s_regs->status);
+	if (regval & LCC_MI2S_STAT_OSR_CLK_MASK)
+		if (regval & LCC_MI2S_STAT_BIT_CLK_MASK)
+			return 0;
+
+	printk(BIOS_ERR, "%s: error enabling MI2S clocks: %u\n",
+	       __func__, regval);
+	return 1;
+}
+
+int audio_clock_config(unsigned frequency)
+{
+	Ipq806xLccClocks *bus = malloc(sizeof(*bus));
+
+	if (!bus) {
+		printk(BIOS_ERR, "%s: failed to allocate bus structure\n",
+		       __func__);
+		return 1;
+	}
+
+	bus->gcc_apcs_regs = (void *)(MSM_GCC_BASE + GCC_PLL_APCS_REG);
+	bus->lcc_pll0_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_PLL0_MODE_REG);
+	bus->lcc_ahbix_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_AHBIX_NS_REG);
+	bus->lcc_mi2s_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_MI2S_NS_REG);
+	bus->lcc_pll_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_PLL_PCLK_REG);
+
+
+	if (lcc_init_enable_pll0(bus))
+		return 1;
+	if (lcc_init_enable_ahbix(bus))
+		return 1;
+	if (lcc_init_mi2s(bus, frequency))
+		return 1;
+
+	if (lcc_enable_mi2s(bus))
+		return 1;
+
+	return 0;
+}



More information about the coreboot-gerrit mailing list