11#include <linux/types.h>
22#include <linux/kernel.h>
33#include <linux/slab.h>
4+ #include <linux/string.h>
45#include <linux/io.h>
56#include <linux/debugfs.h>
67#include <linux/uaccess.h>
1314#include "ra.h"
1415
1516#define FVMAP_SIZE (SZ_8K)
17+ #define FVMAP_EXTRA_SIZE SZ_1K
1618#define STEP_UV (6250)
1719
1820void __iomem * fvmap_base ;
@@ -21,6 +23,8 @@ void __iomem *sram_fvmap_base;
2123static int init_margin_table [MAX_MARGIN_ID ];
2224static int volt_offset_percent = 0 ;
2325static int percent_margin_table [MAX_MARGIN_ID ];
26+ static size_t fvmap_alloc_offset ;
27+ static size_t fvmap_alloc_limit ;
2428
2529static int __init get_mif_volt (char * str )
2630{
@@ -220,6 +224,75 @@ static int __init get_percent_margin_volt(char *str)
220224}
221225early_param ("volt_offset_percent" , get_percent_margin_volt );
222226
227+ static void * fvmap_alloc_extra (size_t size , size_t align )
228+ {
229+ void * ptr ;
230+
231+ fvmap_alloc_offset = ALIGN (fvmap_alloc_offset , align );
232+ if (fvmap_alloc_offset + size > fvmap_alloc_limit )
233+ return NULL ;
234+
235+ ptr = fvmap_base + fvmap_alloc_offset ;
236+ fvmap_alloc_offset += size ;
237+
238+ return ptr ;
239+ }
240+
241+ static bool fvmap_extend_g3d (struct fvmap_header * fvmap_header ,
242+ void __iomem * map_base , void __iomem * sram_base ,
243+ struct vclk * vclk )
244+ {
245+ const int old_lv = fvmap_header -> num_of_lv ;
246+ const int new_lv = 13 ;
247+ struct rate_volt_header * old_rv , * new_rv ;
248+ struct dvfs_table * old_tbl , * new_tbl ;
249+ int members = fvmap_header -> num_of_members ;
250+
251+ if (old_lv >= new_lv )
252+ return false;
253+
254+ old_rv = sram_base + fvmap_header -> o_ratevolt ;
255+ new_rv = fvmap_alloc_extra (sizeof (struct rate_volt ) * new_lv ,
256+ __alignof__(struct rate_volt ));
257+ if (!new_rv ) {
258+ pr_err ("[%s] g3d: no space for extended rate/volt table\n" ,
259+ __func__ );
260+ return false;
261+ }
262+
263+ /* insert OC level at the top and shift existing entries down */
264+ new_rv -> table [0 ].rate = 754000 ;
265+ new_rv -> table [0 ].volt = old_rv -> table [0 ].volt ;
266+ memcpy (& new_rv -> table [1 ], & old_rv -> table [0 ],
267+ sizeof (struct rate_volt ) * old_lv );
268+
269+ old_tbl = sram_base + fvmap_header -> o_tables ;
270+ new_tbl = fvmap_alloc_extra (members * new_lv , 1 );
271+ if (!new_tbl ) {
272+ pr_err ("[%s] g3d: no space for extended dvfs table\n" ,
273+ __func__ );
274+ return false;
275+ }
276+
277+ memcpy (& new_tbl -> val [0 ], & old_tbl -> val [0 ], members );
278+ memcpy (& new_tbl -> val [members ], & old_tbl -> val [0 ], members * old_lv );
279+
280+ fvmap_header -> o_ratevolt = (unsigned short )((void * )new_rv - map_base );
281+ fvmap_header -> o_tables = (unsigned short )((void * )new_tbl - map_base );
282+ fvmap_header -> num_of_lv = new_lv ;
283+ if (fvmap_header -> init_lv < new_lv )
284+ fvmap_header -> init_lv += 1 ;
285+
286+ pr_info ("dvfs_g3d: extended FV table %d -> %d levels (OC 754MHz)\n" ,
287+ old_lv , new_lv );
288+
289+ /* update vclk names to reflect new size */
290+ if (vclk )
291+ vclk -> num_of_lv = new_lv ;
292+
293+ return true;
294+ }
295+
223296int fvmap_set_raw_voltage_table (unsigned int id , int uV )
224297{
225298 struct fvmap_header * fvmap_header ;
@@ -306,47 +379,48 @@ static int get_vclk_id_from_margin_id(int margin_id)
306379 int size = cmucal_get_list_size (ACPM_VCLK_TYPE );
307380 int i ;
308381 struct vclk * vclk ;
382+ bool g3d_extended ;
309383
310- for (i = 0 ; i < size ; i ++ ) {
384+ for (i = 0 ; i < size ; i ++ ) {
311385 vclk = cmucal_get_node (ACPM_VCLK_TYPE | i );
312386
313387 if (vclk -> margin_id == margin_id )
314388 return i ;
315- }
389+ }
316390
317- return - EINVAL ;
391+ return - EINVAL ;
318392}
319393
320394#define attr_percent (margin_id , type ) \
321395static ssize_t show_##type##_percent \
322396(struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
323397{ \
324- return snprintf(buf, PAGE_SIZE, "%d\n", percent_margin_table[margin_id]); \
398+ return snprintf(buf, PAGE_SIZE, "%d\n", percent_margin_table[margin_id]); \
325399} \
326400 \
327401static ssize_t store_##type##_percent \
328402(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) \
329403{ \
330- int input, vclk_id; \
404+ int input, vclk_id; \
331405 \
332- if (!sscanf(buf, "%d", &input)) \
406+ if (!sscanf(buf, "%d", &input)) \
333407 return -EINVAL; \
334408 \
335- if (input < -100 || input > 100) \
409+ if (input < -100 || input > 100) \
336410 return -EINVAL; \
337411 \
338- vclk_id = get_vclk_id_from_margin_id(margin_id); \
339- if (vclk_id == -EINVAL) \
412+ vclk_id = get_vclk_id_from_margin_id(margin_id); \
413+ if (vclk_id == -EINVAL) \
340414 return vclk_id; \
341- percent_margin_table[margin_id] = input; \
342- cal_dfs_set_volt_margin(vclk_id | ACPM_VCLK_TYPE, input); \
415+ percent_margin_table[margin_id] = input; \
416+ cal_dfs_set_volt_margin(vclk_id | ACPM_VCLK_TYPE, input); \
343417 \
344- return count; \
418+ return count; \
345419} \
346420 \
347421static struct kobj_attribute type##_percent = \
348422__ATTR(type##_percent, 0600, \
349- show_##type##_percent, store_##type##_percent)
423+ show_##type##_percent, store_##type##_percent)
350424
351425attr_percent (MARGIN_MIF , mif_margin );
352426attr_percent (MARGIN_INT , int_margin );
@@ -366,48 +440,50 @@ attr_percent(MARGIN_NPU, npu_margin);
366440attr_percent (MARGIN_MFC , mfc_margin );
367441
368442static struct attribute * percent_margin_attrs [] = {
369- & mif_margin_percent .attr ,
370- & int_margin_percent .attr ,
371- & big_margin_percent .attr ,
372- & mid_margin_percent .attr ,
373- & lit_margin_percent .attr ,
374- & g3d_margin_percent .attr ,
375- & intcam_margin_percent .attr ,
376- & cam_margin_percent .attr ,
377- & disp_margin_percent .attr ,
378- & cp_margin_percent .attr ,
379- & fsys0_margin_percent .attr ,
380- & aud_margin_percent .attr ,
381- & iva_margin_percent .attr ,
382- & score_margin_percent .attr ,
383- & npu_margin_percent .attr ,
384- & mfc_margin_percent .attr ,
385- NULL ,
443+ & mif_margin_percent .attr ,
444+ & int_margin_percent .attr ,
445+ & big_margin_percent .attr ,
446+ & mid_margin_percent .attr ,
447+ & lit_margin_percent .attr ,
448+ & g3d_margin_percent .attr ,
449+ & intcam_margin_percent .attr ,
450+ & cam_margin_percent .attr ,
451+ & disp_margin_percent .attr ,
452+ & cp_margin_percent .attr ,
453+ & fsys0_margin_percent .attr ,
454+ & aud_margin_percent .attr ,
455+ & iva_margin_percent .attr ,
456+ & score_margin_percent .attr ,
457+ & npu_margin_percent .attr ,
458+ & mfc_margin_percent .attr ,
459+ NULL ,
386460};
387461
388462static const struct attribute_group percent_margin_group = {
389- .attrs = percent_margin_attrs ,
463+ .attrs = percent_margin_attrs ,
390464};
391465
392466static void fvmap_copy_from_sram (void __iomem * map_base , void __iomem * sram_base )
393467{
394- volatile struct fvmap_header * fvmap_header , * header ;
395- struct rate_volt_header * old , * new ;
396- struct dvfs_table * old_param , * new_param ;
397- struct clocks * clks ;
398- struct pll_header * plls ;
399- struct vclk * vclk ;
400- unsigned int member_addr ;
401- unsigned int blk_idx , param_idx ;
402- int size , margin ;
403- int i , j , k ;
404-
405- fvmap_header = map_base ;
406- header = sram_base ;
407-
408- size = cmucal_get_list_size (ACPM_VCLK_TYPE );
409-
410- for (i = 0 ; i < size ; i ++ ) {
468+ volatile struct fvmap_header * fvmap_header , * header ;
469+ struct rate_volt_header * old , * new ;
470+ struct dvfs_table * old_param , * new_param ;
471+ struct clocks * clks ;
472+ struct pll_header * plls ;
473+ struct vclk * vclk ;
474+ bool g3d_extended ;
475+ unsigned int member_addr ;
476+ unsigned int blk_idx , param_idx ;
477+ unsigned short orig_o_ratevolt , orig_o_tables ;
478+ int size , margin ;
479+ int i , j , k ;
480+
481+ fvmap_header = map_base ;
482+ header = sram_base ;
483+
484+ size = cmucal_get_list_size (ACPM_VCLK_TYPE );
485+
486+ for (i = 0 ; i < size ; i ++ ) {
411487 /* load fvmap info */
412488 fvmap_header [i ].dvfs_type = header [i ].dvfs_type ;
413489 fvmap_header [i ].num_of_lv = header [i ].num_of_lv ;
@@ -426,16 +502,26 @@ static void fvmap_copy_from_sram(void __iomem *map_base, void __iomem *sram_base
426502 fvmap_header [i ].o_members = header [i ].o_members ;
427503 fvmap_header [i ].o_ratevolt = header [i ].o_ratevolt ;
428504 fvmap_header [i ].o_tables = header [i ].o_tables ;
505+ orig_o_ratevolt = fvmap_header [i ].o_ratevolt ;
506+ orig_o_tables = fvmap_header [i ].o_tables ;
429507
430508 vclk = cmucal_get_node (ACPM_VCLK_TYPE | i );
431509 if (vclk == NULL )
432- continue ;
510+ continue ;
511+
512+ g3d_extended = false;
513+
514+ if (!strncmp (vclk -> name , "dvfs_g3d" , 8 ))
515+ g3d_extended = fvmap_extend_g3d (& fvmap_header [i ], map_base , sram_base , vclk );
433516 pr_info ("dvfs_type : %s - id : %x\n" ,
434- vclk -> name , fvmap_header [i ].dvfs_type );
517+ vclk -> name , fvmap_header [i ].dvfs_type );
435518 pr_info (" num_of_lv : %d\n" , fvmap_header [i ].num_of_lv );
436519 pr_info (" num_of_members : %d\n" , fvmap_header [i ].num_of_members );
437520
438- old = sram_base + fvmap_header [i ].o_ratevolt ;
521+ if (g3d_extended )
522+ old = map_base + fvmap_header [i ].o_ratevolt ;
523+ else
524+ old = sram_base + orig_o_ratevolt ;
439525 new = map_base + fvmap_header [i ].o_ratevolt ;
440526
441527 check_percent_margin (old , fvmap_header [i ].num_of_lv );
@@ -478,7 +564,10 @@ static void fvmap_copy_from_sram(void __iomem *map_base, void __iomem *sram_base
478564 volt_offset_percent );
479565 }
480566
481- old_param = sram_base + fvmap_header [i ].o_tables ;
567+ if (g3d_extended )
568+ old_param = map_base + fvmap_header [i ].o_tables ;
569+ else
570+ old_param = sram_base + orig_o_tables ;
482571 new_param = map_base + fvmap_header [i ].o_tables ;
483572 for (j = 0 ; j < fvmap_header [i ].num_of_lv ; j ++ ) {
484573 for (k = 0 ; k < fvmap_header [i ].num_of_members ; k ++ ) {
@@ -500,11 +589,16 @@ int fvmap_init(void __iomem *sram_base)
500589{
501590 void __iomem * map_base ;
502591 struct kobject * kobj ;
592+ size_t alloc_size ;
593+
594+ alloc_size = FVMAP_SIZE + FVMAP_EXTRA_SIZE ;
503595
504- map_base = kzalloc (FVMAP_SIZE , GFP_KERNEL );
596+ map_base = kzalloc (alloc_size , GFP_KERNEL );
505597
506598 fvmap_base = map_base ;
507599 sram_fvmap_base = sram_base ;
600+ fvmap_alloc_offset = FVMAP_SIZE ;
601+ fvmap_alloc_limit = alloc_size ;
508602 pr_info ("%s:fvmap initialize %p\n" , __func__ , sram_base );
509603 fvmap_copy_from_sram (map_base , sram_base );
510604
0 commit comments