Skip to content

Commit

Permalink
ACPI: Support I2S master clock adjustment via _DSM
Browse files Browse the repository at this point in the history
Mux the TX clock source accordingly and initialize MCLK at 256 * 48000Hz
to fix playback speed in Windows.

RX is not configured yet.

Signed-off-by: Mario Bălănică <[email protected]>
  • Loading branch information
mariobalanica committed Jan 19, 2024
1 parent 2124a8c commit 21c4983
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 5 deletions.
180 changes: 178 additions & 2 deletions edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/I2s.asl
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
/** @file
*
* Copyright (c) 2021, ARM Limited. All rights reserved.
* Copyright (c) 2024, Mario Bălănică <[email protected]>
* Copyright (c) 2024, CoolStar. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/
#include "AcpiTables.h"

#define RK3588_PLL_AUPLL_RATE 786432000
#define RK3588_PLL_CPLL_RATE 1500000000

#define I2S_INITIAL_CLOCK (256 * 48000)

#define I2S_DSM_UUID ToUUID ("7056bfa1-af0b-48e5-b67f-139f2004a26a")

#if FixedPcdGetBool(PcdI2S0Supported)
Device (I2S0) {
Name (_HID, "RKCP3003")
Expand All @@ -30,6 +38,56 @@
}
})
Name (_DEP, Package () { \_SB.DMA0 })

Method (_INI, 0, Serialized) {
_DSM (I2S_DSM_UUID, 0, 1, Package () { I2S_INITIAL_CLOCK })
}

Method (_DSM, 4, Serialized) {
// CRU_CLKSEL_CON24
OperationRegion (CRU, SystemMemory, 0xFD7C0360, 0x8)
Field (CRU, DWordAcc, NoLock, Preserve) {
C24, 32,
C25, 32
}

// Check the UUID
If (Arg0 == I2S_DSM_UUID) {
// Check the revision
If (Arg1 >= 0) {
// Check the function index
Switch (ToInteger (Arg2)) {
//
// Supported functions:
// Bit 0 - Indicates support for functions other than 0
// Bit 1 - Indicates support for setting TX master clock
// Bit 2 - Indicates support for setting RX master clock
//
Case (0) {
Return (Buffer () { 0x03 })
}

//
// Function Index 1: Set TX master clock
// Takes the target clock rate in Hz, returns the actual set rate.
//
Case (1) {
// Source divided by clk_i2s0_8ch_tx_src_div + 1
Local0 = RK3588_PLL_AUPLL_RATE / (((C24 >> 4) & 0xf) + 1)

// Compute numerator/denumerator
Local1 = FRBA (DerefOf (Arg3[0]), Local0, 0xFFFF, 0xFFFF)

// Set fractional register
C25 = (DerefOf (Local1[0])) << 16 | DerefOf (Local1[1])

Return ((Local0 * DerefOf (Local1[0])) / DerefOf (Local1[1]))
}
} // Function index check
} // Revision check
} // UUID check
Return (Buffer () { 0x0 })
} // _DSM
}
#endif

Expand Down Expand Up @@ -60,5 +118,123 @@
}
})
Name (_DEP, Package () { \_SB.DMA0 })

Method (_INI, 0, Serialized) {
_DSM (I2S_DSM_UUID, 0, 1, Package () { I2S_INITIAL_CLOCK })
}

Method (_DSM, 4, Serialized) {
// PMU1CRU_CLKSEL_CON05
OperationRegion (CRU, SystemMemory, 0xFD7F0314, 0x8)
Field (CRU, DWordAcc, NoLock, Preserve) {
C05, 32,
C06, 32
}

// Check the UUID
If (Arg0 == I2S_DSM_UUID) {
// Check the revision
If (Arg1 >= 0) {
// Check the function index
Switch (ToInteger (Arg2)) {
//
// Supported functions:
// Bit 0 - Indicates support for functions other than 0
// Bit 1 - Indicates support for setting TX master clock
// Bit 2 - Indicates support for setting RX master clock
//
Case (0) {
Return (Buffer () { 0x03 })
}

//
// Function Index 1: Set TX master clock
// Takes the target clock rate in Hz, returns the actual set rate.
//
Case (1) {
// Source divided by clk_i2s1_8ch_tx_src_div + 1
Local0 = RK3588_PLL_CPLL_RATE / (((C05 >> 2) & 0xf) + 1)

// Compute numerator/denumerator
Local1 = FRBA (DerefOf (Arg3[0]), Local0, 0xFFFF, 0xFFFF)

// Set fractional register
C06 = (DerefOf (Local1[0])) << 16 | DerefOf (Local1[1])

Return ((Local0 * DerefOf (Local1[0])) / DerefOf (Local1[1]))
}
} // Function index check
} // Revision check
} // UUID check
Return (Buffer () { 0x0 })
} // _DSM
}
#endif

//
// FRBA - Find Rational Best Approximation
//
// Arguments: (4)
// Arg0 - Given numerator
// Arg1 - Given denominator
// Arg2 - Maximum numerator
// Arg3 - Maximum denominator
//
// Return:
// Package of two integers: best numerator, best denominator
//
Function (FRBA, PkgObj, { IntObj, IntObj, IntObj, IntObj }) {
//
// Variables used throughout this function:
// Local0, Local1 - Remaining numerator/denominator for Euclidean algorithm
// Local2, Local4 - Previous numerator/denominator convergent
// Local3, Local5 - Current numerator/denominator convergent
// Local6 - Temporary variable for swapping values around
// Local7 - Next term in the continued fraction
//
Local0 = Arg0
Local1 = Arg1
Local2 = 0
Local3 = 1
Local4 = 1
Local5 = 0

While (1) {
// Reached limits? Fall back to previous convergent.
If (Local3 > Arg2 || Local5 > Arg3) {
Local3 = Local2
Local5 = Local4
Break
}

// No remainder? We're done.
If (Local1 == 0) {
Break
}

// Find next term for convergent
Local7 = Local0 / Local1

// Set remainder
Local6 = Local1
Local1 = Local0 % Local1
Local0 = Local6

// Calculate numerator and save previous one
Local6 = Local2 + Local7 * Local3
Local2 = Local3
Local3 = Local6

// Caculate denominator and save previous one
Local6 = Local4 + Local7 * Local5
Local4 = Local5
Local5 = Local6
}

// Prepare return object
Local0 = Package (2) { 0, 0 }
Local0[0] = Local3
Local0[1] = Local5

Return (Local0)
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,14 @@ ApplyVariables (
AfterApplyVariablesInit ();
}

EFI_STATUS
RK3588InitPeripherals (
STATIC
VOID
RK3588SetupAudio (
IN VOID
)
{
DEBUG((DEBUG_INIT, "RK3588InitPeripherals: Entry\n"));
// Source PLL, ACPI expects this exact rate.
HAL_CRU_ClkSetFreq (PLL_AUPLL, 786432000);

// Warning: Only enable I2S if present.
// E.g. Enabling I2S1 on OPI5+ causes PCIe devices to disappear
Expand All @@ -234,6 +236,9 @@ RK3588InitPeripherals (
GpioPinSetFunction(1, GPIO_PIN_PC5, 1); //i2s0_lrck
GpioPinSetFunction(1, GPIO_PIN_PC3, 1); //i2s0_sclk
GpioPinSetFunction(1, GPIO_PIN_PC2, 1); //i2s0_mclk

HAL_CRU_ClkSetMux (CLK_I2S0_8CH_TX_SRC, 0x1); // clk_aupll_mux
HAL_CRU_ClkSetMux (MCLK_I2S0_8CH_TX, 0x1); // clk_i2s0_8ch_tx_frac
}

if (FixedPcdGetBool(PcdI2S1Supported)){
Expand All @@ -244,7 +249,20 @@ RK3588InitPeripherals (
GpioPinSetFunction(4, GPIO_PIN_PA2, 3); //i2s1m0_lrck
GpioPinSetFunction(4, GPIO_PIN_PA1, 3); //i2s1m0_sclk
GpioPinSetFunction(4, GPIO_PIN_PA0, 3); //i2s1m0_mclk

// CLK_I2S1_8CH_TX_SRC fixed parent: PLL_CPLL
HAL_CRU_ClkSetMux (MCLK_I2S1_8CH_TX, 0x1); // clk_i2s1_8ch_tx_frac
}
}

EFI_STATUS
RK3588InitPeripherals (
IN VOID
)
{
DEBUG((DEBUG_INIT, "RK3588InitPeripherals: Entry\n"));

RK3588SetupAudio ();

Rk806Configure();

Expand Down
3 changes: 3 additions & 0 deletions edk2-rockchip/Silicon/Rockchip/RK3588/Include/Soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ typedef enum {
CLK_REF_PIPE_PHY1,
CLK_REF_PIPE_PHY2,
DCLK_VOP2_SRC,
CLK_I2S0_8CH_TX_SRC,
MCLK_I2S0_8CH_TX,
MCLK_I2S1_8CH_TX,
CLK_COUNT
} RK3588_CLOCK_IDS;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ static struct PLL_CONFIG PLL_TABLE[] = {
RK3588_PLL_RATE(1000000000, 3, 500, 2, 0),
RK3588_PLL_RATE(983040000, 4, 655, 2, 23592),
RK3588_PLL_RATE(816000000, 2, 272, 2, 0),
RK3588_PLL_RATE(786432000, 2, 262, 2, 9437),
RK3588_PLL_RATE(100000000, 3, 400, 5, 0),
{ /* sentinel */ },
};
Expand Down Expand Up @@ -184,6 +185,16 @@ static CRU_CLOCK Clocks[CLK_COUNT] = {
CRU_CLKSEL_CON_OFFSET, DCLK_VOP2_SRC_SEL,
CRU_CLKSEL_CON_OFFSET, DCLK_VOP2_SRC_DIV,
CRU_CLKGATE_CON_OFFSET, DCLK_VOP2_SRC_GATE),
CRU_CLOCK_INIT (CLK_I2S0_8CH_TX_SRC, CRU_BASE,
CRU_CLKSEL_CON_OFFSET, CLK_I2S0_8CH_TX_SRC_SEL,
CRU_CLKSEL_CON_OFFSET, CLK_I2S0_8CH_TX_SRC_DIV,
CRU_CLKGATE_CON_OFFSET, CLK_I2S0_8CH_TX_GATE),
CRU_CLOCK_NODIV_INIT (MCLK_I2S0_8CH_TX, CRU_BASE,
CRU_CLKSEL_CON_OFFSET, MCLK_I2S0_8CH_TX_SEL,
CRU_CLKGATE_CON_OFFSET, MCLK_I2S0_8CH_TX_GATE),
CRU_CLOCK_NODIV_INIT (MCLK_I2S1_8CH_TX, PMU1CRU_BASE,
CRU_CLKSEL_CON_OFFSET, MCLK_I2S1_8CH_TX_SEL,
CRU_CLKGATE_CON_OFFSET, MCLK_I2S1_8CH_TX_GATE),
};

static CRU_RESET Resets[RESET_COUNT] = {
Expand Down

0 comments on commit 21c4983

Please sign in to comment.