[PATCH 2/3] phy: stm32-usbphyc: usbphyc is a clock provider of ck_usbo_48m clock

Patrick DELAUNAY patrick.delaunay at foss.st.com
Mon May 9 17:44:37 CEST 2022


Hi Sean

On 5/8/22 20:23, Sean Anderson wrote:
> On 4/26/22 8:37 AM, Patrick Delaunay wrote:
>> ck_usbo_48m is generated by usbphyc PLL and used by OTG controller
>> for Full-Speed use cases with dedicated Full-Speed transceiver.
>>
>> ck_usbo_48m is available as soon as the PLL is enabled.
>>
>> Signed-off-by: Patrick Delaunay <patrick.delaunay at foss.st.com>
>> ---
>>
>>   drivers/phy/phy-stm32-usbphyc.c | 79 +++++++++++++++++++++++++++++++++
>>   1 file changed, 79 insertions(+)
>>
>> diff --git a/drivers/phy/phy-stm32-usbphyc.c 
>> b/drivers/phy/phy-stm32-usbphyc.c
>> index 16c8799eca..e0b8fcb8f2 100644
>> --- a/drivers/phy/phy-stm32-usbphyc.c
>> +++ b/drivers/phy/phy-stm32-usbphyc.c
>> @@ -7,6 +7,7 @@
>>     #include <common.h>
>>   #include <clk.h>
>> +#include <clk-uclass.h>
>>   #include <div64.h>
>>   #include <dm.h>
>>   #include <fdtdec.h>
>> @@ -17,6 +18,7 @@
>>   #include <usb.h>
>>   #include <asm/io.h>
>>   #include <dm/device_compat.h>
>> +#include <dm/lists.h>
>>   #include <linux/bitops.h>
>>   #include <linux/delay.h>
>>   #include <power/regulator.h>
>> @@ -49,6 +51,9 @@
>>   #define PLL_INFF_MIN_RATE    19200000 /* in Hz */
>>   #define PLL_INFF_MAX_RATE    38400000 /* in Hz */
>>   +/* USBPHYC_CLK48 */
>> +#define USBPHYC_CLK48_FREQ    48000000 /* in Hz */
>> +
>>   struct pll_params {
>>       u8 ndiv;
>>       u16 frac;
>> @@ -355,6 +360,16 @@ static const struct phy_ops 
>> stm32_usbphyc_phy_ops = {
>>       .of_xlate = stm32_usbphyc_of_xlate,
>>   };
>>   +static int stm32_usbphyc_bind(struct udevice *dev)
>> +{
>> +    int ret;
>> +
>> +    ret = device_bind_driver_to_node(dev, "stm32-usbphyc-clk", 
>> "ck_usbo_48m",
>> +                     dev_ofnode(dev), NULL);
>> +
>> +    return log_ret(ret);
>> +}
>> +
>>   static int stm32_usbphyc_probe(struct udevice *dev)
>>   {
>>       struct stm32_usbphyc *usbphyc = dev_get_priv(dev);
>> @@ -444,6 +459,70 @@ U_BOOT_DRIVER(stm32_usb_phyc) = {
>>       .id = UCLASS_PHY,
>>       .of_match = stm32_usbphyc_of_match,
>>       .ops = &stm32_usbphyc_phy_ops,
>> +    .bind = stm32_usbphyc_bind,
>>       .probe = stm32_usbphyc_probe,
>>       .priv_auto    = sizeof(struct stm32_usbphyc),
>>   };
>> +
>> +struct stm32_usbphyc_clk {
>> +    bool enable;
>> +};
>> +
>> +static ulong stm32_usbphyc_clk48_get_rate(struct clk *clk)
>> +{
>> +    return USBPHYC_CLK48_FREQ;
>
> What is the relationship between this clock and the PLL?


The output clock of USBPHYC, running a 48MHz is only available when the 
USBPHYC is initialized and the PLL is enabled.

=> ck_usbo_48m is available as soon as the PLL is enabled.

see the associated code in kernel:

https://lore.kernel.org/all/20210208114659.15269-1-amelie.delaunay@foss.st.com/T/


>
>> +}
>> +
>> +static int stm32_usbphyc_clk48_enable(struct clk *clk)
>> +{
>> +    struct stm32_usbphyc_clk *usbphyc_clk = dev_get_priv(clk->dev);
>> +    struct stm32_usbphyc *usbphyc;
>> +    int ret;
>> +
>> +    if (usbphyc_clk->enable)
>> +        return 0;
>> +
>> +    usbphyc = dev_get_priv(clk->dev->parent);
>> +
>> +    /* ck_usbo_48m is generated by usbphyc PLL */
>> +    ret = stm32_usbphyc_pll_enable(usbphyc);
>> +    if (ret)
>> +        return ret;
>> +
>> +    usbphyc_clk->enable = true;
>> +
>> +    return 0;
>> +}
>> +
>> +static int stm32_usbphyc_clk48_disable(struct clk *clk)
>> +{ usbphyc provides a unique clock called ck_usbo_48m.
>> STM32 USB OTG needs a 48Mhz clock (utmifs_clk48) for Full-Speed 
>> operation.
>> ck_usbo_48m is a possible parent clock for USB OTG 48Mhz clock.
>> +    struct stm32_usbphyc_clk *usbphyc_clk = dev_get_priv(clk->dev);
>> +    struct stm32_usbphyc *usbphyc;
>> +    int ret;
>> +
>> +    if (!usbphyc_clk->enable)
>> +        return 0;
>> +
>> +    usbphyc = dev_get_priv(clk->dev->parent);
>> +
>> +    ret = stm32_usbphyc_pll_disable(usbphyc);
>> +    if (ret)
>> +        return ret;
>> +
>> +    usbphyc_clk->enable = false;
>> +
>> +    return 0;
>> +}
>> +
>> +const struct clk_ops usbphyc_clk48_ops = {
>> +    .get_rate = stm32_usbphyc_clk48_get_rate,
>> +    .enable = stm32_usbphyc_clk48_enable,
>> +    .disable = stm32_usbphyc_clk48_disable,
>> +};
>> +
>> +U_BOOT_DRIVER(stm32_usb_phyc_clk) = {
>> +    .name = "stm32-usbphyc-clk",
>> +    .id = UCLASS_CLK,
>> +    .ops = &usbphyc_clk48_ops,
>> +    .priv_auto = sizeof(struct stm32_usbphyc_clk),
>> +};
>>
>
> I see that in the next patch you call this device from 
> drivers/clk/clk_stm32mp1.c
>
> Why is this clock a separate driver from the clock driver?


The clock driver STM32MP1 = drivers/clk/clk_stm32mp1.c manage the clock in

the hardware IP RCC include in STM32MPU

=> 4 PLL and several oscillators LSI / HSI / CSI / HSE / LSE

=> manage clock source for many peripheral clock in STM32 MPU


The USBPHYC drivers manages the USB PHYC hardware block, it manage a PHY for

USB operation (device or host).

This hardware block have a internal PLL for its operation which is managed

directly by USBPHYC registers:

   usbphyc provides a unique clock called ck_usbo_48m.
   STM32 USB OTG needs a 48Mhz clock (utmifs_clk48) for Full-Speed operation.
   ck_usbo_48m is a possible parent clock for USB OTG 48Mhz clock.


This PLL is required for internal operation of USBPHYC (this PLL need to 
be enable

to allow USB detection for example) but also as input clock for RCC 
peripheral clock

USBO is "rcc_ck_usbo_48m" (see RCC_USBCKSELR.USBOSRC : USB OTG kernel clock

source selection)


So in RCC driver, we need to get the rate (it is trivial = 48MHz)

and enable the PLL when the peripheral clock USBO is required.


For this last point I prefer export a generic clock provider = CLK 
UCLASS than

export a specific usbphy function or duplicate USBPHYC code in RCC CLK 
driver.

even if the enable request on "rcc_ck_usbo_48m" is not managed in STM32MP15x

RCC driver...(stm32mp1_clk_enable don't enable the parent clock)


This patch prepares the STM32MP13x RCC driver introduction (coming soon),

based on CCF (common clock framework, ported n U-Boot):

each clock on the system is a CLK UCLASS and the dependencies are correctly

handle (each parent clock is enable when a clock is enable) but without

a CLK UCLASS for each USBO parent, a error occur during STM32MP13x CLK

driver probe (it is linked to drivers/clk/clk.c::clk_register(), with 
unkwon parent).


I hope that it is more clear.


>
> --Sean


Patrick



More information about the U-Boot mailing list