Commit 7552d1b9 authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge branches 'clk-stm', 'clk-renesas', 'clk-scmi' and 'clk-allwinner' into clk-next

 - STM32MP257 SoC clk driver
 - Allocate clk_ops dynamically for SCMI clk driver

* clk-stm:
  dt-bindings: clocks: stm32mp25: add access-controllers description
  clk: stm32: introduce clocks for STM32MP257 platform
  dt-bindings: clocks: stm32mp25: add description of all parents
  clk: stm32mp13: use platform device APIs

* clk-renesas:
  clk: renesas: r9a08g045: Add support for power domains
  clk: renesas: rzg2l: Extend power domain support
  dt-bindings: clock: renesas,rzg2l-cpg: Update #power-domain-cells = <1> for RZ/G3S
  dt-bindings: clock: r9a08g045-cpg: Add power domain IDs
  dt-bindings: clock: r9a07g054-cpg: Add power domain IDs
  dt-bindings: clock: r9a07g044-cpg: Add power domain IDs
  dt-bindings: clock: r9a07g043-cpg: Add power domain IDs
  clk: renesas: shmobile: Remove unused CLK_ENABLE_ON_INIT
  clk: renesas: r8a7740: Remove unused div4_clk.flags field
  clk: renesas: r9a07g043: Add clock and reset entry for PLIC
  clk: renesas: r8a779h0: Add INTC-EX clock
  clk: renesas: r8a779h0: Add MSIOF clocks
  clk: renesas: r8a779a0: Fix CANFD parent clock
  clk: rs9: fix wrong default value for clock amplitude
  clk: renesas: r8a779h0: Add timer clocks
  clk: renesas: r8a779h0: Add SCIF clocks
  clk: renesas: r9a07g044: Mark resets array as const
  clk: renesas: r9a07g043: Mark mod_clks and resets arrays as const
  clk: renesas: r8a779h0: Add thermal clock
  dt-bindings: clock: r9a07g043-cpg: Annotate RZ/G2UL-only core clocks

* clk-scmi:
  clk: scmi: Add support for get/set duty_cycle operations
  clk: scmi: Add support for re-parenting restricted clocks
  clk: scmi: Add support for rate change restricted clocks
  clk: scmi: Add support for state control restricted clocks
  clk: scmi: Allocate CLK operations dynamically

* clk-allwinner:
  clk: sunxi-ng: fix module autoloading
  clk: sunxi-ng: a64: Add constraints on PLL-MIPI's n/m ratio and parent rate
  clk: sunxi-ng: nkm: Support constraints on m/n ratio and parent rate
Loading
Loading
Loading
Loading
+17 −1
Original line number Diff line number Diff line
@@ -57,7 +57,8 @@ properties:
      can be power-managed through Module Standby should refer to the CPG device
      node in their "power-domains" property, as documented by the generic PM
      Domain bindings in Documentation/devicetree/bindings/power/power-domain.yaml.
    const: 0
      The power domain specifiers defined in <dt-bindings/clock/r9a0*-cpg.h> could
      be used to reference individual CPG power domains.

  '#reset-cells':
    description:
@@ -76,6 +77,21 @@ required:

additionalProperties: false

allOf:
  - if:
      properties:
        compatible:
          contains:
            const: renesas,r9a08g045-cpg
    then:
      properties:
        '#power-domain-cells':
          const: 1
    else:
      properties:
        '#power-domain-cells':
          const: 0

examples:
  - |
    cpg: clock-controller@11010000 {
+158 −14
Original line number Diff line number Diff line
@@ -38,14 +38,85 @@ properties:
      - description: CK_SCMI_MSI Low Power Internal oscillator (~ 4 MHz or ~ 16 MHz)
      - description: CK_SCMI_LSE Low Speed External oscillator (32 KHz)
      - description: CK_SCMI_LSI Low Speed Internal oscillator (~ 32 KHz)
      - description: CK_SCMI_HSE_DIV2 CK_SCMI_HSE divided by 2 (coud be gated)
      - description: CK_SCMI_ICN_HS_MCU High Speed interconnect bus clock
      - description: CK_SCMI_ICN_LS_MCU Low Speed interconnect bus clock
      - description: CK_SCMI_ICN_SDMMC SDMMC interconnect bus clock
      - description: CK_SCMI_ICN_DDR DDR interconnect bus clock
      - description: CK_SCMI_ICN_DISPLAY Display interconnect bus clock
      - description: CK_SCMI_ICN_HSL HSL interconnect bus clock
      - description: CK_SCMI_ICN_NIC NIC interconnect bus clock
      - description: CK_SCMI_ICN_VID Video interconnect bus clock
      - description: CK_SCMI_FLEXGEN_07 flexgen clock 7
      - description: CK_SCMI_FLEXGEN_08 flexgen clock 8
      - description: CK_SCMI_FLEXGEN_09 flexgen clock 9
      - description: CK_SCMI_FLEXGEN_10 flexgen clock 10
      - description: CK_SCMI_FLEXGEN_11 flexgen clock 11
      - description: CK_SCMI_FLEXGEN_12 flexgen clock 12
      - description: CK_SCMI_FLEXGEN_13 flexgen clock 13
      - description: CK_SCMI_FLEXGEN_14 flexgen clock 14
      - description: CK_SCMI_FLEXGEN_15 flexgen clock 15
      - description: CK_SCMI_FLEXGEN_16 flexgen clock 16
      - description: CK_SCMI_FLEXGEN_17 flexgen clock 17
      - description: CK_SCMI_FLEXGEN_18 flexgen clock 18
      - description: CK_SCMI_FLEXGEN_19 flexgen clock 19
      - description: CK_SCMI_FLEXGEN_20 flexgen clock 20
      - description: CK_SCMI_FLEXGEN_21 flexgen clock 21
      - description: CK_SCMI_FLEXGEN_22 flexgen clock 22
      - description: CK_SCMI_FLEXGEN_23 flexgen clock 23
      - description: CK_SCMI_FLEXGEN_24 flexgen clock 24
      - description: CK_SCMI_FLEXGEN_25 flexgen clock 25
      - description: CK_SCMI_FLEXGEN_26 flexgen clock 26
      - description: CK_SCMI_FLEXGEN_27 flexgen clock 27
      - description: CK_SCMI_FLEXGEN_28 flexgen clock 28
      - description: CK_SCMI_FLEXGEN_29 flexgen clock 29
      - description: CK_SCMI_FLEXGEN_30 flexgen clock 30
      - description: CK_SCMI_FLEXGEN_31 flexgen clock 31
      - description: CK_SCMI_FLEXGEN_32 flexgen clock 32
      - description: CK_SCMI_FLEXGEN_33 flexgen clock 33
      - description: CK_SCMI_FLEXGEN_34 flexgen clock 34
      - description: CK_SCMI_FLEXGEN_35 flexgen clock 35
      - description: CK_SCMI_FLEXGEN_36 flexgen clock 36
      - description: CK_SCMI_FLEXGEN_37 flexgen clock 37
      - description: CK_SCMI_FLEXGEN_38 flexgen clock 38
      - description: CK_SCMI_FLEXGEN_39 flexgen clock 39
      - description: CK_SCMI_FLEXGEN_40 flexgen clock 40
      - description: CK_SCMI_FLEXGEN_41 flexgen clock 41
      - description: CK_SCMI_FLEXGEN_42 flexgen clock 42
      - description: CK_SCMI_FLEXGEN_43 flexgen clock 43
      - description: CK_SCMI_FLEXGEN_44 flexgen clock 44
      - description: CK_SCMI_FLEXGEN_45 flexgen clock 45
      - description: CK_SCMI_FLEXGEN_46 flexgen clock 46
      - description: CK_SCMI_FLEXGEN_47 flexgen clock 47
      - description: CK_SCMI_FLEXGEN_48 flexgen clock 48
      - description: CK_SCMI_FLEXGEN_49 flexgen clock 49
      - description: CK_SCMI_FLEXGEN_50 flexgen clock 50
      - description: CK_SCMI_FLEXGEN_51 flexgen clock 51
      - description: CK_SCMI_FLEXGEN_52 flexgen clock 52
      - description: CK_SCMI_FLEXGEN_53 flexgen clock 53
      - description: CK_SCMI_FLEXGEN_54 flexgen clock 54
      - description: CK_SCMI_FLEXGEN_55 flexgen clock 55
      - description: CK_SCMI_FLEXGEN_56 flexgen clock 56
      - description: CK_SCMI_FLEXGEN_57 flexgen clock 57
      - description: CK_SCMI_FLEXGEN_58 flexgen clock 58
      - description: CK_SCMI_FLEXGEN_59 flexgen clock 59
      - description: CK_SCMI_FLEXGEN_60 flexgen clock 60
      - description: CK_SCMI_FLEXGEN_61 flexgen clock 61
      - description: CK_SCMI_FLEXGEN_62 flexgen clock 62
      - description: CK_SCMI_FLEXGEN_63 flexgen clock 63
      - description: CK_SCMI_ICN_APB1 Peripheral bridge 1
      - description: CK_SCMI_ICN_APB2 Peripheral bridge 2
      - description: CK_SCMI_ICN_APB3 Peripheral bridge 3
      - description: CK_SCMI_ICN_APB4 Peripheral bridge 4
      - description: CK_SCMI_ICN_APBDBG Peripheral bridge for degub
      - description: CK_SCMI_TIMG1 Peripheral bridge for timer1
      - description: CK_SCMI_TIMG2 Peripheral bridge for timer2
      - description: CK_SCMI_PLL3 PLL3 clock
      - description: clk_dsi_txbyte DSI byte clock

  clock-names:
    items:
      - const: hse
      - const: hsi
      - const: msi
      - const: lse
      - const: lsi
  access-controllers:
    minItems: 1
    maxItems: 2

required:
  - compatible
@@ -53,7 +124,6 @@ required:
  - '#clock-cells'
  - '#reset-cells'
  - clocks
  - clock-names

additionalProperties: false

@@ -66,11 +136,85 @@ examples:
        reg = <0x44200000 0x10000>;
        #clock-cells = <1>;
        #reset-cells = <1>;
        clock-names = "hse", "hsi", "msi", "lse", "lsi";
        clocks =  <&scmi_clk CK_SCMI_HSE>,
                  <&scmi_clk CK_SCMI_HSI>,
                  <&scmi_clk CK_SCMI_MSI>,
                  <&scmi_clk CK_SCMI_LSE>,
                 <&scmi_clk CK_SCMI_LSI>;
                  <&scmi_clk CK_SCMI_LSI>,
                  <&scmi_clk CK_SCMI_HSE_DIV2>,
                  <&scmi_clk CK_SCMI_ICN_HS_MCU>,
                  <&scmi_clk CK_SCMI_ICN_LS_MCU>,
                  <&scmi_clk CK_SCMI_ICN_SDMMC>,
                  <&scmi_clk CK_SCMI_ICN_DDR>,
                  <&scmi_clk CK_SCMI_ICN_DISPLAY>,
                  <&scmi_clk CK_SCMI_ICN_HSL>,
                  <&scmi_clk CK_SCMI_ICN_NIC>,
                  <&scmi_clk CK_SCMI_ICN_VID>,
                  <&scmi_clk CK_SCMI_FLEXGEN_07>,
                  <&scmi_clk CK_SCMI_FLEXGEN_08>,
                  <&scmi_clk CK_SCMI_FLEXGEN_09>,
                  <&scmi_clk CK_SCMI_FLEXGEN_10>,
                  <&scmi_clk CK_SCMI_FLEXGEN_11>,
                  <&scmi_clk CK_SCMI_FLEXGEN_12>,
                  <&scmi_clk CK_SCMI_FLEXGEN_13>,
                  <&scmi_clk CK_SCMI_FLEXGEN_14>,
                  <&scmi_clk CK_SCMI_FLEXGEN_15>,
                  <&scmi_clk CK_SCMI_FLEXGEN_16>,
                  <&scmi_clk CK_SCMI_FLEXGEN_17>,
                  <&scmi_clk CK_SCMI_FLEXGEN_18>,
                  <&scmi_clk CK_SCMI_FLEXGEN_19>,
                  <&scmi_clk CK_SCMI_FLEXGEN_20>,
                  <&scmi_clk CK_SCMI_FLEXGEN_21>,
                  <&scmi_clk CK_SCMI_FLEXGEN_22>,
                  <&scmi_clk CK_SCMI_FLEXGEN_23>,
                  <&scmi_clk CK_SCMI_FLEXGEN_24>,
                  <&scmi_clk CK_SCMI_FLEXGEN_25>,
                  <&scmi_clk CK_SCMI_FLEXGEN_26>,
                  <&scmi_clk CK_SCMI_FLEXGEN_27>,
                  <&scmi_clk CK_SCMI_FLEXGEN_28>,
                  <&scmi_clk CK_SCMI_FLEXGEN_29>,
                  <&scmi_clk CK_SCMI_FLEXGEN_30>,
                  <&scmi_clk CK_SCMI_FLEXGEN_31>,
                  <&scmi_clk CK_SCMI_FLEXGEN_32>,
                  <&scmi_clk CK_SCMI_FLEXGEN_33>,
                  <&scmi_clk CK_SCMI_FLEXGEN_34>,
                  <&scmi_clk CK_SCMI_FLEXGEN_35>,
                  <&scmi_clk CK_SCMI_FLEXGEN_36>,
                  <&scmi_clk CK_SCMI_FLEXGEN_37>,
                  <&scmi_clk CK_SCMI_FLEXGEN_38>,
                  <&scmi_clk CK_SCMI_FLEXGEN_39>,
                  <&scmi_clk CK_SCMI_FLEXGEN_40>,
                  <&scmi_clk CK_SCMI_FLEXGEN_41>,
                  <&scmi_clk CK_SCMI_FLEXGEN_42>,
                  <&scmi_clk CK_SCMI_FLEXGEN_43>,
                  <&scmi_clk CK_SCMI_FLEXGEN_44>,
                  <&scmi_clk CK_SCMI_FLEXGEN_45>,
                  <&scmi_clk CK_SCMI_FLEXGEN_46>,
                  <&scmi_clk CK_SCMI_FLEXGEN_47>,
                  <&scmi_clk CK_SCMI_FLEXGEN_48>,
                  <&scmi_clk CK_SCMI_FLEXGEN_49>,
                  <&scmi_clk CK_SCMI_FLEXGEN_50>,
                  <&scmi_clk CK_SCMI_FLEXGEN_51>,
                  <&scmi_clk CK_SCMI_FLEXGEN_52>,
                  <&scmi_clk CK_SCMI_FLEXGEN_53>,
                  <&scmi_clk CK_SCMI_FLEXGEN_54>,
                  <&scmi_clk CK_SCMI_FLEXGEN_55>,
                  <&scmi_clk CK_SCMI_FLEXGEN_56>,
                  <&scmi_clk CK_SCMI_FLEXGEN_57>,
                  <&scmi_clk CK_SCMI_FLEXGEN_58>,
                  <&scmi_clk CK_SCMI_FLEXGEN_59>,
                  <&scmi_clk CK_SCMI_FLEXGEN_60>,
                  <&scmi_clk CK_SCMI_FLEXGEN_61>,
                  <&scmi_clk CK_SCMI_FLEXGEN_62>,
                  <&scmi_clk CK_SCMI_FLEXGEN_63>,
                  <&scmi_clk CK_SCMI_ICN_APB1>,
                  <&scmi_clk CK_SCMI_ICN_APB2>,
                  <&scmi_clk CK_SCMI_ICN_APB3>,
                  <&scmi_clk CK_SCMI_ICN_APB4>,
                  <&scmi_clk CK_SCMI_ICN_APBDBG>,
                  <&scmi_clk CK_SCMI_TIMG1>,
                  <&scmi_clk CK_SCMI_TIMG2>,
                  <&scmi_clk CK_SCMI_PLL3>,
                  <&clk_dsi_txbyte>;
    };
...
+6 −4
Original line number Diff line number Diff line
@@ -25,10 +25,12 @@
#define RS9_REG_SS_AMP_0V7			0x1
#define RS9_REG_SS_AMP_0V8			0x2
#define RS9_REG_SS_AMP_0V9			0x3
#define RS9_REG_SS_AMP_DEFAULT			RS9_REG_SS_AMP_0V8
#define RS9_REG_SS_AMP_MASK			0x3
#define RS9_REG_SS_SSC_100			0
#define RS9_REG_SS_SSC_M025			(1 << 3)
#define RS9_REG_SS_SSC_M050			(3 << 3)
#define RS9_REG_SS_SSC_DEFAULT			RS9_REG_SS_SSC_100
#define RS9_REG_SS_SSC_MASK			(3 << 3)
#define RS9_REG_SS_SSC_LOCK			BIT(5)
#define RS9_REG_SR				0x2
@@ -205,8 +207,8 @@ static int rs9_get_common_config(struct rs9_driver_data *rs9)
	int ret;

	/* Set defaults */
	rs9->pll_amplitude = RS9_REG_SS_AMP_0V7;
	rs9->pll_ssc = RS9_REG_SS_SSC_100;
	rs9->pll_amplitude = RS9_REG_SS_AMP_DEFAULT;
	rs9->pll_ssc = RS9_REG_SS_SSC_DEFAULT;

	/* Output clock amplitude */
	ret = of_property_read_u32(np, "renesas,out-amplitude-microvolt",
@@ -247,13 +249,13 @@ static void rs9_update_config(struct rs9_driver_data *rs9)
	int i;

	/* If amplitude is non-default, update it. */
	if (rs9->pll_amplitude != RS9_REG_SS_AMP_0V7) {
	if (rs9->pll_amplitude != RS9_REG_SS_AMP_DEFAULT) {
		regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_AMP_MASK,
				   rs9->pll_amplitude);
	}

	/* If SSC is non-default, update it. */
	if (rs9->pll_ssc != RS9_REG_SS_SSC_100) {
	if (rs9->pll_ssc != RS9_REG_SS_SSC_DEFAULT) {
		regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_SSC_MASK,
				   rs9->pll_ssc);
	}
+201 −48
Original line number Diff line number Diff line
@@ -2,9 +2,10 @@
/*
 * System Control and Power Interface (SCMI) Protocol based clock driver
 *
 * Copyright (C) 2018-2022 ARM Ltd.
 * Copyright (C) 2018-2024 ARM Ltd.
 */

#include <linux/bits.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -16,6 +17,17 @@
#define NOT_ATOMIC	false
#define ATOMIC		true

enum scmi_clk_feats {
	SCMI_CLK_ATOMIC_SUPPORTED,
	SCMI_CLK_STATE_CTRL_SUPPORTED,
	SCMI_CLK_RATE_CTRL_SUPPORTED,
	SCMI_CLK_PARENT_CTRL_SUPPORTED,
	SCMI_CLK_DUTY_CYCLE_SUPPORTED,
	SCMI_CLK_FEATS_COUNT
};

#define SCMI_MAX_CLK_OPS	BIT(SCMI_CLK_FEATS_COUNT)

static const struct scmi_clk_proto_ops *scmi_proto_clk_ops;

struct scmi_clk {
@@ -158,41 +170,44 @@ static int scmi_clk_atomic_is_enabled(struct clk_hw *hw)
	return !!enabled;
}

/*
 * We can provide enable/disable/is_enabled atomic callbacks only if the
 * underlying SCMI transport for an SCMI instance is configured to handle
 * SCMI commands in an atomic manner.
 *
 * When no SCMI atomic transport support is available we instead provide only
 * the prepare/unprepare API, as allowed by the clock framework when atomic
 * calls are not available.
 *
 * Two distinct sets of clk_ops are provided since we could have multiple SCMI
 * instances with different underlying transport quality, so they cannot be
 * shared.
 */
static const struct clk_ops scmi_clk_ops = {
	.recalc_rate = scmi_clk_recalc_rate,
	.round_rate = scmi_clk_round_rate,
	.set_rate = scmi_clk_set_rate,
	.prepare = scmi_clk_enable,
	.unprepare = scmi_clk_disable,
	.set_parent = scmi_clk_set_parent,
	.get_parent = scmi_clk_get_parent,
	.determine_rate = scmi_clk_determine_rate,
};
static int scmi_clk_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
{
	int ret;
	u32 val;
	struct scmi_clk *clk = to_scmi_clk(hw);

static const struct clk_ops scmi_atomic_clk_ops = {
	.recalc_rate = scmi_clk_recalc_rate,
	.round_rate = scmi_clk_round_rate,
	.set_rate = scmi_clk_set_rate,
	.enable = scmi_clk_atomic_enable,
	.disable = scmi_clk_atomic_disable,
	.is_enabled = scmi_clk_atomic_is_enabled,
	.set_parent = scmi_clk_set_parent,
	.get_parent = scmi_clk_get_parent,
	.determine_rate = scmi_clk_determine_rate,
};
	ret = scmi_proto_clk_ops->config_oem_get(clk->ph, clk->id,
						 SCMI_CLOCK_CFG_DUTY_CYCLE,
						 &val, NULL, false);
	if (!ret) {
		duty->num = val;
		duty->den = 100;
	} else {
		dev_warn(clk->dev,
			 "Failed to get duty cycle for clock ID %d\n", clk->id);
	}

	return ret;
}

static int scmi_clk_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
{
	int ret;
	u32 val;
	struct scmi_clk *clk = to_scmi_clk(hw);

	/* SCMI OEM Duty Cycle is expressed as a percentage */
	val = (duty->num * 100) / duty->den;
	ret = scmi_proto_clk_ops->config_oem_set(clk->ph, clk->id,
						 SCMI_CLOCK_CFG_DUTY_CYCLE,
						 val, false);
	if (ret)
		dev_warn(clk->dev,
			 "Failed to set duty cycle(%u/%u) for clock ID %d\n",
			 duty->num, duty->den, clk->id);

	return ret;
}

static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
			     const struct clk_ops *scmi_ops)
@@ -230,17 +245,153 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
	return ret;
}

/**
 * scmi_clk_ops_alloc() - Alloc and configure clock operations
 * @dev: A device reference for devres
 * @feats_key: A bitmap representing the desired clk_ops capabilities
 *
 * Allocate and configure a proper set of clock operations depending on the
 * specifically required SCMI clock features.
 *
 * Return: A pointer to the allocated and configured clk_ops on success,
 *	   or NULL on allocation failure.
 */
static const struct clk_ops *
scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
{
	struct clk_ops *ops;

	ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
	if (!ops)
		return NULL;
	/*
	 * We can provide enable/disable/is_enabled atomic callbacks only if the
	 * underlying SCMI transport for an SCMI instance is configured to
	 * handle SCMI commands in an atomic manner.
	 *
	 * When no SCMI atomic transport support is available we instead provide
	 * only the prepare/unprepare API, as allowed by the clock framework
	 * when atomic calls are not available.
	 */
	if (feats_key & BIT(SCMI_CLK_STATE_CTRL_SUPPORTED)) {
		if (feats_key & BIT(SCMI_CLK_ATOMIC_SUPPORTED)) {
			ops->enable = scmi_clk_atomic_enable;
			ops->disable = scmi_clk_atomic_disable;
		} else {
			ops->prepare = scmi_clk_enable;
			ops->unprepare = scmi_clk_disable;
		}
	}

	if (feats_key & BIT(SCMI_CLK_ATOMIC_SUPPORTED))
		ops->is_enabled = scmi_clk_atomic_is_enabled;

	/* Rate ops */
	ops->recalc_rate = scmi_clk_recalc_rate;
	ops->round_rate = scmi_clk_round_rate;
	ops->determine_rate = scmi_clk_determine_rate;
	if (feats_key & BIT(SCMI_CLK_RATE_CTRL_SUPPORTED))
		ops->set_rate = scmi_clk_set_rate;

	/* Parent ops */
	ops->get_parent = scmi_clk_get_parent;
	if (feats_key & BIT(SCMI_CLK_PARENT_CTRL_SUPPORTED))
		ops->set_parent = scmi_clk_set_parent;

	/* Duty cycle */
	if (feats_key & BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED)) {
		ops->get_duty_cycle = scmi_clk_get_duty_cycle;
		ops->set_duty_cycle = scmi_clk_set_duty_cycle;
	}

	return ops;
}

/**
 * scmi_clk_ops_select() - Select a proper set of clock operations
 * @sclk: A reference to an SCMI clock descriptor
 * @atomic_capable: A flag to indicate if atomic mode is supported by the
 *		    transport
 * @atomic_threshold_us: Platform atomic threshold value in microseconds:
 *			 clk_ops are atomic when clock enable latency is less
 *			 than this threshold
 * @clk_ops_db: A reference to the array used as a database to store all the
 *		created clock operations combinations.
 * @db_size: Maximum number of entries held by @clk_ops_db
 *
 * After having built a bitmap descriptor to represent the set of features
 * needed by this SCMI clock, at first use it to lookup into the set of
 * previously allocated clk_ops to check if a suitable combination of clock
 * operations was already created; when no match is found allocate a brand new
 * set of clk_ops satisfying the required combination of features and save it
 * for future references.
 *
 * In this way only one set of clk_ops is ever created for each different
 * combination that is effectively needed by a driver instance.
 *
 * Return: A pointer to the allocated and configured clk_ops on success, or
 *	   NULL otherwise.
 */
static const struct clk_ops *
scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
		    unsigned int atomic_threshold_us,
		    const struct clk_ops **clk_ops_db, size_t db_size)
{
	const struct scmi_clock_info *ci = sclk->info;
	unsigned int feats_key = 0;
	const struct clk_ops *ops;

	/*
	 * Note that when transport is atomic but SCMI protocol did not
	 * specify (or support) an enable_latency associated with a
	 * clock, we default to use atomic operations mode.
	 */
	if (atomic_capable && ci->enable_latency <= atomic_threshold_us)
		feats_key |= BIT(SCMI_CLK_ATOMIC_SUPPORTED);

	if (!ci->state_ctrl_forbidden)
		feats_key |= BIT(SCMI_CLK_STATE_CTRL_SUPPORTED);

	if (!ci->rate_ctrl_forbidden)
		feats_key |= BIT(SCMI_CLK_RATE_CTRL_SUPPORTED);

	if (!ci->parent_ctrl_forbidden)
		feats_key |= BIT(SCMI_CLK_PARENT_CTRL_SUPPORTED);

	if (ci->extended_config)
		feats_key |= BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED);

	if (WARN_ON(feats_key >= db_size))
		return NULL;

	/* Lookup previously allocated ops */
	ops = clk_ops_db[feats_key];
	if (ops)
		return ops;

	/* Did not find a pre-allocated clock_ops */
	ops = scmi_clk_ops_alloc(sclk->dev, feats_key);
	if (!ops)
		return NULL;

	/* Store new ops combinations */
	clk_ops_db[feats_key] = ops;

	return ops;
}

static int scmi_clocks_probe(struct scmi_device *sdev)
{
	int idx, count, err;
	unsigned int atomic_threshold;
	bool is_atomic;
	unsigned int atomic_threshold_us;
	bool transport_is_atomic;
	struct clk_hw **hws;
	struct clk_hw_onecell_data *clk_data;
	struct device *dev = &sdev->dev;
	struct device_node *np = dev->of_node;
	const struct scmi_handle *handle = sdev->handle;
	struct scmi_protocol_handle *ph;
	const struct clk_ops *scmi_clk_ops_db[SCMI_MAX_CLK_OPS] = {};

	if (!handle)
		return -ENODEV;
@@ -264,7 +415,8 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
	clk_data->num = count;
	hws = clk_data->hws;

	is_atomic = handle->is_transport_atomic(handle, &atomic_threshold);
	transport_is_atomic = handle->is_transport_atomic(handle,
							  &atomic_threshold_us);

	for (idx = 0; idx < count; idx++) {
		struct scmi_clk *sclk;
@@ -286,15 +438,17 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
		sclk->dev = dev;

		/*
		 * Note that when transport is atomic but SCMI protocol did not
		 * specify (or support) an enable_latency associated with a
		 * clock, we default to use atomic operations mode.
		 * Note that the scmi_clk_ops_db is on the stack, not global,
		 * because it cannot be shared between mulitple probe-sequences
		 * to avoid sharing the devm_ allocated clk_ops between multiple
		 * SCMI clk driver instances.
		 */
		if (is_atomic &&
		    sclk->info->enable_latency <= atomic_threshold)
			scmi_ops = &scmi_atomic_clk_ops;
		else
			scmi_ops = &scmi_clk_ops;
		scmi_ops = scmi_clk_ops_select(sclk, transport_is_atomic,
					       atomic_threshold_us,
					       scmi_clk_ops_db,
					       ARRAY_SIZE(scmi_clk_ops_db));
		if (!scmi_ops)
			return -ENOMEM;

		/* Initialize clock parent data. */
		if (sclk->info->num_parents > 0) {
@@ -318,8 +472,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
		} else {
			dev_dbg(dev, "Registered clock:%s%s\n",
				sclk->info->name,
				scmi_ops == &scmi_atomic_clk_ops ?
				" (atomic ops)" : "");
				scmi_ops->enable ? " (atomic ops)" : "");
			hws[idx] = &sclk->hw;
		}
	}
+0 −2
Original line number Diff line number Diff line
@@ -30,8 +30,6 @@ struct r8a73a4_cpg {
#define CPG_PLL2HCR	0xe4
#define CPG_PLL2SCR	0xf4

#define CLK_ENABLE_ON_INIT BIT(0)

struct div4_clk {
	const char *name;
	unsigned int reg;
Loading