mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 15:27:46 -04:00
gp2x+wiz binary support, wiz code wip
git-svn-id: file:///home/notaz/opt/svn/PicoDrive@705 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
parent
0d9bf4fcda
commit
ee2a3bdfa5
18 changed files with 911 additions and 95 deletions
380
platform/gp2x/pollux_set.c
Normal file
380
platform/gp2x/pollux_set.c
Normal file
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* quick tool to set various timings for Wiz
|
||||
*
|
||||
* Copyright (c) Gražvydas "notaz" Ignotas, 2009
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the organization nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* HTOTAL: X VTOTAL: 341
|
||||
* HSWIDTH: 1 VSWIDTH: 0
|
||||
* HASTART: 37 VASTART: 17
|
||||
* HAEND: 277 VAEND: 337
|
||||
*
|
||||
* 120Hz
|
||||
* pcd 8, 447: + 594us
|
||||
* pcd 9, 397: + 36us
|
||||
* pcd 10, 357: - 523us
|
||||
* pcd 11, 325: +1153us
|
||||
*
|
||||
* 'lcd_timings=397,1,37,277,341,0,17,337;dpc_clkdiv0=9'
|
||||
* 'ram_timings=2,9,4,1,1,1,1'
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "pollux_set.h"
|
||||
|
||||
/* parse stuff */
|
||||
static int parse_lcd_timings(const char *str, void *data)
|
||||
{
|
||||
int *lcd_timings = data;
|
||||
const char *p = str;
|
||||
int ret, c;
|
||||
ret = sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d",
|
||||
&lcd_timings[0], &lcd_timings[1], &lcd_timings[2], &lcd_timings[3],
|
||||
&lcd_timings[4], &lcd_timings[5], &lcd_timings[6], &lcd_timings[7]);
|
||||
if (ret != 8)
|
||||
return -1;
|
||||
/* skip seven commas */
|
||||
for (c = 0; c < 7 && *p != 0; p++)
|
||||
if (*p == ',')
|
||||
c++;
|
||||
if (c != 7)
|
||||
return -1;
|
||||
/* skip last number */
|
||||
while ('0' <= *p && *p <= '9')
|
||||
p++;
|
||||
|
||||
return p - str;
|
||||
}
|
||||
|
||||
static int parse_ram_timings(const char *str, void *data)
|
||||
{
|
||||
int *ram_timings = data;
|
||||
const char *p = str;
|
||||
int ret, c;
|
||||
float cas;
|
||||
|
||||
ret = sscanf(p, "%f,%d,%d,%d,%d,%d,%d",
|
||||
&cas, &ram_timings[1], &ram_timings[2], &ram_timings[3],
|
||||
&ram_timings[4], &ram_timings[5], &ram_timings[6]);
|
||||
if (ret != 7)
|
||||
return -1;
|
||||
if (cas == 2)
|
||||
ram_timings[0] = 1;
|
||||
else if (cas == 2.5)
|
||||
ram_timings[0] = 2;
|
||||
else if (cas == 3)
|
||||
ram_timings[0] = 3;
|
||||
else
|
||||
return -1;
|
||||
for (c = 0; c < 6 && *p != 0; p++)
|
||||
if (*p == ',')
|
||||
c++;
|
||||
if (c != 6)
|
||||
return -1;
|
||||
while ('0' <= *p && *p <= '9')
|
||||
p++;
|
||||
|
||||
return p - str;
|
||||
}
|
||||
|
||||
static int parse_decimal(const char *str, void *data)
|
||||
{
|
||||
char *ep;
|
||||
|
||||
*(int *)data = strtoul(str, &ep, 10);
|
||||
if (ep == str)
|
||||
return -1;
|
||||
|
||||
return ep - str;
|
||||
}
|
||||
|
||||
/* validate and apply stuff */
|
||||
static int apply_lcd_timings(volatile unsigned short *memregs, void *data)
|
||||
{
|
||||
int *lcd_timings = data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (lcd_timings[i] & ~0xffff) {
|
||||
fprintf(stderr, "pollux_set: invalid lcd timing %d: %d\n", i, lcd_timings[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
memregs[(0x307c>>1) + i] = lcd_timings[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
signed char adj; /* how to adjust value passed by user */
|
||||
signed short min; /* range of */
|
||||
signed short max; /* allowed values (inclusive) */
|
||||
}
|
||||
ram_ranges[] = {
|
||||
{ 0, 1, 3 }, /* cas (cl) */
|
||||
{ -2, 0, 15 }, /* trc */
|
||||
{ -2, 0, 15 }, /* tras */
|
||||
{ 0, 0, 15 }, /* twr */
|
||||
{ 0, 0, 15 }, /* tmrd */
|
||||
{ 0, 0, 15 }, /* trp */
|
||||
{ 0, 0, 15 }, /* trcd */
|
||||
};
|
||||
|
||||
static int apply_ram_timings(volatile unsigned short *memregs, void *data)
|
||||
{
|
||||
int *ram_timings = data;
|
||||
int i, val;
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
ram_timings[i] += ram_ranges[i].adj;
|
||||
if (ram_timings[i] < ram_ranges[i].min || ram_timings[i] > ram_ranges[i].max) {
|
||||
fprintf(stderr, "pollux_set: invalid RAM timing %d\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
val = memregs[0x14802>>1] & 0x0f00;
|
||||
val |= (ram_timings[4] << 12) | (ram_timings[5] << 4) | ram_timings[6];
|
||||
memregs[0x14802>>1] = val;
|
||||
|
||||
val = memregs[0x14804>>1] & 0x4000;
|
||||
val |= (ram_timings[0] << 12) | (ram_timings[1] << 8) |
|
||||
(ram_timings[2] << 4) | ram_timings[3];
|
||||
val |= 0x8000;
|
||||
memregs[0x14804>>1] = val;
|
||||
|
||||
for (i = 0; i < 0x100000 && (memregs[0x14804>>1] & 0x8000); i++)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_dpc_clkdiv0(volatile unsigned short *memregs, void *data)
|
||||
{
|
||||
int pcd = *(int *)data;
|
||||
int tmp;
|
||||
|
||||
if ((pcd - 1) & ~0x3f) {
|
||||
fprintf(stderr, "pollux_set: invalid lcd clkdiv0: %d\n", pcd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pcd = (pcd - 1) & 0x3f;
|
||||
tmp = memregs[0x31c4>>1];
|
||||
memregs[0x31c4>>1] = (tmp & ~0x3f0) | (pcd << 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_cpuclk(volatile unsigned short *memregs, void *data)
|
||||
{
|
||||
volatile unsigned int *memregl = (volatile void *)memregs;
|
||||
int mhz = *(int *)data;
|
||||
int mdiv, pdiv, sdiv = 0;
|
||||
int i, v;
|
||||
|
||||
// m = MDIV, p = PDIV, s = SDIV
|
||||
#define SYS_CLK_FREQ 27
|
||||
pdiv = 9;
|
||||
mdiv = (mhz * pdiv) / SYS_CLK_FREQ;
|
||||
if (mdiv & ~0x3ff)
|
||||
return -1;
|
||||
v = (pdiv<<18) | (mdiv<<8) | sdiv;
|
||||
|
||||
memregl[0xf004>>2] = v;
|
||||
memregl[0xf07c>>2] |= 0x8000;
|
||||
for (i = 0; (memregl[0xf07c>>2] & 0x8000) && i < 0x100000; i++)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lcd_timings[8];
|
||||
static int ram_timings[7];
|
||||
static int dpc_clkdiv0;
|
||||
static int cpuclk;
|
||||
|
||||
static const char lcd_t_help[] = "htotal,hswidth,hastart,haend,vtotal,vswidth,vastart,vaend";
|
||||
static const char ram_t_help[] = "CAS,tRC,tRAS,tWR,tMRD,tRP,tRCD";
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
const char *help;
|
||||
int (*parse)(const char *str, void *data);
|
||||
int (*apply)(volatile unsigned short *memregs, void *data);
|
||||
void *data;
|
||||
}
|
||||
all_params[] = {
|
||||
{ "lcd_timings", lcd_t_help, parse_lcd_timings, apply_lcd_timings, lcd_timings },
|
||||
{ "ram_timings", ram_t_help, parse_ram_timings, apply_ram_timings, ram_timings },
|
||||
{ "dpc_clkdiv0", "divider", parse_decimal, apply_dpc_clkdiv0, &dpc_clkdiv0 },
|
||||
{ "clkdiv0", "divider", parse_decimal, apply_dpc_clkdiv0, &dpc_clkdiv0 }, /* alias */
|
||||
{ "cpuclk", "MHZ", parse_decimal, apply_cpuclk, &cpuclk },
|
||||
};
|
||||
#define ALL_PARAM_COUNT (sizeof(all_params) / sizeof(all_params[0]))
|
||||
|
||||
/*
|
||||
* set timings based on preformated string
|
||||
* returns 0 on success.
|
||||
*/
|
||||
int pollux_set(volatile unsigned short *memregs, const char *str)
|
||||
{
|
||||
int parsed_params[ALL_PARAM_COUNT];
|
||||
int applied_params[ALL_PARAM_COUNT];
|
||||
int applied_something = 0;
|
||||
const char *p, *po;
|
||||
int i, ret;
|
||||
|
||||
if (str == NULL)
|
||||
return -1;
|
||||
|
||||
memset(parsed_params, 0, sizeof(parsed_params));
|
||||
memset(applied_params, 0, sizeof(applied_params));
|
||||
|
||||
p = str;
|
||||
while (1)
|
||||
{
|
||||
again:
|
||||
while (*p == ';' || *p == ' ')
|
||||
p++;
|
||||
if (*p == 0)
|
||||
break;
|
||||
|
||||
for (i = 0; i < ALL_PARAM_COUNT; i++)
|
||||
{
|
||||
int param_len = strlen(all_params[i].name);
|
||||
if (strncmp(p, all_params[i].name, param_len) == 0 && p[param_len] == '=')
|
||||
{
|
||||
p += param_len + 1;
|
||||
ret = all_params[i].parse(p, all_params[i].data);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "pollux_set parser: error at %-10s\n", p);
|
||||
fprintf(stderr, " valid format is: <%s>\n", all_params[i].help);
|
||||
return -1;
|
||||
}
|
||||
parsed_params[i] = 1;
|
||||
p += ret;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unknown param. Attempt to be forward compatible and ignore it. */
|
||||
for (po = p; *p != 0 && *p != ';'; p++)
|
||||
;
|
||||
|
||||
fprintf(stderr, "unhandled param: ");
|
||||
fwrite(po, 1, p - po, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* validate and apply */
|
||||
for (i = 0; i < ALL_PARAM_COUNT; i++)
|
||||
{
|
||||
if (!parsed_params[i])
|
||||
continue;
|
||||
|
||||
ret = all_params[i].apply(memregs, all_params[i].data);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "pollux_set: failed to apply %s (bad value?)\n",
|
||||
all_params[i].name);
|
||||
continue;
|
||||
}
|
||||
|
||||
applied_something = 1;
|
||||
applied_params[i] = 1;
|
||||
}
|
||||
|
||||
if (applied_something)
|
||||
{
|
||||
int c;
|
||||
printf("applied: ");
|
||||
for (i = c = 0; i < ALL_PARAM_COUNT; i++)
|
||||
{
|
||||
if (!applied_params[i])
|
||||
continue;
|
||||
if (c != 0)
|
||||
printf(", ");
|
||||
printf("%s", all_params[i].name);
|
||||
c++;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef BINARY
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void usage(const char *binary)
|
||||
{
|
||||
int i;
|
||||
printf("usage:\n%s <set_str[;set_str[;...]]>\n"
|
||||
"set_str:\n", binary);
|
||||
for (i = 0; i < ALL_PARAM_COUNT; i++)
|
||||
printf(" %s=<%s>\n", all_params[i].name, all_params[i].help);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
volatile unsigned short *memregs;
|
||||
int ret, memdev;
|
||||
|
||||
if (argc != 2) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memdev = open("/dev/mem", O_RDWR);
|
||||
if (memdev == -1)
|
||||
{
|
||||
perror("open(/dev/mem) failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memregs = mmap(0, 0x20000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
|
||||
if (memregs == MAP_FAILED)
|
||||
{
|
||||
perror("mmap(memregs) failed");
|
||||
close(memdev);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = pollux_set(memregs, argv[1]);
|
||||
|
||||
munmap((void *)memregs, 0x20000);
|
||||
close(memdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue