《Reworking the Zephyr Clock System.pdf》由會員分享,可在線閱讀,更多相關《Reworking the Zephyr Clock System.pdf(21頁珍藏版)》請在三個皮匠報告上搜索。
1、#EMBEDDEDOSSUMMITReworking the Zephyr Clock Control Subsystem Moritz Fischer,G$whoamiEngineering Lead GoogleWorks on firmware for in-house ASICsOpen Source HippieI hate reinventing the wheelWere hiring!I2CUART AUART BSPI ASPI BCPU ACPU BASIC XASIC YASIC ZCPU AI2CUART ACPU BSPI AUART BCPU BCPU BSPI B
2、SPI BWorking on ASICs means re-using IP wherever possibleYou make something that works-suddenly everyone wants to integrate itEvery ASIC integrates IP slightly differentlyI cant rewrite all my firmware everytimeWhy do I care?Bus widths(32 bit/64 bit)Bus typeIP revisionsResetsClockingTypical integrat
3、ion differences(HW)ASIC AFixed PLLUART ARefASIC BUART AFractional PLLCPU ARefProducerConsumerProducerConsumerAll HW needs clocks to runConsumer might need info from/or control over producerExample:UART output divider depends on input clock rateClocks in ASICsASIC AFixed PLLUART ARefASIC BUART AFract
4、ional PLLCPU ARefProducerConsumerProducerConsumer(ideally)Handles dependenciesThe operations are fairly simpleConsumers should not need to know about internals of the ProducerWhat Id expect from a clock APIONOFFSet RateGet RateGet StatusFixed clocksDynamic Clocks(Type A)Dynamic Clocks(Type B)Clocks
5、in Zephyr todayWe dont use the API,we just grab the value using a macroAll compile-timeDifferent producers possible as long as they define clock-frequency in DTClocks in Zephyr today-Fixed Clocksclk0:clk clock-frequency=;compatible=“fixed-clock;#clock-cells=;uart:uart41000000 compatible=“arm,pl011”;
6、.clocks=;ret=pl011_set_baudrate(dev,config-sys_clk_freq,data-baud_rate);.static struct pl011_config pl011_cfg_port_#n=DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n),.sys_clk_freq=DT_INST_PROP_BY_PHANDLE(n,clocks,clock_frequency),PINCTRL_INIT(n);DTDriverUse the API with hardcoded SoC specific dataConsumer drive
7、r needs extra SoC specific knowledge about how to package opaque dataNo reusability without modifying consumer driverClocks in Zephyr today-Dynamic Clocks(Type A)device_foo compatible=“vendor,foo”;.clocks=;#include#define SOME_SOC_SPECIFIC_DATA 10.clock_control_on(cfg-clk_dev,(clock_subsys_t)SOME_SO
8、C_SPECIFIC_DATA);static struct foo_config foo_config_#n=DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n),.clk_dev=DT_INST_CLOCK_CTLR_GET_BY_IDX(n,clocks,0),;DTDriverUse the API with DT encoded producer specific dataConsumer driver needs extra producer specific knowledge about how to package opaque dataNo reusabi
9、lity without modifying consumer driverClocks in Zephyr today-Dynamic Clocks(Type B)device_foo compatible=“vendor,foo”;.clocks=;#include struct opaque_data uint32_t some_cell;.clock_control_on(cfg-clk_dev,(clock_subsys_t)cfg-clk_data);static const struct opaque_data foo_clock_data_#n=.some_cell=DT_IN
10、ST_CLOCKS_CELL_GET_BY_IDX(.,cell_name);static struct foo_config foo_config_#n=.base=DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n),.clk_dev=DT_INST_CLOCK_CTLR_GET_BY_IDX(n,clocks,0),.clk_data=&foo_clock_data_#n;DTDriverClocks in Zephyr today-Code Generation(Simplified)#clock-cells-const:1clock-cells-some-cell/
11、*devicetree-generated.h*/.DT_N_S_soc_S_clkc_400000000.DT_N_S_soc_S_uart_41000000_P_clocks_IDX_0_EXISTS 1DT_N_S_soc_S_uart_41000000_P_clocks_IDX_0_PH DT_N_S_soc_S_clkc_400000000DT_N_S_soc_S_uart_41000000_P_clocks_VAL_some_cell 10DT_N_S_soc_S_uart_41000000_P_clocks_VAL_some_cell_EXISTS 1.DT_N_S_soc_S_
12、uart_41000000_P_clocks_LEN 1DT_N_S_soc_S_uart_41000000_P_clocks_EXISTS 1DT Binding of ProducerGenerated Headersoc clkc:clk400000000 clock-frequency=;compatible=“vendor,some-clock-producer;#clock-cells=;uart:uart41000000 compatible=“vendor,uart-foo”;.clocks=;DT for Consumerscripts/dts/gen_defines.pyC
13、hange 1:fixed-clock needs a driverRemove clocks propertyAdd fixed-clock as a clock producer driverNeed to get back to thisChange 2:Rethink the APICurrent API on the right/*include/zephyr/drivers/clock_control.h*/int clock_control_on(const struct device*dev,clock_control_subsys_t sys);int clock_contr
14、ol_off(const struct device*dev,clock_control_subsys_t sys);int clock_control_async_on(const struct device*dev,clock_control_subsys_t sys,clock_control_cb_t cb,void*user_data);enum clock_control_status clock_control_get_status(const struct device*dev,clock_control_subsys_t sys);int clock_control_get_
15、rate(const struct device*dev,clock_control_subsys_t sys,uint32_t*rate);int clock_control_set_rate(const struct device*dev,clock_control_subsys_t sys,uint32_t rate);int clock_control_configure(const struct device*dev,clock_control_subsys_t sys,void*data);Change 2:Rethink the APIWhat we really want I
16、think is a struct clock to operate onThis struct clock encapsulates all info for a given clock/*include/zephyr/drivers/clock_control.h*/+struct clock_dt_spec;+struct clock+const struct device*dev;+const struct clock_dt_spec dt_spec;+;-int clock_control_on(const struct device*dev,clock_control_subsys
17、_t sys);+int clock_control_on(const struct clock*clk);-int clock_control_off(const struct device*dev,clock_control_subsys_t sys);+int clock_control_off(const struct clock*clk);-int clock_control_get_rate(const struct device*dev,-clock_control_subsys_t sys,uint32_t*rate);+int clock_control_get_rate(c
18、onst struct clock*clk,uint32_t*rate);-int clock_control_set_rate(const struct device*dev,-clock_control_subsys_t sys,uint32_t rate);+int clock_control_set_rate(const struct clock*clk,uint32_t rate);Change 3:How do consumers work?Introduce a new set of helpers to populate a struct clock/*include/zeph
19、yr/drivers/clock_control.h*/+struct clock_dt_spec+uint32_t cell_0;+uint32_t cell_1;+uint32_t cell_2;+;+struct clock+const struct device*dev;+const struct clock_dt_spec dt_spec;+;/*include/zephyr/devicetree/clocks.h*/+#define DT_CLOCKS_GET_CLOCK_BY_IDX(node_id,idx)+.dev=DEVICE_DT_GET(DT_CLOCKS_GET_CT
20、LR_BY_IDX(node_id,idx),+.dt_spec+.cell_0=DT_PHA_BY_IDX_OR(node_id,clocks,idx,generic_clock_cell_0,0)+.cell_1=DT_PHA_BY_IDX_OR(node_id,clocks,idx,generic_clock_cell_1,0)+.cell_2=DT_PHA_BY_IDX_OR(node_id,clocks,idx,generic_clock_cell_2,0)+.+Change 3:How do consumers work?/*include/zephyr/drivers/clock
21、_control.h*/+struct clock_dt_spec+uint32_t cell_0;+uint32_t cell_1;+uint32_t cell_2;+;+struct clock+const struct device*dev;+const struct clock_dt_spec dt_spec;+;/*include/zephyr/devicetree/clocks.h*/+#define DT_CLOCKS_GET_CLOCK_BY_IDX(node_id,idx)+.dev=DEVICE_DT_GET(DT_CLOCKS_GET_CTLR_BY_IDX(node_i
22、d,idx),+.dt_spec+.cell_0=DT_PHA_BY_IDX_OR(node_id,clocks,idx,generic_clock_cell_0,0)+.cell_1=DT_PHA_BY_IDX_OR(node_id,clocks,idx,generic_clock_cell_1,0)+.cell_2=DT_PHA_BY_IDX_OR(node_id,clocks,idx,generic_clock_cell_2,0)+.+Change 3:How do consumers work?/*include/zephyr/devicetree/clocks.h*/#define
23、DT_CLOCKS_GET_CLOCK_BY_IDX(node_id,idx).dev=DEVICE_DT_GET(DT_CLOCKS_GET_CTLR_BY_IDX(node_id,idx),.dt_spec.cell_0=DT_PHA_BY_IDX_OR(node_id,clocks,idx,generic_clock_cell_0,0).cell_1=DT_PHA_BY_IDX_OR(node_id,clocks,idx,generic_clock_cell_1,0).cell_2=DT_PHA_BY_IDX_OR(node_id,clocks,idx,generic_clock_cel
24、l_2,0).Modification to scripts/dts/gen_defines.pyIn addition to named clock cells we generated generic aliases/extra entriesRoom for improvement,on struct sizesLook for largest#clock-cells in DTKconfig/*devicetree-generated.h*/DT_N_S_soc_S_uart_41000000_P_clocks_IDX_0_EXISTS 1DT_N_S_soc_S_uart_41000
25、000_P_clocks_IDX_0_PH DT_N_S_soc_S_clkc_400000000DT_N_S_soc_S_uart_41000000_P_clocks_VAL_some_cell 10DT_N_S_soc_S_uart_41000000_P_clocks_VAL_some_cell_EXISTS 1DT_N_S_soc_S_uart_41000000_P_clocks_VAL_generic_clock_cell_0 10DT_N_S_soc_S_uart_41000000_P_clocks_VAL_generic_clock_cell_0_EXISTS 1.DT_N_S_s
26、oc_S_uart_41000000_P_clocks_LEN 1DT_N_S_soc_S_uart_41000000_P_clocks_EXISTS 1Generated HeaderChange 3:How do consumers work?struct foo_config struct clock clk;.;int foo_init(const struct device*dev)const struct foo_config*config=dev-config;int err;err=clock_control_on(&config-clk);if(err)return err;.#define FOO_INIT(n)struct foo_config foo_config_#n=.clk=DT_CLOCKS_INST_GET_CLOCK_BY_IDX(n,0);Decoupled producer and consumer?Opens&DiscussionLarge-ish changeSome SoCs do not encode clock relations in DTWhats the overhead for folks that dont care?How do we deal with clock dependencies?Lets discuss!