@@ -220,6 +220,97 @@ static int __init get_percent_margin_volt(char *str)
220220}
221221early_param ("volt_offset_percent" , get_percent_margin_volt );
222222
223+ static void * fvmap_alloc_extra (size_t size , size_t align )
224+ {
225+ void * ptr ;
226+
227+ fvmap_alloc_offset = ALIGN (fvmap_alloc_offset , align );
228+ if (fvmap_alloc_offset + size > fvmap_alloc_limit )
229+ return NULL ;
230+
231+ ptr = fvmap_base + fvmap_alloc_offset ;
232+ fvmap_alloc_offset += size ;
233+
234+ return ptr ;
235+ }
236+
237+ static bool fvmap_extend_g3d (struct fvmap_header * fvmap_header ,
238+ void __iomem * map_base , void __iomem * sram_base ,
239+ struct vclk * vclk )
240+ {
241+ const unsigned int oc_rate = 754000 ;
242+ const int old_lv = fvmap_header -> num_of_lv ;
243+ int new_lv = 13 ;
244+ struct rate_volt_header * old_rv , * new_rv ;
245+ struct dvfs_table * old_tbl , * new_tbl ;
246+ int members = fvmap_header -> num_of_members ;
247+ bool have_oc ;
248+
249+ old_rv = sram_base + fvmap_header -> o_ratevolt ;
250+ have_oc = old_lv > 0 && old_rv -> table [0 ].rate == oc_rate ;
251+
252+ if (old_lv >= new_lv && have_oc )
253+ return false;
254+
255+ if (old_lv >= new_lv )
256+ new_lv = old_lv + 1 ;
257+
258+ new_rv = fvmap_alloc_extra (sizeof (struct rate_volt ) * new_lv ,
259+ __alignof__(struct rate_volt ));
260+ if (!new_rv ) {
261+ pr_err ("[%s] g3d: no space for extended rate/volt table\n" ,
262+ __func__ );
263+ return false;
264+ }
265+
266+ /* insert OC level at the top and shift existing entries down */
267+ new_rv -> table [0 ].rate = oc_rate ;
268+ new_rv -> table [0 ].volt = old_rv -> table [0 ].volt ;
269+ memcpy (& new_rv -> table [1 ], & old_rv -> table [0 ],
270+ sizeof (struct rate_volt ) * old_lv );
271+
272+ old_tbl = sram_base + fvmap_header -> o_tables ;
273+ new_tbl = fvmap_alloc_extra (members * new_lv , 1 );
274+ if (!new_tbl ) {
275+ pr_err ("[%s] g3d: no space for extended dvfs table\n" ,
276+ __func__ );
277+ return false;
278+ }
279+
280+ memcpy (& new_tbl -> val [0 ], & old_tbl -> val [0 ], members );
281+ memcpy (& new_tbl -> val [members ], & old_tbl -> val [0 ], members * old_lv );
282+
283+ fvmap_header -> o_ratevolt = (unsigned short )((void * )new_rv - map_base );
284+ fvmap_header -> o_tables = (unsigned short )((void * )new_tbl - map_base );
285+ fvmap_header -> num_of_lv = new_lv ;
286+ if (fvmap_header -> init_lv < new_lv )
287+ fvmap_header -> init_lv += 1 ;
288+
289+ pr_info ("dvfs_g3d: extended FV table %d -> %d levels (OC 754MHz)\n" ,
290+ old_lv , new_lv );
291+
292+ /* update vclk LUT to expose the new OC rate to CAL/clients */
293+ if (vclk && vclk -> lut ) {
294+ int lut_sz = vclk -> num_rates ;
295+ int copy_lv = min (new_lv - 1 , old_lv );
296+ int idx ;
297+
298+ if (lut_sz < new_lv )
299+ lut_sz = new_lv ;
300+
301+ for (idx = min (lut_sz - 1 , copy_lv ); idx > 0 ; idx -- )
302+ vclk -> lut [idx ].rate = vclk -> lut [idx - 1 ].rate ;
303+
304+ vclk -> lut [0 ].rate = oc_rate ;
305+ vclk -> num_rates = max (vclk -> num_rates , (unsigned int )new_lv );
306+ vclk -> max_freq = max (vclk -> max_freq , oc_rate );
307+ vclk -> min_freq = min (vclk -> min_freq ,
308+ new_rv -> table [new_lv - 1 ].rate );
309+ }
310+
311+ return true;
312+ }
313+
223314int fvmap_set_raw_voltage_table (unsigned int id , int uV )
224315{
225316 struct fvmap_header * fvmap_header ;
0 commit comments