1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries
7 * Author: Varshini Rajendran <varshini.rajendran@microchip.com>
10 #include <linux/clk.h>
11 #include <linux/clk-provider.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/slab.h>
15 #include <dt-bindings/clock/at91.h>
19 static DEFINE_SPINLOCK(pmc_pll_lock
);
20 static DEFINE_SPINLOCK(mck_lock
);
23 * enum pll_ids - PLL clocks identifiers
24 * @PLL_ID_PLLA: PLLA identifier
25 * @PLL_ID_UPLL: UPLL identifier
26 * @PLL_ID_AUDIO: Audio PLL identifier
27 * @PLL_ID_LVDS: LVDS PLL identifier
28 * @PLL_ID_PLLA_DIV2: PLLA DIV2 identifier
29 * @PLL_ID_MAX: Max PLL Identifier
41 * enum pll_type - PLL type identifiers
42 * @PLL_TYPE_FRAC: fractional PLL identifier
43 * @PLL_TYPE_DIV: divider PLL identifier
50 static const struct clk_master_characteristics mck_characteristics
= {
51 .output
= { .min
= 32000000, .max
= 266666667 },
52 .divisors
= { 1, 2, 4, 3, 5},
56 static const struct clk_master_layout sam9x7_master_layout
= {
62 /* Fractional PLL core output range. */
63 static const struct clk_range plla_core_outputs
[] = {
64 { .min
= 375000000, .max
= 1600000000 },
67 static const struct clk_range upll_core_outputs
[] = {
68 { .min
= 600000000, .max
= 1200000000 },
71 static const struct clk_range lvdspll_core_outputs
[] = {
72 { .min
= 400000000, .max
= 800000000 },
75 static const struct clk_range audiopll_core_outputs
[] = {
76 { .min
= 400000000, .max
= 800000000 },
79 static const struct clk_range plladiv2_core_outputs
[] = {
80 { .min
= 375000000, .max
= 1600000000 },
83 /* Fractional PLL output range. */
84 static const struct clk_range plla_outputs
[] = {
85 { .min
= 732421, .max
= 800000000 },
88 static const struct clk_range upll_outputs
[] = {
89 { .min
= 300000000, .max
= 600000000 },
92 static const struct clk_range lvdspll_outputs
[] = {
93 { .min
= 10000000, .max
= 800000000 },
96 static const struct clk_range audiopll_outputs
[] = {
97 { .min
= 10000000, .max
= 800000000 },
100 static const struct clk_range plladiv2_outputs
[] = {
101 { .min
= 366210, .max
= 400000000 },
104 /* PLL characteristics. */
105 static const struct clk_pll_characteristics plla_characteristics
= {
106 .input
= { .min
= 20000000, .max
= 50000000 },
107 .num_output
= ARRAY_SIZE(plla_outputs
),
108 .output
= plla_outputs
,
109 .core_output
= plla_core_outputs
,
112 static const struct clk_pll_characteristics upll_characteristics
= {
113 .input
= { .min
= 20000000, .max
= 50000000 },
114 .num_output
= ARRAY_SIZE(upll_outputs
),
115 .output
= upll_outputs
,
116 .core_output
= upll_core_outputs
,
120 static const struct clk_pll_characteristics lvdspll_characteristics
= {
121 .input
= { .min
= 20000000, .max
= 50000000 },
122 .num_output
= ARRAY_SIZE(lvdspll_outputs
),
123 .output
= lvdspll_outputs
,
124 .core_output
= lvdspll_core_outputs
,
127 static const struct clk_pll_characteristics audiopll_characteristics
= {
128 .input
= { .min
= 20000000, .max
= 50000000 },
129 .num_output
= ARRAY_SIZE(audiopll_outputs
),
130 .output
= audiopll_outputs
,
131 .core_output
= audiopll_core_outputs
,
134 static const struct clk_pll_characteristics plladiv2_characteristics
= {
135 .input
= { .min
= 20000000, .max
= 50000000 },
136 .num_output
= ARRAY_SIZE(plladiv2_outputs
),
137 .output
= plladiv2_outputs
,
138 .core_output
= plladiv2_core_outputs
,
141 /* Layout for fractional PLL ID PLLA. */
142 static const struct clk_pll_layout plla_frac_layout
= {
143 .mul_mask
= GENMASK(31, 24),
144 .frac_mask
= GENMASK(21, 0),
150 /* Layout for fractional PLLs. */
151 static const struct clk_pll_layout pll_frac_layout
= {
152 .mul_mask
= GENMASK(31, 24),
153 .frac_mask
= GENMASK(21, 0),
158 /* Layout for DIV PLLs. */
159 static const struct clk_pll_layout pll_divpmc_layout
= {
160 .div_mask
= GENMASK(7, 0),
161 .endiv_mask
= BIT(29),
166 /* Layout for DIV PLL ID PLLADIV2. */
167 static const struct clk_pll_layout plladiv2_divpmc_layout
= {
168 .div_mask
= GENMASK(7, 0),
169 .endiv_mask
= BIT(29),
175 /* Layout for DIVIO dividers. */
176 static const struct clk_pll_layout pll_divio_layout
= {
177 .div_mask
= GENMASK(19, 12),
178 .endiv_mask
= BIT(30),
184 * PLL clocks description
189 * @c: pll characteristics
191 * @eid: export index in sam9x7->chws[] array
193 static const struct {
196 const struct clk_pll_layout
*l
;
198 const struct clk_pll_characteristics
*c
;
201 } sam9x7_plls
[][3] = {
206 .l
= &plla_frac_layout
,
209 * This feeds plla_divpmcck which feeds CPU. It should
212 .f
= CLK_IS_CRITICAL
| CLK_SET_RATE_GATE
,
213 .c
= &plla_characteristics
,
217 .n
= "plla_divpmcck",
219 .l
= &pll_divpmc_layout
,
221 /* This feeds CPU. It should not be disabled */
222 .f
= CLK_IS_CRITICAL
| CLK_SET_RATE_GATE
,
224 .c
= &plla_characteristics
,
232 .l
= &pll_frac_layout
,
234 .f
= CLK_SET_RATE_GATE
,
235 .c
= &upll_characteristics
,
239 .n
= "upll_divpmcck",
241 .l
= &pll_divpmc_layout
,
243 .f
= CLK_SET_RATE_GATE
| CLK_SET_PARENT_GATE
|
246 .c
= &upll_characteristics
,
252 .n
= "audiopll_fracck",
254 .l
= &pll_frac_layout
,
255 .f
= CLK_SET_RATE_GATE
,
256 .c
= &audiopll_characteristics
,
261 .n
= "audiopll_divpmcck",
262 .p
= "audiopll_fracck",
263 .l
= &pll_divpmc_layout
,
264 .f
= CLK_SET_RATE_GATE
| CLK_SET_PARENT_GATE
|
266 .c
= &audiopll_characteristics
,
267 .eid
= PMC_AUDIOPMCPLL
,
272 .n
= "audiopll_diviock",
273 .p
= "audiopll_fracck",
274 .l
= &pll_divio_layout
,
275 .f
= CLK_SET_RATE_GATE
| CLK_SET_PARENT_GATE
|
277 .c
= &audiopll_characteristics
,
278 .eid
= PMC_AUDIOIOPLL
,
285 .n
= "lvdspll_fracck",
287 .l
= &pll_frac_layout
,
288 .f
= CLK_SET_RATE_GATE
,
289 .c
= &lvdspll_characteristics
,
294 .n
= "lvdspll_divpmcck",
295 .p
= "lvdspll_fracck",
296 .l
= &pll_divpmc_layout
,
297 .f
= CLK_SET_RATE_GATE
| CLK_SET_PARENT_GATE
|
299 .c
= &lvdspll_characteristics
,
305 [PLL_ID_PLLA_DIV2
] = {
307 .n
= "plla_div2pmcck",
309 .l
= &plladiv2_divpmc_layout
,
311 * This may feed critical parts of the system like timers.
312 * It should not be disabled.
314 .f
= CLK_IS_CRITICAL
| CLK_SET_RATE_GATE
,
315 .c
= &plladiv2_characteristics
,
322 static const struct clk_programmable_layout sam9x7_programmable_layout
= {
330 static const struct clk_pcr_layout sam9x7_pcr_layout
= {
333 .gckcss_mask
= GENMASK(12, 8),
334 .pid_mask
= GENMASK(6, 0),
337 static const struct {
342 } sam9x7_systemck
[] = {
344 * ddrck feeds DDR controller and is enabled by bootloader thus we need
345 * to keep it enabled in case there is no Linux consumer for it.
347 { .n
= "ddrck", .p
= "masterck_div", .id
= 2, .flags
= CLK_IS_CRITICAL
},
348 { .n
= "uhpck", .p
= "usbck", .id
= 6 },
349 { .n
= "pck0", .p
= "prog0", .id
= 8 },
350 { .n
= "pck1", .p
= "prog1", .id
= 9 },
354 * Peripheral clocks description
359 static const struct {
363 } sam9x7_periphck
[] = {
364 { .n
= "pioA_clk", .id
= 2, },
365 { .n
= "pioB_clk", .id
= 3, },
366 { .n
= "pioC_clk", .id
= 4, },
367 { .n
= "flex0_clk", .id
= 5, },
368 { .n
= "flex1_clk", .id
= 6, },
369 { .n
= "flex2_clk", .id
= 7, },
370 { .n
= "flex3_clk", .id
= 8, },
371 { .n
= "flex6_clk", .id
= 9, },
372 { .n
= "flex7_clk", .id
= 10, },
373 { .n
= "flex8_clk", .id
= 11, },
374 { .n
= "sdmmc0_clk", .id
= 12, },
375 { .n
= "flex4_clk", .id
= 13, },
376 { .n
= "flex5_clk", .id
= 14, },
377 { .n
= "flex9_clk", .id
= 15, },
378 { .n
= "flex10_clk", .id
= 16, },
379 { .n
= "tcb0_clk", .id
= 17, },
380 { .n
= "pwm_clk", .id
= 18, },
381 { .n
= "adc_clk", .id
= 19, },
382 { .n
= "dma0_clk", .id
= 20, },
383 { .n
= "uhphs_clk", .id
= 22, },
384 { .n
= "udphs_clk", .id
= 23, },
385 { .n
= "macb0_clk", .id
= 24, },
386 { .n
= "lcd_clk", .id
= 25, },
387 { .n
= "sdmmc1_clk", .id
= 26, },
388 { .n
= "ssc_clk", .id
= 28, },
389 { .n
= "can0_clk", .id
= 29, },
390 { .n
= "can1_clk", .id
= 30, },
391 { .n
= "flex11_clk", .id
= 32, },
392 { .n
= "flex12_clk", .id
= 33, },
393 { .n
= "i2s_clk", .id
= 34, },
394 { .n
= "qspi_clk", .id
= 35, },
395 { .n
= "gfx2d_clk", .id
= 36, },
396 { .n
= "pit64b0_clk", .id
= 37, },
397 { .n
= "trng_clk", .id
= 38, },
398 { .n
= "aes_clk", .id
= 39, },
399 { .n
= "tdes_clk", .id
= 40, },
400 { .n
= "sha_clk", .id
= 41, },
401 { .n
= "classd_clk", .id
= 42, },
402 { .n
= "isi_clk", .id
= 43, },
403 { .n
= "pioD_clk", .id
= 44, },
404 { .n
= "tcb1_clk", .id
= 45, },
405 { .n
= "dbgu_clk", .id
= 47, },
407 * mpddr_clk feeds DDR controller and is enabled by bootloader thus we
408 * need to keep it enabled in case there is no Linux consumer for it.
410 { .n
= "mpddr_clk", .id
= 49, .f
= CLK_IS_CRITICAL
},
411 { .n
= "csi2dc_clk", .id
= 52, },
412 { .n
= "csi4l_clk", .id
= 53, },
413 { .n
= "dsi4l_clk", .id
= 54, },
414 { .n
= "lvdsc_clk", .id
= 56, },
415 { .n
= "pit64b1_clk", .id
= 58, },
416 { .n
= "puf_clk", .id
= 59, },
417 { .n
= "gmactsu_clk", .id
= 67, },
421 * Generic clock description
424 * @pp_mux_table: PLL parents mux table
425 * @r: clock output range
426 * @pp_chg_id: id in parent array of changeable PLL parent
427 * @pp_count: PLL parents count
430 static const struct {
433 const char pp_mux_table
[8];
442 .pp
= { "plla_div2pmcck", },
443 .pp_mux_table
= { 8, },
445 .pp_chg_id
= INT_MIN
,
451 .pp
= { "plla_div2pmcck", },
452 .pp_mux_table
= { 8, },
454 .pp_chg_id
= INT_MIN
,
460 .pp
= { "plla_div2pmcck", },
461 .pp_mux_table
= { 8, },
463 .pp_chg_id
= INT_MIN
,
469 .pp
= { "plla_div2pmcck", },
470 .pp_mux_table
= { 8, },
472 .pp_chg_id
= INT_MIN
,
478 .pp
= { "plla_div2pmcck", },
479 .pp_mux_table
= { 8, },
481 .pp_chg_id
= INT_MIN
,
487 .pp
= { "plla_div2pmcck", },
488 .pp_mux_table
= { 8, },
490 .pp_chg_id
= INT_MIN
,
496 .pp
= { "plla_div2pmcck", },
497 .pp_mux_table
= { 8, },
499 .pp_chg_id
= INT_MIN
,
505 .r
= { .max
= 105000000 },
506 .pp
= { "audiopll_divpmcck", "plla_div2pmcck", },
507 .pp_mux_table
= { 6, 8, },
509 .pp_chg_id
= INT_MIN
,
515 .pp
= { "plla_div2pmcck", },
516 .pp_mux_table
= { 8, },
518 .pp_chg_id
= INT_MIN
,
524 .pp
= { "plla_div2pmcck", },
525 .pp_mux_table
= { 8, },
527 .pp_chg_id
= INT_MIN
,
533 .pp
= { "plla_div2pmcck", },
534 .pp_mux_table
= { 8, },
536 .pp_chg_id
= INT_MIN
,
542 .pp
= { "plla_div2pmcck", },
543 .pp_mux_table
= { 8, },
545 .pp_chg_id
= INT_MIN
,
551 .pp
= { "audiopll_divpmcck", "plla_div2pmcck", },
552 .pp_mux_table
= { 6, 8, },
554 .pp_chg_id
= INT_MIN
,
560 .pp
= { "upll_divpmcck", "plla_div2pmcck", },
561 .pp_mux_table
= { 5, 8, },
563 .pp_chg_id
= INT_MIN
,
569 .r
= { .max
= 75000000 },
570 .pp
= { "audiopll_divpmcck", "plla_div2pmcck", },
571 .pp_mux_table
= { 6, 8, },
573 .pp_chg_id
= INT_MIN
,
579 .r
= { .max
= 105000000 },
580 .pp
= { "audiopll_divpmcck", "plla_div2pmcck", },
581 .pp_mux_table
= { 6, 8, },
583 .pp_chg_id
= INT_MIN
,
589 .r
= { .max
= 80000000 },
590 .pp
= { "upll_divpmcck", "plla_div2pmcck", },
591 .pp_mux_table
= { 5, 8, },
593 .pp_chg_id
= INT_MIN
,
599 .r
= { .max
= 80000000 },
600 .pp
= { "upll_divpmcck", "plla_div2pmcck", },
601 .pp_mux_table
= { 5, 8, },
603 .pp_chg_id
= INT_MIN
,
609 .pp
= { "plla_div2pmcck", },
610 .pp_mux_table
= { 8, },
612 .pp_chg_id
= INT_MIN
,
618 .pp
= { "plla_div2pmcck", },
619 .pp_mux_table
= { 8, },
621 .pp_chg_id
= INT_MIN
,
627 .r
= { .max
= 100000000 },
628 .pp
= { "audiopll_divpmcck", "plla_div2pmcck", },
629 .pp_mux_table
= { 6, 8, },
631 .pp_chg_id
= INT_MIN
,
637 .r
= { .max
= 200000000 },
638 .pp
= { "audiopll_divpmcck", "plla_div2pmcck", },
639 .pp_mux_table
= { 6, 8, },
641 .pp_chg_id
= INT_MIN
,
647 .pp
= { "plla_div2pmcck", },
648 .pp_mux_table
= { 8, },
650 .pp_chg_id
= INT_MIN
,
656 .r
= { .max
= 100000000 },
657 .pp
= { "audiopll_divpmcck", "plla_div2pmcck", },
658 .pp_mux_table
= { 6, 8, },
660 .pp_chg_id
= INT_MIN
,
666 .pp
= { "audiopll_divpmcck", "plla_div2pmcck", },
667 .pp_mux_table
= { 6, 8, },
669 .pp_chg_id
= INT_MIN
,
675 .pp
= { "plla_div2pmcck", },
676 .pp_mux_table
= { 8, },
678 .pp_chg_id
= INT_MIN
,
684 .r
= { .max
= 27000000 },
685 .pp
= { "plla_div2pmcck", },
686 .pp_mux_table
= { 8, },
688 .pp_chg_id
= INT_MIN
,
694 .pp
= { "plla_div2pmcck", },
695 .pp_mux_table
= { 8, },
697 .pp_chg_id
= INT_MIN
,
703 .pp
= { "audiopll_divpmcck", "plla_div2pmcck", },
704 .pp_mux_table
= { 6, 8, },
706 .pp_chg_id
= INT_MIN
,
710 static void __init
sam9x7_pmc_setup(struct device_node
*np
)
712 struct clk_range range
= CLK_RANGE(0, 0);
713 const char *td_slck_name
, *md_slck_name
, *mainxtal_name
;
714 struct pmc_data
*sam9x7_pmc
;
715 const char *parent_names
[9];
716 void **clk_mux_buffer
= NULL
;
717 int clk_mux_buffer_size
= 0;
718 struct clk_hw
*main_osc_hw
;
719 struct regmap
*regmap
;
723 i
= of_property_match_string(np
, "clock-names", "td_slck");
727 td_slck_name
= of_clk_get_parent_name(np
, i
);
729 i
= of_property_match_string(np
, "clock-names", "md_slck");
733 md_slck_name
= of_clk_get_parent_name(np
, i
);
735 i
= of_property_match_string(np
, "clock-names", "main_xtal");
738 mainxtal_name
= of_clk_get_parent_name(np
, i
);
740 regmap
= device_node_to_regmap(np
);
744 sam9x7_pmc
= pmc_data_allocate(PMC_LVDSPLL
+ 1,
745 nck(sam9x7_systemck
),
746 nck(sam9x7_periphck
),
751 clk_mux_buffer
= kmalloc(sizeof(void *) *
752 (ARRAY_SIZE(sam9x7_gck
)),
757 hw
= at91_clk_register_main_rc_osc(regmap
, "main_rc_osc", 12000000,
762 hw
= at91_clk_register_main_osc(regmap
, "main_osc", mainxtal_name
, NULL
, 0);
767 parent_names
[0] = "main_rc_osc";
768 parent_names
[1] = "main_osc";
769 hw
= at91_clk_register_sam9x5_main(regmap
, "mainck", parent_names
, NULL
, 2);
773 sam9x7_pmc
->chws
[PMC_MAIN
] = hw
;
775 for (i
= 0; i
< PLL_ID_MAX
; i
++) {
776 for (j
= 0; j
< 3; j
++) {
777 struct clk_hw
*parent_hw
;
779 if (!sam9x7_plls
[i
][j
].n
)
782 switch (sam9x7_plls
[i
][j
].t
) {
784 if (!strcmp(sam9x7_plls
[i
][j
].p
, "mainck"))
785 parent_hw
= sam9x7_pmc
->chws
[PMC_MAIN
];
786 else if (!strcmp(sam9x7_plls
[i
][j
].p
, "main_osc"))
787 parent_hw
= main_osc_hw
;
789 parent_hw
= __clk_get_hw(of_clk_get_by_name
790 (np
, sam9x7_plls
[i
][j
].p
));
792 hw
= sam9x60_clk_register_frac_pll(regmap
,
799 sam9x7_plls
[i
][j
].f
);
803 hw
= sam9x60_clk_register_div_pll(regmap
,
806 sam9x7_plls
[i
][j
].p
, NULL
, i
,
809 sam9x7_plls
[i
][j
].f
, 0);
819 if (sam9x7_plls
[i
][j
].eid
)
820 sam9x7_pmc
->chws
[sam9x7_plls
[i
][j
].eid
] = hw
;
824 parent_names
[0] = md_slck_name
;
825 parent_names
[1] = "mainck";
826 parent_names
[2] = "plla_divpmcck";
827 parent_names
[3] = "upll_divpmcck";
828 hw
= at91_clk_register_master_pres(regmap
, "masterck_pres", 4,
829 parent_names
, NULL
, &sam9x7_master_layout
,
830 &mck_characteristics
, &mck_lock
);
834 hw
= at91_clk_register_master_div(regmap
, "masterck_div",
835 "masterck_pres", NULL
, &sam9x7_master_layout
,
836 &mck_characteristics
, &mck_lock
,
837 CLK_SET_RATE_GATE
, 0);
841 sam9x7_pmc
->chws
[PMC_MCK
] = hw
;
843 parent_names
[0] = "plla_divpmcck";
844 parent_names
[1] = "upll_divpmcck";
845 parent_names
[2] = "main_osc";
846 hw
= sam9x60_clk_register_usb(regmap
, "usbck", parent_names
, 3);
850 parent_names
[0] = md_slck_name
;
851 parent_names
[1] = td_slck_name
;
852 parent_names
[2] = "mainck";
853 parent_names
[3] = "masterck_div";
854 parent_names
[4] = "plla_divpmcck";
855 parent_names
[5] = "upll_divpmcck";
856 parent_names
[6] = "audiopll_divpmcck";
857 for (i
= 0; i
< 2; i
++) {
860 snprintf(name
, sizeof(name
), "prog%d", i
);
862 hw
= at91_clk_register_programmable(regmap
, name
,
863 parent_names
, NULL
, 7, i
,
864 &sam9x7_programmable_layout
,
869 sam9x7_pmc
->pchws
[i
] = hw
;
872 for (i
= 0; i
< ARRAY_SIZE(sam9x7_systemck
); i
++) {
873 hw
= at91_clk_register_system(regmap
, sam9x7_systemck
[i
].n
,
874 sam9x7_systemck
[i
].p
, NULL
,
875 sam9x7_systemck
[i
].id
,
876 sam9x7_systemck
[i
].flags
);
880 sam9x7_pmc
->shws
[sam9x7_systemck
[i
].id
] = hw
;
883 for (i
= 0; i
< ARRAY_SIZE(sam9x7_periphck
); i
++) {
884 hw
= at91_clk_register_sam9x5_peripheral(regmap
, &pmc_pcr_lock
,
886 sam9x7_periphck
[i
].n
,
887 "masterck_div", NULL
,
888 sam9x7_periphck
[i
].id
,
890 sam9x7_periphck
[i
].f
);
894 sam9x7_pmc
->phws
[sam9x7_periphck
[i
].id
] = hw
;
897 parent_names
[0] = md_slck_name
;
898 parent_names
[1] = td_slck_name
;
899 parent_names
[2] = "mainck";
900 parent_names
[3] = "masterck_div";
901 for (i
= 0; i
< ARRAY_SIZE(sam9x7_gck
); i
++) {
902 u8 num_parents
= 4 + sam9x7_gck
[i
].pp_count
;
905 mux_table
= kmalloc_array(num_parents
, sizeof(*mux_table
),
910 PMC_INIT_TABLE(mux_table
, 4);
911 PMC_FILL_TABLE(&mux_table
[4], sam9x7_gck
[i
].pp_mux_table
,
912 sam9x7_gck
[i
].pp_count
);
913 PMC_FILL_TABLE(&parent_names
[4], sam9x7_gck
[i
].pp
,
914 sam9x7_gck
[i
].pp_count
);
916 hw
= at91_clk_register_generated(regmap
, &pmc_pcr_lock
,
919 parent_names
, NULL
, mux_table
,
923 sam9x7_gck
[i
].pp_chg_id
);
927 sam9x7_pmc
->ghws
[sam9x7_gck
[i
].id
] = hw
;
928 clk_mux_buffer
[clk_mux_buffer_size
++] = mux_table
;
931 of_clk_add_hw_provider(np
, of_clk_hw_pmc_get
, sam9x7_pmc
);
932 kfree(clk_mux_buffer
);
937 if (clk_mux_buffer
) {
938 for (i
= 0; i
< clk_mux_buffer_size
; i
++)
939 kfree(clk_mux_buffer
[i
]);
940 kfree(clk_mux_buffer
);
945 /* Some clks are used for a clocksource */
946 CLK_OF_DECLARE(sam9x7_pmc
, "microchip,sam9x7-pmc", sam9x7_pmc_setup
);