@@ -41,7 +41,7 @@ static uint32_t extract_field(uint32_t raw, uint8_t shift, uint8_t width) {
4141 return (raw >> shift ) & mask ;
4242}
4343
44- static cJSON * decode_pll (const struct pll_info * pll ) {
44+ static cJSON * decode_pll (const struct pll_info * pll , bool brief ) {
4545 cJSON * j_inner = cJSON_CreateObject ();
4646
4747 /* Read ctrl_reg1 (FRACDIV / POSTDIV1 / POSTDIV2) */
@@ -56,9 +56,6 @@ static cJSON *decode_pll(const struct pll_info *pll) {
5656
5757 if (!ok1 || !ok2 ) {
5858 ADD_PARAM ("error" , "register read failed" );
59- ADD_PARAM_FMT ("ctrl_reg1" , "0x%08x" , pll -> ctrl_reg1 );
60- if (pll -> ctrl_reg2 )
61- ADD_PARAM_FMT ("ctrl_reg2" , "0x%08x" , pll -> ctrl_reg2 );
6259 return j_inner ;
6360 }
6461
@@ -76,6 +73,23 @@ static cJSON *decode_pll(const struct pll_info *pll) {
7673 if (pll -> refdiv_width == 0 )
7774 refdiv = 1 ;
7875
76+ /* Compute frequency. f = input * (FBDIV + FRACDIV/2^frac_width) /
77+ * (REFDIV * POSTDIV1 * POSTDIV2). */
78+ double freq_mhz = 0.0 ;
79+ uint32_t denom = refdiv * pdiv1 * pdiv2 ;
80+ if (fbdiv != 0 && denom != 0 ) {
81+ uint64_t numer_khz = (uint64_t )pll -> input_khz * fbdiv ;
82+ if (pll -> frac_width )
83+ numer_khz +=
84+ ((uint64_t )pll -> input_khz * fracdiv ) >> pll -> frac_width ;
85+ freq_mhz = (double )numer_khz / (double )denom / 1000.0 ;
86+ }
87+
88+ if (brief ) {
89+ ADD_PARAM_NUM ("freq_mhz" , freq_mhz );
90+ return j_inner ;
91+ }
92+
7993 ADD_PARAM_FMT ("ctrl_reg1" , "0x%08x" , pll -> ctrl_reg1 );
8094 ADD_PARAM_FMT ("ctrl_reg1_raw" , "0x%08x" , raw1 );
8195 if (pll -> ctrl_reg2 && pll -> ctrl_reg2 != pll -> ctrl_reg1 ) {
@@ -88,70 +102,28 @@ static cJSON *decode_pll(const struct pll_info *pll) {
88102 ADD_PARAM_NUM ("postdiv2" , pdiv2 );
89103 if (pll -> frac_width )
90104 ADD_PARAM_FMT ("fracdiv" , "0x%06x" , fracdiv );
91-
92- if (fbdiv == 0 ) {
93- ADD_PARAM ("note" , "PLL gated (FBDIV=0)" );
94- ADD_PARAM_NUM ("freq_mhz" , 0 );
95- return j_inner ;
96- }
97- uint32_t denom = refdiv * pdiv1 * pdiv2 ;
98- if (denom == 0 ) {
99- ADD_PARAM ("note" , "invalid divisor (REFDIV*POSTDIV1*POSTDIV2 = 0)" );
100- ADD_PARAM_NUM ("freq_mhz" , 0 );
101- return j_inner ;
102- }
103- /* f = input * (FBDIV + FRACDIV/2^24) / (REFDIV * POSTDIV1 * POSTDIV2)
104- * Compute in microhertz to keep the integer part exact. */
105- uint64_t numer_khz = (uint64_t )pll -> input_khz * fbdiv ;
106- if (pll -> frac_width )
107- numer_khz += ((uint64_t )pll -> input_khz * fracdiv ) >> pll -> frac_width ;
108- double freq_mhz = (double )numer_khz / (double )denom / 1000.0 ;
109105 ADD_PARAM_NUM ("freq_mhz" , freq_mhz );
110- return j_inner ;
111- }
112106
113- static cJSON * decode_raw (const struct raw_reg_info * r ) {
114- cJSON * j_inner = cJSON_CreateObject ();
115- uint32_t raw1 ;
116- if (!mem_reg (r -> reg , & raw1 , OP_READ )) {
117- ADD_PARAM ("error" , "register read failed" );
118- ADD_PARAM_FMT ("reg" , "0x%08x" , r -> reg );
119- return j_inner ;
120- }
121- if (r -> reg2 ) {
122- /* Two-register PLL config pair: report both raws. */
123- uint32_t raw2 ;
124- bool ok2 = mem_reg (r -> reg2 , & raw2 , OP_READ );
125- ADD_PARAM_FMT ("ctrl_reg1" , "0x%08x" , r -> reg );
126- ADD_PARAM_FMT ("ctrl_reg1_raw" , "0x%08x" , raw1 );
127- ADD_PARAM_FMT ("ctrl_reg2" , "0x%08x" , r -> reg2 );
128- if (ok2 )
129- ADD_PARAM_FMT ("ctrl_reg2_raw" , "0x%08x" , raw2 );
130- else
131- ADD_PARAM ("ctrl_reg2_raw" , "<read failed>" );
132- } else {
133- ADD_PARAM_FMT ("reg" , "0x%08x" , r -> reg );
134- ADD_PARAM_FMT ("raw" , "0x%08x" , raw1 );
107+ /* Optional lock-bit check (e.g. PERI_CRG_PLL122 bit 0 = APLL on V4). */
108+ if (pll -> lock_reg ) {
109+ uint32_t lock_raw ;
110+ if (mem_reg (pll -> lock_reg , & lock_raw , OP_READ )) {
111+ bool locked = (lock_raw >> pll -> lock_bit ) & 1u ;
112+ cJSON_AddItemToObject (j_inner , "locked" , cJSON_CreateBool (locked ));
113+ }
135114 }
136- if (r -> note )
137- ADD_PARAM ("note" , r -> note );
138115 return j_inner ;
139116}
140117
141- static cJSON * decode_mux (const struct mux_info * mux ) {
118+ static cJSON * decode_mux (const struct mux_info * mux , bool brief ) {
142119 cJSON * j_inner = cJSON_CreateObject ();
143120 uint32_t raw ;
144121 if (!mem_reg (mux -> reg , & raw , OP_READ )) {
145122 ADD_PARAM ("error" , "register read failed" );
146- ADD_PARAM_FMT ("reg" , "0x%08x" , mux -> reg );
147123 return j_inner ;
148124 }
149125 uint8_t sel = (raw >> mux -> sel_shift ) & mux -> sel_mask ;
150126
151- ADD_PARAM_FMT ("reg" , "0x%08x" , mux -> reg );
152- ADD_PARAM_FMT ("raw" , "0x%08x" , raw );
153- ADD_PARAM_NUM ("cksel" , sel );
154-
155127 uint16_t mhz = 0 ;
156128 bool found = false;
157129 for (size_t i = 0 ; i < mux -> table_len ; i ++ ) {
@@ -161,12 +133,23 @@ static cJSON *decode_mux(const struct mux_info *mux) {
161133 break ;
162134 }
163135 }
136+
137+ if (brief ) {
138+ if (mux -> rate_mult )
139+ ADD_PARAM_NUM ("data_rate_mbps" ,
140+ (uint32_t )mhz * (found ? mux -> rate_mult : 0 ));
141+ else
142+ ADD_PARAM_NUM ("freq_mhz" , mhz );
143+ return j_inner ;
144+ }
145+
146+ ADD_PARAM_FMT ("reg" , "0x%08x" , mux -> reg );
147+ ADD_PARAM_FMT ("raw" , "0x%08x" , raw );
148+ ADD_PARAM_NUM ("cksel" , sel );
164149 if (found ) {
165150 ADD_PARAM_NUM ("freq_mhz" , mhz );
166151 if (mux -> rate_mult )
167152 ADD_PARAM_NUM ("data_rate_mbps" , (uint32_t )mhz * mux -> rate_mult );
168- } else {
169- ADD_PARAM ("note" , "cksel value not in known table" );
170153 }
171154 return j_inner ;
172155}
@@ -188,19 +171,23 @@ static const char *hpm_bin(uint16_t v, const struct hpm_info *h) {
188171 return "high" ;
189172}
190173
191- static cJSON * decode_hpm (const struct hpm_info * h ) {
174+ static cJSON * decode_hpm (const struct hpm_info * h , bool brief ) {
192175 cJSON * j_inner = cJSON_CreateObject ();
193176 uint32_t raw ;
194177 if (!mem_reg (h -> reg , & raw , OP_READ ) || raw == 0xFFFFFFFF ) {
195- /* HPM register absent on this variant — caller should treat NULL-ish
196- * by simply omitting; we return an empty object and let the parent
197- * decide. */
178+ /* HPM register absent on this variant — caller treats NULL by
179+ * omitting the section entirely. */
198180 cJSON_Delete (j_inner );
199181 return NULL ;
200182 }
201183 uint16_t value = (raw >> h -> value_shift ) & h -> value_mask ;
202184 const char * bin = hpm_bin (value , h );
203185
186+ if (brief ) {
187+ ADD_PARAM ("bin" , bin );
188+ return j_inner ;
189+ }
190+
204191 ADD_PARAM_FMT ("reg" , "0x%08x" , h -> reg );
205192 ADD_PARAM_FMT ("raw" , "0x%08x" , raw );
206193 ADD_PARAM_NUM ("value" , value );
@@ -211,12 +198,6 @@ static cJSON *decode_hpm(const struct hpm_info *h) {
211198 cJSON_AddItemToArray (window , cJSON_CreateNumber (h -> bin_max ));
212199 cJSON_AddItemToObject (j_inner , "binning_window" , window );
213200
214- if (!strcmp (bin , "low" ) || !strcmp (bin , "below_window" )) {
215- ADD_PARAM ("note" ,
216- "low-bin silicon; mask ROM may have selected a reduced PLL "
217- "multiplier at boot" );
218- }
219-
220201 if (h -> aux_reg ) {
221202 uint32_t aux ;
222203 if (mem_reg (h -> aux_reg , & aux , OP_READ )) {
@@ -278,36 +259,7 @@ static cJSON *build_cpu_running(void) {
278259 return j_inner ;
279260}
280261
281- static void add_plls (cJSON * parent , const struct clock_family * fam ) {
282- for (size_t i = 0 ; i < fam -> n_plls ; i ++ ) {
283- cJSON * p = decode_pll (& fam -> plls [i ]);
284- cJSON_AddItemToObject (parent , fam -> plls [i ].name , p );
285- }
286- }
287-
288- static void add_muxes (cJSON * parent , const struct clock_family * fam ) {
289- for (size_t i = 0 ; i < fam -> n_muxes ; i ++ ) {
290- cJSON * m = decode_mux (& fam -> muxes [i ]);
291- cJSON_AddItemToObject (parent , fam -> muxes [i ].name , m );
292- }
293- }
294-
295- static void add_hpms (cJSON * parent , const struct clock_family * fam ) {
296- for (size_t i = 0 ; i < fam -> n_hpms ; i ++ ) {
297- cJSON * h = decode_hpm (& fam -> hpms [i ]);
298- if (h )
299- cJSON_AddItemToObject (parent , fam -> hpms [i ].name , h );
300- }
301- }
302-
303- static void add_raws (cJSON * parent , const struct clock_family * fam ) {
304- for (size_t i = 0 ; i < fam -> n_raws ; i ++ ) {
305- cJSON * r = decode_raw (& fam -> raws [i ]);
306- cJSON_AddItemToObject (parent , fam -> raws [i ].name , r );
307- }
308- }
309-
310- cJSON * clocks_build_json (void ) {
262+ cJSON * clocks_build_json (bool brief ) {
311263 /* Make sure chip detection has run and chip_generation is populated. */
312264 if (!getchipname ())
313265 return NULL ;
@@ -317,17 +269,26 @@ cJSON *clocks_build_json(void) {
317269 return NULL ;
318270
319271 cJSON * j_inner = cJSON_CreateObject ();
320- ADD_PARAM ("family" , fam -> label );
321-
322- add_plls (j_inner , fam );
323- add_muxes (j_inner , fam );
324- add_hpms (j_inner , fam );
325- add_raws (j_inner , fam );
326272
327- cJSON * running = build_cpu_running ();
328- if (running )
329- cJSON_AddItemToObject (j_inner , "cpu_running" , running );
273+ for (size_t i = 0 ; i < fam -> n_plls ; i ++ ) {
274+ cJSON * p = decode_pll (& fam -> plls [i ], brief );
275+ cJSON_AddItemToObject (j_inner , fam -> plls [i ].name , p );
276+ }
277+ for (size_t i = 0 ; i < fam -> n_muxes ; i ++ ) {
278+ cJSON * m = decode_mux (& fam -> muxes [i ], brief );
279+ cJSON_AddItemToObject (j_inner , fam -> muxes [i ].name , m );
280+ }
281+ for (size_t i = 0 ; i < fam -> n_hpms ; i ++ ) {
282+ cJSON * h = decode_hpm (& fam -> hpms [i ], brief );
283+ if (h )
284+ cJSON_AddItemToObject (j_inner , fam -> hpms [i ].name , h );
285+ }
330286
287+ if (!brief ) {
288+ cJSON * running = build_cpu_running ();
289+ if (running )
290+ cJSON_AddItemToObject (j_inner , "cpu_running" , running );
291+ }
331292 return j_inner ;
332293}
333294
@@ -382,7 +343,7 @@ int clocks_cmd(int argc, char **argv) {
382343 return EXIT_FAILURE ;
383344 }
384345
385- cJSON * clocks = clocks_build_json ();
346+ cJSON * clocks = clocks_build_json (false );
386347 if (!clocks ) {
387348 fprintf (stderr , "clocks: failed to build clock info\n" );
388349 return EXIT_FAILURE ;
0 commit comments