+
+typedef struct
+{
+ unsigned short reg, valmask, val;
+}
+reg_setting;
+
+// ~59.998, couldn't figure closer values
+static reg_setting rate_almost60[] =
+{
+ { 0x0914, 0xffff, (212<<8)|(2<<2)|1 }, /* UPLLSETVREG */
+ { 0x0924, 0xff00, (2<<14)|(36<<8) }, /* DISPCSETREG */
+ { 0x281A, 0x00ff, 1 }, /* .HSWID(T2) */
+ { 0x281C, 0x00ff, 0 }, /* .HSSTR(T8) */
+ { 0x281E, 0x00ff, 2 }, /* .HSEND(T7) */
+ { 0x2822, 0x01ff, 12 }, /* .VSEND (T9) */
+ { 0x2826, 0x0ff0, 34<<4 }, /* .DESTR(T3) */
+ { 0, 0, 0 }
+};
+
+// perfect 50Hz?
+static reg_setting rate_50[] =
+{
+ { 0x0914, 0xffff, (39<<8)|(0<<2)|2 }, /* UPLLSETVREG */
+ { 0x0924, 0xff00, (2<<14)|(7<<8) }, /* DISPCSETREG */
+ { 0x281A, 0x00ff, 31 }, /* .HSWID(T2) */
+ { 0x281C, 0x00ff, 16 }, /* .HSSTR(T8) */
+ { 0x281E, 0x00ff, 15 }, /* .HSEND(T7) */
+ { 0x2822, 0x01ff, 15 }, /* .VSEND (T9) */
+ { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */
+ { 0, 0, 0 }
+};
+
+// 16639/2 ~120.20
+static reg_setting rate_120_20[] =
+{
+ { 0x0914, 0xffff, (96<<8)|(0<<2)|2 }, /* UPLLSETVREG */
+ { 0x0924, 0xff00, (2<<14)|(7<<8) }, /* DISPCSETREG */
+ { 0x281A, 0x00ff, 19 }, /* .HSWID(T2) */
+ { 0x281C, 0x00ff, 7 }, /* .HSSTR(T8) */
+ { 0x281E, 0x00ff, 7 }, /* .HSEND(T7) */
+ { 0x2822, 0x01ff, 12 }, /* .VSEND (T9) */
+ { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */
+ { 0, 0, 0 }
+};
+
+// 19997/2 ~100.02
+static reg_setting rate_100_02[] =
+{
+ { 0x0914, 0xffff, (98<<8)|(0<<2)|2 }, /* UPLLSETVREG */
+ { 0x0924, 0xff00, (2<<14)|(8<<8) }, /* DISPCSETREG */
+ { 0x281A, 0x00ff, 26 }, /* .HSWID(T2) */
+ { 0x281C, 0x00ff, 6 }, /* .HSSTR(T8) */
+ { 0x281E, 0x00ff, 6 }, /* .HSEND(T7) */
+ { 0x2822, 0x01ff, 31 }, /* .VSEND (T9) */
+ { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */
+ { 0, 0, 0 }
+};
+
+// 120.00 97/0/2/7|25/ 7/ 7/11/37
+static reg_setting rate_120[] =
+{
+ { 0x0914, 0xffff, (97<<8)|(0<<2)|2 }, /* UPLLSETVREG */
+ { 0x0924, 0xff00, (2<<14)|(7<<8) }, /* DISPCSETREG */
+ { 0x281A, 0x00ff, 25 }, /* .HSWID(T2) */
+ { 0x281C, 0x00ff, 7 }, /* .HSSTR(T8) */
+ { 0x281E, 0x00ff, 7 }, /* .HSEND(T7) */
+ { 0x2822, 0x01ff, 11 }, /* .VSEND (T9) */
+ { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */
+ { 0, 0, 0 }
+};
+
+// 100.00 96/0/2/7|29/25/53/15/37
+static reg_setting rate_100[] =
+{
+ { 0x0914, 0xffff, (96<<8)|(0<<2)|2 }, /* UPLLSETVREG */
+ { 0x0924, 0xff00, (2<<14)|(7<<8) }, /* DISPCSETREG */
+ { 0x281A, 0x00ff, 29 }, /* .HSWID(T2) */
+ { 0x281C, 0x00ff, 25 }, /* .HSSTR(T8) */
+ { 0x281E, 0x00ff, 53 }, /* .HSEND(T7) */
+ { 0x2822, 0x01ff, 15 }, /* .VSEND (T9) */
+ { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */
+ { 0, 0, 0 }
+};
+
+
+
+static reg_setting *possible_rates[] = { rate_almost60, rate_50, rate_120_20, rate_100_02, rate_120, rate_100 };
+
+void set_LCD_custom_rate(lcd_rate_t rate)
+{
+ reg_setting *set;
+
+ if (MEM_REG[0x2800>>1] & 0x100) // tv-out
+ {
+ return;
+ }
+
+ printf("setting custom LCD refresh, mode=%i... ", rate); fflush(stdout);
+ for (set = possible_rates[rate]; set->reg; set++)
+ {
+ unsigned short val = MEM_REG[set->reg >> 1];
+ val &= ~set->valmask;
+ val |= set->val;
+ MEM_REG[set->reg >> 1] = val;
+ }
+ printf("done.\n");
+}
+
+void unset_LCD_custom_rate(void)
+{
+ printf("reset to prev LCD refresh.\n");
+ MEM_REG[0x914>>1]=system_reg.UPLLVSETREG;
+ MEM_REG[0x924>>1]=system_reg.DISPCSETREG;
+ MEM_REG[0x281A>>1]=system_reg.DPC_HS_WIDTH;
+ MEM_REG[0x281C>>1]=system_reg.DPC_HS_STR;
+ MEM_REG[0x281E>>1]=system_reg.DPC_HS_END;
+ MEM_REG[0x2822>>1]=system_reg.DPC_VS_END;
+ MEM_REG[0x2826>>1]=system_reg.DPC_DE;
+}
+