From b75dcabd6c6c71d7cea64f78b06d18d9cda0ddd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> Date: Fri, 29 Jan 2010 11:40:38 +0100 Subject: [PATCH 001/842] modpost: members of *driver structs should not point to __init functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Either the functions referred to in a driver struct should live in .devinit or the driver should be registered using platform_driver_probe (or equivalent for different driver types) with ->probe being NULL. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> --- scripts/mod/modpost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 20923613467c..713b62eed875 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -961,7 +961,7 @@ static int section_mismatch(const char *fromsec, const char *tosec) * Pattern 2: * Many drivers utilise a *driver container with references to * add, remove, probe functions etc. - * These functions may often be marked __init and we do not want to + * These functions may often be marked __devinit and we do not want to * warn here. * the pattern is identified by: * tosec = init or exit section -- GitLab From 4a31a229fb6cbbeabf5ca9a0dcb55d53ca052048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> Date: Fri, 29 Jan 2010 12:04:26 +0100 Subject: [PATCH 002/842] modpost: define ALL_XXX{IN,EX}IT_SECTIONS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> --- scripts/mod/modpost.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 713b62eed875..dbab53a2e225 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -781,10 +781,13 @@ static void check_section(const char *modname, struct elf_info *elf, #define ALL_EXIT_TEXT_SECTIONS \ ".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$" -#define ALL_INIT_SECTIONS INIT_SECTIONS, DEV_INIT_SECTIONS, \ - CPU_INIT_SECTIONS, MEM_INIT_SECTIONS -#define ALL_EXIT_SECTIONS EXIT_SECTIONS, DEV_EXIT_SECTIONS, \ - CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS +#define ALL_XXXINIT_SECTIONS DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, \ + MEM_INIT_SECTIONS +#define ALL_XXXEXIT_SECTIONS DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, \ + MEM_EXIT_SECTIONS + +#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS +#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS #define DATA_SECTIONS ".data$", ".data.rel$" #define TEXT_SECTIONS ".text$" @@ -876,7 +879,7 @@ const struct sectioncheck sectioncheck[] = { }, /* Do not reference init code/data from devinit/cpuinit/meminit code/data */ { - .fromsec = { DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, MEM_INIT_SECTIONS, NULL }, + .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, .tosec = { INIT_SECTIONS, NULL }, .mismatch = XXXINIT_TO_INIT, }, @@ -894,7 +897,7 @@ const struct sectioncheck sectioncheck[] = { }, /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ { - .fromsec = { DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL }, + .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, .tosec = { EXIT_SECTIONS, NULL }, .mismatch = XXXEXIT_TO_EXIT, }, -- GitLab From bbd3f4fb84f8c4a04f22c9c6dc119b0c4856c7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> Date: Sat, 30 Jan 2010 16:35:47 +0100 Subject: [PATCH 003/842] modpost: give most mismatch constants a better name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> --- scripts/mod/modpost.c | 56 +++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index dbab53a2e225..598d54a0fefb 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -836,14 +836,14 @@ static const char *linker_symbols[] = enum mismatch { NO_MISMATCH, - TEXT_TO_INIT, - DATA_TO_INIT, - TEXT_TO_EXIT, - DATA_TO_EXIT, - XXXINIT_TO_INIT, - XXXEXIT_TO_EXIT, - INIT_TO_EXIT, - EXIT_TO_INIT, + TEXT_TO_ANY_INIT, + DATA_TO_ANY_INIT, + TEXT_TO_ANY_EXIT, + DATA_TO_ANY_EXIT, + XXXINIT_TO_SOME_INIT, + XXXEXIT_TO_SOME_EXIT, + ANY_INIT_TO_ANY_EXIT, + ANY_EXIT_TO_ANY_INIT, EXPORT_TO_INIT_EXIT, }; @@ -860,70 +860,70 @@ const struct sectioncheck sectioncheck[] = { { .fromsec = { TEXT_SECTIONS, NULL }, .tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = TEXT_TO_INIT, + .mismatch = TEXT_TO_ANY_INIT, }, { .fromsec = { DATA_SECTIONS, NULL }, .tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = DATA_TO_INIT, + .mismatch = DATA_TO_ANY_INIT, }, { .fromsec = { TEXT_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = TEXT_TO_EXIT, + .mismatch = TEXT_TO_ANY_EXIT, }, { .fromsec = { DATA_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = DATA_TO_EXIT, + .mismatch = DATA_TO_ANY_EXIT, }, /* Do not reference init code/data from devinit/cpuinit/meminit code/data */ { .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, .tosec = { INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_INIT, + .mismatch = XXXINIT_TO_SOME_INIT, }, /* Do not reference cpuinit code/data from meminit code/data */ { .fromsec = { MEM_INIT_SECTIONS, NULL }, .tosec = { CPU_INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_INIT, + .mismatch = XXXINIT_TO_SOME_INIT, }, /* Do not reference meminit code/data from cpuinit code/data */ { .fromsec = { CPU_INIT_SECTIONS, NULL }, .tosec = { MEM_INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_INIT, + .mismatch = XXXINIT_TO_SOME_INIT, }, /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ { .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, .tosec = { EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_EXIT, + .mismatch = XXXEXIT_TO_SOME_EXIT, }, /* Do not reference cpuexit code/data from memexit code/data */ { .fromsec = { MEM_EXIT_SECTIONS, NULL }, .tosec = { CPU_EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_EXIT, + .mismatch = XXXEXIT_TO_SOME_EXIT, }, /* Do not reference memexit code/data from cpuexit code/data */ { .fromsec = { CPU_EXIT_SECTIONS, NULL }, .tosec = { MEM_EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_EXIT, + .mismatch = XXXEXIT_TO_SOME_EXIT, }, /* Do not use exit code/data from init code */ { .fromsec = { ALL_INIT_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = INIT_TO_EXIT, + .mismatch = ANY_INIT_TO_ANY_EXIT, }, /* Do not use init code/data from exit code */ { .fromsec = { ALL_EXIT_SECTIONS, NULL }, .tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = EXIT_TO_INIT, + .mismatch = ANY_EXIT_TO_ANY_INIT, }, /* Do not export init/exit functions or data */ { @@ -1190,7 +1190,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, tosym, to_p); switch (mismatch) { - case TEXT_TO_INIT: + case TEXT_TO_ANY_INIT: fprintf(stderr, "The function %s%s() references\n" "the %s %s%s%s.\n" @@ -1200,7 +1200,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, to, sec2annotation(tosec), tosym, to_p, fromsym, sec2annotation(tosec), tosym); break; - case DATA_TO_INIT: { + case DATA_TO_ANY_INIT: { const char **s = symbol_white_list; fprintf(stderr, "The variable %s references\n" @@ -1214,14 +1214,14 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, fprintf(stderr, "\n"); break; } - case TEXT_TO_EXIT: + case TEXT_TO_ANY_EXIT: fprintf(stderr, "The function %s() references a %s in an exit section.\n" "Often the %s %s%s has valid usage outside the exit section\n" "and the fix is to remove the %sannotation of %s.\n", fromsym, to, to, tosym, to_p, sec2annotation(tosec), tosym); break; - case DATA_TO_EXIT: { + case DATA_TO_ANY_EXIT: { const char **s = symbol_white_list; fprintf(stderr, "The variable %s references\n" @@ -1235,8 +1235,8 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, fprintf(stderr, "\n"); break; } - case XXXINIT_TO_INIT: - case XXXEXIT_TO_EXIT: + case XXXINIT_TO_SOME_INIT: + case XXXEXIT_TO_SOME_EXIT: fprintf(stderr, "The %s %s%s%s references\n" "a %s %s%s%s.\n" @@ -1246,7 +1246,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, to, sec2annotation(tosec), tosym, to_p, tosym, fromsym, tosym); break; - case INIT_TO_EXIT: + case ANY_INIT_TO_ANY_EXIT: fprintf(stderr, "The %s %s%s%s references\n" "a %s %s%s%s.\n" @@ -1259,7 +1259,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, to, sec2annotation(tosec), tosym, to_p, sec2annotation(tosec), tosym, to_p); break; - case EXIT_TO_INIT: + case ANY_EXIT_TO_ANY_INIT: fprintf(stderr, "The %s %s%s%s references\n" "a %s %s%s%s.\n" -- GitLab From 0d2a636ee6c3b8c292fbaae05976fe1537b70958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> Date: Sat, 30 Jan 2010 16:56:20 +0100 Subject: [PATCH 004/842] modpost: pass around const struct sectioncheck * instead of enum mismatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prepares having a per-check whitelist of symbol names. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> --- scripts/mod/modpost.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 598d54a0fefb..3f0380b8d8f7 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -933,7 +933,8 @@ const struct sectioncheck sectioncheck[] = { } }; -static int section_mismatch(const char *fromsec, const char *tosec) +static const struct sectioncheck *section_mismatch( + const char *fromsec, const char *tosec) { int i; int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); @@ -942,10 +943,10 @@ static int section_mismatch(const char *fromsec, const char *tosec) for (i = 0; i < elems; i++) { if (match(fromsec, check->fromsec) && match(tosec, check->tosec)) - return check->mismatch; + return check; check++; } - return NO_MISMATCH; + return NULL; } /** @@ -1158,7 +1159,8 @@ static int is_function(Elf_Sym *sym) * Try to find symbols near it so user can find it. * Check whitelist before warning - it may be a false positive. */ -static void report_sec_mismatch(const char *modname, enum mismatch mismatch, +static void report_sec_mismatch(const char *modname, + const struct sectioncheck *mismatch, const char *fromsec, unsigned long long fromaddr, const char *fromsym, @@ -1189,7 +1191,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, tosym, to_p); - switch (mismatch) { + switch (mismatch->mismatch) { case TEXT_TO_ANY_INIT: fprintf(stderr, "The function %s%s() references\n" @@ -1289,11 +1291,11 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf, Elf_Rela *r, Elf_Sym *sym, const char *fromsec) { const char *tosec; - enum mismatch mismatch; + const struct sectioncheck *mismatch; tosec = sec_name(elf, sym->st_shndx); mismatch = section_mismatch(fromsec, tosec); - if (mismatch != NO_MISMATCH) { + if (mismatch) { Elf_Sym *to; Elf_Sym *from; const char *tosym; -- GitLab From fc2f7efadb755b020ad8fdf195515dacaf185e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> Date: Sat, 30 Jan 2010 16:57:48 +0100 Subject: [PATCH 005/842] modpost: remove now unused NO_MISMATCH constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> --- scripts/mod/modpost.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 3f0380b8d8f7..a94bd10ad2de 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -835,7 +835,6 @@ static const char *linker_symbols[] = { "__init_begin", "_sinittext", "_einittext", NULL }; enum mismatch { - NO_MISMATCH, TEXT_TO_ANY_INIT, DATA_TO_ANY_INIT, TEXT_TO_ANY_EXIT, @@ -1280,8 +1279,6 @@ static void report_sec_mismatch(const char *modname, "Fix this by removing the %sannotation of %s " "or drop the export.\n", tosym, sec2annotation(tosec), sec2annotation(tosec), tosym); - case NO_MISMATCH: - /* To get warnings on missing members */ break; } fprintf(stderr, "\n"); -- GitLab From af92a82d0fec4dfd344b2ffd7a63e30f05c53938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> Date: Sat, 30 Jan 2010 20:52:50 +0100 Subject: [PATCH 006/842] modpost: make symbol white list a per mismatch type variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> --- scripts/mod/modpost.c | 49 +++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index a94bd10ad2de..5dbe4db2bd42 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -817,18 +817,15 @@ static const char *data_sections[] = { DATA_SECTIONS, NULL }; /* symbols in .data that may refer to init/exit sections */ -static const char *symbol_white_list[] = -{ - "*driver", - "*_template", /* scsi uses *_template a lot */ - "*_timer", /* arm uses ops structures named _timer a lot */ - "*_sht", /* scsi also used *_sht to some extent */ - "*_ops", - "*_probe", - "*_probe_one", - "*_console", - NULL -}; +#define DEFAULT_SYMBOL_WHITE_LIST \ + "*driver", \ + "*_template", /* scsi uses *_template a lot */ \ + "*_timer", /* arm uses ops structures named _timer a lot */ \ + "*_sht", /* scsi also used *_sht to some extent */ \ + "*_ops", \ + "*_probe", \ + "*_probe_one", \ + "*_console" static const char *head_sections[] = { ".head.text*", NULL }; static const char *linker_symbols[] = @@ -850,6 +847,7 @@ struct sectioncheck { const char *fromsec[20]; const char *tosec[20]; enum mismatch mismatch; + const char *symbol_white_list[20]; }; const struct sectioncheck sectioncheck[] = { @@ -860,75 +858,88 @@ const struct sectioncheck sectioncheck[] = { .fromsec = { TEXT_SECTIONS, NULL }, .tosec = { ALL_INIT_SECTIONS, NULL }, .mismatch = TEXT_TO_ANY_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, .tosec = { ALL_INIT_SECTIONS, NULL }, .mismatch = DATA_TO_ANY_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { TEXT_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, .mismatch = TEXT_TO_ANY_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, { .fromsec = { DATA_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, .mismatch = DATA_TO_ANY_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference init code/data from devinit/cpuinit/meminit code/data */ { .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, .tosec = { INIT_SECTIONS, NULL }, .mismatch = XXXINIT_TO_SOME_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference cpuinit code/data from meminit code/data */ { .fromsec = { MEM_INIT_SECTIONS, NULL }, .tosec = { CPU_INIT_SECTIONS, NULL }, .mismatch = XXXINIT_TO_SOME_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference meminit code/data from cpuinit code/data */ { .fromsec = { CPU_INIT_SECTIONS, NULL }, .tosec = { MEM_INIT_SECTIONS, NULL }, .mismatch = XXXINIT_TO_SOME_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ { .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, .tosec = { EXIT_SECTIONS, NULL }, .mismatch = XXXEXIT_TO_SOME_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference cpuexit code/data from memexit code/data */ { .fromsec = { MEM_EXIT_SECTIONS, NULL }, .tosec = { CPU_EXIT_SECTIONS, NULL }, .mismatch = XXXEXIT_TO_SOME_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not reference memexit code/data from cpuexit code/data */ { .fromsec = { CPU_EXIT_SECTIONS, NULL }, .tosec = { MEM_EXIT_SECTIONS, NULL }, .mismatch = XXXEXIT_TO_SOME_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not use exit code/data from init code */ { .fromsec = { ALL_INIT_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, .mismatch = ANY_INIT_TO_ANY_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not use init code/data from exit code */ { .fromsec = { ALL_EXIT_SECTIONS, NULL }, .tosec = { ALL_INIT_SECTIONS, NULL }, .mismatch = ANY_EXIT_TO_ANY_INIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, /* Do not export init/exit functions or data */ { .fromsec = { "__ksymtab*", NULL }, .tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, - .mismatch = EXPORT_TO_INIT_EXIT + .mismatch = EXPORT_TO_INIT_EXIT, + .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, } }; @@ -985,7 +996,8 @@ static const struct sectioncheck *section_mismatch( * refsymname = __init_begin, _sinittext, _einittext * **/ -static int secref_whitelist(const char *fromsec, const char *fromsym, +static int secref_whitelist(const struct sectioncheck *mismatch, + const char *fromsec, const char *fromsym, const char *tosec, const char *tosym) { /* Check for pattern 1 */ @@ -997,7 +1009,7 @@ static int secref_whitelist(const char *fromsec, const char *fromsym, /* Check for pattern 2 */ if (match(tosec, init_exit_sections) && match(fromsec, data_sections) && - match(fromsym, symbol_white_list)) + match(fromsym, mismatch->symbol_white_list)) return 0; /* Check for pattern 3 */ @@ -1202,7 +1214,7 @@ static void report_sec_mismatch(const char *modname, fromsym, sec2annotation(tosec), tosym); break; case DATA_TO_ANY_INIT: { - const char **s = symbol_white_list; + const char *const *s = mismatch->symbol_white_list; fprintf(stderr, "The variable %s references\n" "the %s %s%s%s\n" @@ -1223,7 +1235,7 @@ static void report_sec_mismatch(const char *modname, fromsym, to, to, tosym, to_p, sec2annotation(tosec), tosym); break; case DATA_TO_ANY_EXIT: { - const char **s = symbol_white_list; + const char *const *s = mismatch->symbol_white_list; fprintf(stderr, "The variable %s references\n" "the %s %s%s%s\n" @@ -1304,7 +1316,8 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf, tosym = sym_name(elf, to); /* check whitelist - we may ignore it */ - if (secref_whitelist(fromsec, fromsym, tosec, tosym)) { + if (secref_whitelist(mismatch, + fromsec, fromsym, tosec, tosym)) { report_sec_mismatch(modname, mismatch, fromsec, r->r_offset, fromsym, is_function(from), tosec, tosym, -- GitLab From 0db252452378aa7a9e001a13226e1cd1dc61453d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> Date: Sat, 30 Jan 2010 21:14:23 +0100 Subject: [PATCH 007/842] modpost: don't allow *driver to reference .init.* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> --- scripts/mod/modpost.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 5dbe4db2bd42..3318692e4e76 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -862,10 +862,19 @@ const struct sectioncheck sectioncheck[] = { }, { .fromsec = { DATA_SECTIONS, NULL }, - .tosec = { ALL_INIT_SECTIONS, NULL }, + .tosec = { ALL_XXXINIT_SECTIONS, NULL }, .mismatch = DATA_TO_ANY_INIT, .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, +{ + .fromsec = { DATA_SECTIONS, NULL }, + .tosec = { INIT_SECTIONS, NULL }, + .mismatch = DATA_TO_ANY_INIT, + .symbol_white_list = { + "*_template", "*_timer", "*_sht", "*_ops", + "*_probe", "*_probe_one", "*_console", NULL + }, +}, { .fromsec = { TEXT_SECTIONS, NULL }, .tosec = { ALL_EXIT_SECTIONS, NULL }, -- GitLab From 4b024242e8a4e9679fa327ea03958b89f89096c9 Mon Sep 17 00:00:00 2001 From: Jiafu He <jay@goldhive.com> Date: Thu, 17 Dec 2009 18:22:13 -0700 Subject: [PATCH 008/842] kbuild: Fix linking error built-in.o no such file or directory This patch fixes the link error "built-in.o: no such file or directory". The problem happens if "dirx/Makefile" contains only "obj-m += diry/ dirz/" and the empty "dirx/built-in.o" is missing. Adding $(subdir-m) into check for builtin-target fixes this error. Signed-off-by: Jiafu He <jay@goldhive.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/Makefile.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 0b94d2fa3a88..e4deb73e9a84 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -82,7 +82,7 @@ ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),) lib-target := $(obj)/lib.a endif -ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),) +ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),) builtin-target := $(obj)/built-in.o endif -- GitLab From 84336466011c589b6af554f2f2f1fcfa1a5c1437 Mon Sep 17 00:00:00 2001 From: Roland McGrath <roland@redhat.com> Date: Mon, 21 Dec 2009 16:24:06 -0800 Subject: [PATCH 009/842] kconfig CROSS_COMPILE option This adds CROSS_COMPILE as a kconfig string so you can store it in .config. Then you can use plain "make" in the configured kernel build directory to do the right cross compilation without setting the command-line or environment variable every time. With this, you can set up different build directories for different kernel configurations, whether native or cross-builds, and then use the simple: make -C /build/dir M=module-source-dir idiom to build modules for any given target kernel, indicating which one by nothing but the build directory chosen. I tried a version that defaults the string with env="CROSS_COMPILE" so that in a "make oldconfig" with CROSS_COMPILE in the environment you can just hit return to store the way you're building it. But the kconfig prompt for strings doesn't give you any way to say you want an empty string instead of the default, so I punted that. Signed-off-by: Roland McGrath <roland@redhat.com> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: Anibal Monsalve Salazar <anibal@debian.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Michal Marek <mmarek@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Makefile | 3 +++ init/Kconfig | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/Makefile b/Makefile index 394aec712c7d..f9dc25cd9b2e 100644 --- a/Makefile +++ b/Makefile @@ -183,11 +183,14 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ # CROSS_COMPILE can be set on the command line # make CROSS_COMPILE=ia64-linux- # Alternatively CROSS_COMPILE can be set in the environment. +# A third alternative is to store a setting in .config so that plain +# "make" in the configured kernel build directory always uses that. # Default value for CROSS_COMPILE is not to prefix executables # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile export KBUILD_BUILDHOST := $(SUBARCH) ARCH ?= $(SUBARCH) CROSS_COMPILE ?= +CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) # Architecture as present in compile.h UTS_MACHINE := $(ARCH) diff --git a/init/Kconfig b/init/Kconfig index d95ca7cd5d45..313506d8be6e 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -76,6 +76,14 @@ config INIT_ENV_ARG_LIMIT variables passed to init from the kernel command line. +config CROSS_COMPILE + string "Cross-compiler tool prefix" + help + Same as running 'make CROSS_COMPILE=prefix-' but stored for + default make runs in this kernel build directory. You don't + need to set this unless you want the configured kernel build + directory to select the cross-compiler automatically. + config LOCALVERSION string "Local version - append to kernel release" help -- GitLab From 5358db0b0e16470337c6ec08177deb3f68ed7673 Mon Sep 17 00:00:00 2001 From: Rabin Vincent <rabin@rab.in> Date: Tue, 5 Jan 2010 20:27:58 +0530 Subject: [PATCH 010/842] scripts: add ARM support to decodecode This patch adds support for decoding ARM oopses to scripts/decodecode. The following things are handled: - ARCH and CROSS_COMPILE environment variables are respected. - The Code: in x86 oopses is in bytes, while it is in either words (4 bytes) or halfwords for ARM. - Some versions of ARM objdump refuse to disassemble instructions generated by literal constants (".word 0x..."). The workaround is to strip the object file first. - The faulting instruction is marked (liked so) in ARM, but <like so> in x86. - ARM mnemonics may include characters such as [] which need to be escaped before being passed to sed for the "<- trapping instruction" substitution. Signed-off-by: Rabin Vincent <rabin@rab.in> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/decodecode | 48 +++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/scripts/decodecode b/scripts/decodecode index 4b00647814bc..8b30cc36744f 100755 --- a/scripts/decodecode +++ b/scripts/decodecode @@ -7,7 +7,7 @@ # AFLAGS=--32 decodecode < 386.oops cleanup() { - rm -f $T $T.s $T.o $T.oo $T.aa $T.aaa + rm -f $T $T.s $T.o $T.oo $T.aa $T.dis exit 1 } @@ -39,6 +39,29 @@ fi echo $code code=`echo $code | sed -e 's/.*Code: //'` +width=`expr index "$code" ' '` +width=$[($width-1)/2] +case $width in +1) type=byte ;; +2) type=2byte ;; +4) type=4byte ;; +esac + +disas() { + ${CROSS_COMPILE}as $AFLAGS -o $1.o $1.s &> /dev/null + + if [ "$ARCH" == "arm" ]; then + if [ $width == 2 ]; then + OBJDUMPFLAGS="-M force-thumb" + fi + + ${CROSS_COMPILE}strip $1.o + fi + + ${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $1.o | \ + grep -v "/tmp\|Disassembly\|\.text\|^$" &> $1.dis +} + marker=`expr index "$code" "\<"` if [ $marker -eq 0 ]; then marker=`expr index "$code" "\("` @@ -49,26 +72,25 @@ if [ $marker -ne 0 ]; then echo All code >> $T.oo echo ======== >> $T.oo beforemark=`echo "$code"` - echo -n " .byte 0x" > $T.s - echo $beforemark | sed -e 's/ /,0x/g' | sed -e 's/<//g' | sed -e 's/>//g' >> $T.s - as $AFLAGS -o $T.o $T.s &> /dev/null - objdump -S $T.o | grep -v "/tmp" | grep -v "Disassembly" | grep -v "\.text" | grep -v "^$" &> $T.ooo - cat $T.ooo >> $T.oo - rm -f $T.o $T.s $T.ooo + echo -n " .$type 0x" > $T.s + echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s + disas $T + cat $T.dis >> $T.oo + rm -f $T.o $T.s $T.dis # and fix code at-and-after marker code=`echo "$code" | cut -c$((${marker} + 1))-` fi echo Code starting with the faulting instruction > $T.aa echo =========================================== >> $T.aa -code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g'` -echo -n " .byte 0x" > $T.s +code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'` +echo -n " .$type 0x" > $T.s echo $code >> $T.s -as $AFLAGS -o $T.o $T.s &> /dev/null -objdump -S $T.o | grep -v "Disassembly" | grep -v "/tmp" | grep -v "\.text" | grep -v "^$" &> $T.aaa -cat $T.aaa >> $T.aa +disas $T +cat $T.dis >> $T.aa -faultline=`cat $T.aaa | head -1 | cut -d":" -f2` +faultline=`cat $T.dis | head -1 | cut -d":" -f2` +faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'` cat $T.oo | sed -e "s/\($faultline\)/\*\1 <-- trapping instruction/g" echo -- GitLab From da60fbbcb637b37b1d77a41886ae4e275422ca96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vadim=20Bendebury=20=28=D0=B2=D0=B1=29?= <vbendeb@google.com> Date: Sun, 20 Dec 2009 00:29:49 -0800 Subject: [PATCH 011/842] menuconfig: wrap long help lines Help text for certain config options is very extensive (the text includes the names of all other options the option in question depends on). Long lines are not wrapped, making it impossible to see the list without scrolling horizontally. This patch adds some logic which wraps help screen lines at word boundaries to prevent truncating. Tested by running ARCH=powerpc make menuconfig O=/tmp/build which shows that the long lines are now wrapped, and ARCH=powerpc make xconfig O=/tmp/build to demonstrate that it still compiles and operates as expected. Signed-off-by: Vadim Bendebury <vbendeb@google.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/expr.c | 27 +++++++++++++++++++++++++-- scripts/kconfig/lkc.h | 5 +++++ scripts/kconfig/mconf.c | 1 + scripts/kconfig/util.c | 2 ++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index edd3f39a080a..d83f2322893a 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -1097,9 +1097,32 @@ void expr_fprint(struct expr *e, FILE *out) static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) { - str_append((struct gstr*)data, str); + struct gstr *gs = (struct gstr*)data; + const char *sym_str = NULL; + + if (sym) + sym_str = sym_get_string_value(sym); + + if (gs->max_width) { + unsigned extra_length = strlen(str); + const char *last_cr = strrchr(gs->s, '\n'); + unsigned last_line_length; + + if (sym_str) + extra_length += 4 + strlen(sym_str); + + if (!last_cr) + last_cr = gs->s; + + last_line_length = strlen(gs->s) - (last_cr - gs->s); + + if ((last_line_length + extra_length) > gs->max_width) + str_append(gs, "\\\n"); + } + + str_append(gs, str); if (sym) - str_printf((struct gstr*)data, " [=%s]", sym_get_string_value(sym)); + str_printf(gs, " [=%s]", sym_str); } void expr_gstr_print(struct expr *e, struct gstr *gs) diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index f379b0bf8c9e..e59dd0c5787a 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -106,6 +106,11 @@ int file_write_dep(const char *name); struct gstr { size_t len; char *s; + /* + * when max_width is not zero long lines in string s (if any) get + * wrapped not to exceed the max_width value + */ + int max_width; }; struct gstr str_new(void); struct gstr str_assign(const char *s); diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 8413cf38ed27..ac1e9dacde97 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -638,6 +638,7 @@ static void show_help(struct menu *menu) { struct gstr help = str_new(); + help.max_width = getmaxx(stdscr) - 10; menu_get_ext_help(menu, &help); show_helptext(_(menu_get_prompt(menu)), str_get(&help)); diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index b6b2a46af14c..81c100d953ef 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -78,6 +78,7 @@ struct gstr str_new(void) struct gstr gs; gs.s = malloc(sizeof(char) * 64); gs.len = 64; + gs.max_width = 0; strcpy(gs.s, "\0"); return gs; } @@ -88,6 +89,7 @@ struct gstr str_assign(const char *s) struct gstr gs; gs.s = strdup(s); gs.len = strlen(s) + 1; + gs.max_width = 0; return gs; } -- GitLab From c64152bfd0106807c8d3ddbe6d0928e14a64f7bb Mon Sep 17 00:00:00 2001 From: Alexander Beregalov <a.beregalov@gmail.com> Date: Thu, 7 Jan 2010 05:22:41 +0300 Subject: [PATCH 012/842] genksyms: close ref_file after use It is the last place when the file is read, so close it. Signed-off-by: Alexander Beregalov <a.beregalov@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/genksyms/genksyms.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index af6b8363a2d5..f99115ebe925 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -758,8 +758,10 @@ int main(int argc, char **argv) /* setlinebuf(debugfile); */ } - if (flag_reference) + if (flag_reference) { read_reference(ref_file); + fclose(ref_file); + } yyparse(); -- GitLab From 692d97c380c6dce2c35a04c5dcbce4e831a42fa0 Mon Sep 17 00:00:00 2001 From: "nir.tzachar@gmail.com" <nir.tzachar@gmail.com> Date: Wed, 25 Nov 2009 12:28:43 +0200 Subject: [PATCH 013/842] kconfig: new configuration interface (nconfig) This patch was inspired by the kernel projects page, where an ncurses replacement for menuconfig was mentioned (by Sam Ravnborg). Building on menuconfig, this patch implements a more modern look interface using ncurses and ncurses' satellite libraries (menu, panel, form). The implementation does not depend on lxdialog, which is currently distributed with the kernel. Signed-off-by: Nir Tzachar <nir.tzachar@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/Makefile | 16 +- scripts/kconfig/lkc.h | 2 +- scripts/kconfig/lkc_proto.h | 3 +- scripts/kconfig/mconf.c | 13 - scripts/kconfig/menu.c | 16 +- scripts/kconfig/nconf.c | 1568 +++++++++++++++++++++++++++ scripts/kconfig/nconf.gui.c | 617 +++++++++++ scripts/kconfig/nconf.h | 95 ++ scripts/kconfig/zconf.tab.c_shipped | 2 +- scripts/kconfig/zconf.y | 2 +- 10 files changed, 2314 insertions(+), 20 deletions(-) create mode 100644 scripts/kconfig/nconf.c create mode 100644 scripts/kconfig/nconf.gui.c create mode 100644 scripts/kconfig/nconf.h diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 999e8a7d5bf7..75bdf5ae202c 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -23,6 +23,9 @@ menuconfig: $(obj)/mconf config: $(obj)/conf $< $(Kconfig) +nconfig: $(obj)/nconf + $< $(Kconfig) + oldconfig: $(obj)/conf $< -o $(Kconfig) @@ -110,6 +113,7 @@ endif # Help text used by make help help: @echo ' config - Update current config utilising a line-oriented program' + @echo ' nconfig - Update current config utilising a ncurses menu based program' @echo ' menuconfig - Update current config utilising a menu based program' @echo ' xconfig - Update current config utilising a QT based front-end' @echo ' gconfig - Update current config utilising a GTK based front-end' @@ -137,6 +141,8 @@ HOST_EXTRACFLAGS += -DLOCALE # =========================================================================== # Shared Makefile for the various kconfig executables: # conf: Used for defconfig, oldconfig and related targets +# nconf: Used for the nconfig target. +# Utilizes ncurses # mconf: Used for the menuconfig target # Utilizes the lxdialog package # qconf: Used for the xconfig target @@ -149,11 +155,16 @@ lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o conf-objs := conf.o zconf.tab.o -mconf-objs := mconf.o zconf.tab.o $(lxdialog) +mconf-objs := mconf.o zconf.tab.o $(lxdialog) +nconf-objs := nconf.o zconf.tab.o nconf.gui.o kxgettext-objs := kxgettext.o zconf.tab.o hostprogs-y := conf qconf gconf kxgettext +ifeq ($(MAKECMDGOALS),nconfig) + hostprogs-y += nconf +endif + ifeq ($(MAKECMDGOALS),menuconfig) hostprogs-y += mconf endif @@ -177,7 +188,7 @@ endif clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \ .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h -clean-files += mconf qconf gconf +clean-files += mconf qconf gconf nconf clean-files += config.pot linux.pot # Check that we have the required ncurses stuff installed for lxdialog (menuconfig) @@ -202,6 +213,7 @@ HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ -D LKC_DIRECT_LINK +HOSTLOADLIBES_nconf = -lmenu -lpanel -lncurses $(obj)/qconf.o: $(obj)/.tmp_qtcheck ifeq ($(qconf-target),1) diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index e59dd0c5787a..ce6549cdaccf 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -84,7 +84,7 @@ void conf_set_all_new_symbols(enum conf_def_mode mode); void kconfig_load(void); /* menu.c */ -void menu_init(void); +void _menu_init(void); void menu_warn(struct menu *menu, const char *fmt, ...); struct menu *menu_add_menu(void); void menu_end_menu(void); diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index ffeb532b2cff..41e652a8d1f6 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -17,7 +17,8 @@ P(menu_get_root_menu,struct menu *,(struct menu *menu)); P(menu_get_parent_menu,struct menu *,(struct menu *menu)); P(menu_has_help,bool,(struct menu *menu)); P(menu_get_help,const char *,(struct menu *menu)); -P(get_symbol_str,void,(struct gstr *r, struct symbol *sym)); +P(get_symbol_str, void, (struct gstr *r, struct symbol *sym)); +P(get_relations_str, struct gstr, (struct symbol **sym_arr)); P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); /* symbol.c */ diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index ac1e9dacde97..a4a75190457c 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -282,19 +282,6 @@ static void show_textbox(const char *title, const char *text, int r, int c); static void show_helptext(const char *title, const char *text); static void show_help(struct menu *menu); -static struct gstr get_relations_str(struct symbol **sym_arr) -{ - struct symbol *sym; - struct gstr res = str_new(); - int i; - - for (i = 0; sym_arr && (sym = sym_arr[i]); i++) - get_symbol_str(&res, sym); - if (!i) - str_append(&res, _("No matches found.\n")); - return res; -} - static char filename[PATH_MAX+1]; static void set_config_filename(const char *config_filename) { diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 059a2465c574..21bfb3dbc87a 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -38,7 +38,7 @@ static void prop_warn(struct property *prop, const char *fmt, ...) va_end(ap); } -void menu_init(void) +void _menu_init(void) { current_entry = current_menu = &rootmenu; last_entry_ptr = &rootmenu.list; @@ -515,6 +515,20 @@ void get_symbol_str(struct gstr *r, struct symbol *sym) str_append(r, "\n\n"); } +struct gstr get_relations_str(struct symbol **sym_arr) +{ + struct symbol *sym; + struct gstr res = str_new(); + int i; + + for (i = 0; sym_arr && (sym = sym_arr[i]); i++) + get_symbol_str(&res, sym); + if (!i) + str_append(&res, _("No matches found.\n")); + return res; +} + + void menu_get_ext_help(struct menu *menu, struct gstr *help) { struct symbol *sym = menu->sym; diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c new file mode 100644 index 000000000000..8c56150a757d --- /dev/null +++ b/scripts/kconfig/nconf.c @@ -0,0 +1,1568 @@ +/* + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com? + * Released under the terms of the GNU GPL v2.0. + * + * Derived from menuconfig. + * + */ +#define LKC_DIRECT_LINK +#include "lkc.h" +#include "nconf.h" + +static const char nconf_readme[] = N_( +"Overview\n" +"--------\n" +"Some kernel features may be built directly into the kernel.\n" +"Some may be made into loadable runtime modules. Some features\n" +"may be completely removed altogether. There are also certain\n" +"kernel parameters which are not really features, but must be\n" +"entered in as decimal or hexadecimal numbers or possibly text.\n" +"\n" +"Menu items beginning with following braces represent features that\n" +" [ ] can be built in or removed\n" +" < > can be built in, modularized or removed\n" +" { } can be built in or modularized (selected by other feature)\n" +" - - are selected by other feature,\n" +" XXX cannot be selected. use Symbol Info to find out why,\n" +"while *, M or whitespace inside braces means to build in, build as\n" +"a module or to exclude the feature respectively.\n" +"\n" +"To change any of these features, highlight it with the cursor\n" +"keys and press <Y> to build it in, <M> to make it a module or\n" +"<N> to removed it. You may also press the <Space Bar> to cycle\n" +"through the available options (ie. Y->N->M->Y).\n" +"\n" +"Some additional keyboard hints:\n" +"\n" +"Menus\n" +"----------\n" +"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n" +" you wish to change use <Enter> or <Space>. Goto submenu by \n" +" pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n" +" Submenus are designated by \"--->\".\n" +"\n" +" Shortcut: Press the option's highlighted letter (hotkey).\n" +" Pressing a hotkey more than once will sequence\n" +" through all visible items which use that hotkey.\n" +"\n" +" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n" +" unseen options into view.\n" +"\n" +"o To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n" +"\n" +"o To get help with an item, press <F1>\n" +" Shortcut: Press <h> or <?>.\n" +"\n" +"\n" +"Radiolists (Choice lists)\n" +"-----------\n" +"o Use the cursor keys to select the option you wish to set and press\n" +" <S> or the <SPACE BAR>.\n" +"\n" +" Shortcut: Press the first letter of the option you wish to set then\n" +" press <S> or <SPACE BAR>.\n" +"\n" +"o To see available help for the item, press <F1>\n" +" Shortcut: Press <H> or <?>.\n" +"\n" +"\n" +"Data Entry\n" +"-----------\n" +"o Enter the requested information and press <ENTER>\n" +" If you are entering hexadecimal values, it is not necessary to\n" +" add the '0x' prefix to the entry.\n" +"\n" +"o For help, press <F1>.\n" +"\n" +"\n" +"Text Box (Help Window)\n" +"--------\n" +"o Use the cursor keys to scroll up/down/left/right. The VI editor\n" +" keys h,j,k,l function here as do <SPACE BAR> for those\n" +" who are familiar with less and lynx.\n" +"\n" +"o Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n" +"\n" +"\n" +"Alternate Configuration Files\n" +"-----------------------------\n" +"nconfig supports the use of alternate configuration files for\n" +"those who, for various reasons, find it necessary to switch\n" +"between different kernel configurations.\n" +"\n" +"At the end of the main menu you will find two options. One is\n" +"for saving the current configuration to a file of your choosing.\n" +"The other option is for loading a previously saved alternate\n" +"configuration.\n" +"\n" +"Even if you don't use alternate configuration files, but you\n" +"find during a nconfig session that you have completely messed\n" +"up your settings, you may use the \"Load Alternate...\" option to\n" +"restore your previously saved settings from \".config\" without\n" +"restarting nconfig.\n" +"\n" +"Other information\n" +"-----------------\n" +"If you use nconfig in an XTERM window make sure you have your\n" +"$TERM variable set to point to a xterm definition which supports color.\n" +"Otherwise, nconfig will look rather bad. nconfig will not\n" +"display correctly in a RXVT window because rxvt displays only one\n" +"intensity of color, bright.\n" +"\n" +"nconfig will display larger menus on screens or xterms which are\n" +"set to display more than the standard 25 row by 80 column geometry.\n" +"In order for this to work, the \"stty size\" command must be able to\n" +"display the screen's current row and column geometry. I STRONGLY\n" +"RECOMMEND that you make sure you do NOT have the shell variables\n" +"LINES and COLUMNS exported into your environment. Some distributions\n" +"export those variables via /etc/profile. Some ncurses programs can\n" +"become confused when those variables (LINES & COLUMNS) don't reflect\n" +"the true screen size.\n" +"\n" +"Optional personality available\n" +"------------------------------\n" +"If you prefer to have all of the kernel options listed in a single\n" +"menu, rather than the default multimenu hierarchy, run the nconfig\n" +"with NCONFIG_MODE environment variable set to single_menu. Example:\n" +"\n" +"make NCONFIG_MODE=single_menu nconfig\n" +"\n" +"<Enter> will then unroll the appropriate category, or enfold it if it\n" +"is already unrolled.\n" +"\n" +"Note that this mode can eventually be a little more CPU expensive\n" +"(especially with a larger number of unrolled categories) than the\n" +"default mode.\n" +"\n"), +menu_no_f_instructions[] = N_( +" You do not have function keys support. Please follow the\n" +" following instructions:\n" +" Arrow keys navigate the menu.\n" +" <Enter> or <right-arrow> selects submenus --->.\n" +" Capital Letters are hotkeys.\n" +" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n" +" Pressing SpaceBar toggles between the above options\n" +" Press <Esc> or <left-arrow> to go back one menu, \n" +" <?> or <h> for Help, </> for Search.\n" +" <1> is interchangable with <F1>, <2> with <F2>, etc.\n" +" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n" +" <Esc> always leaves the current window\n"), +menu_instructions[] = N_( +" Arrow keys navigate the menu.\n" +" <Enter> or <right-arrow> selects submenus --->.\n" +" Capital Letters are hotkeys.\n" +" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n" +" Pressing SpaceBar toggles between the above options\n" +" Press <Esc>, <F3> or <left-arrow> to go back one menu, \n" +" <?>, <F1> or <h> for Help, </> for Search.\n" +" <1> is interchangable with <F1>, <2> with <F2>, etc.\n" +" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n" +" <Esc> always leaves the current window\n"), +radiolist_instructions[] = N_( +" Use the arrow keys to navigate this window or\n" +" press the hotkey of the item you wish to select\n" +" followed by the <SPACE BAR>.\n" +" Press <?>, <F1> or <h> for additional information about this option.\n"), +inputbox_instructions_int[] = N_( +"Please enter a decimal value.\n" +"Fractions will not be accepted.\n" +"Press <RETURN> to accept, <ESC> to cancel."), +inputbox_instructions_hex[] = N_( +"Please enter a hexadecimal value.\n" +"Press <RETURN> to accept, <ESC> to cancel."), +inputbox_instructions_string[] = N_( +"Please enter a string value.\n" +"Press <RETURN> to accept, <ESC> to cancel."), +setmod_text[] = N_( +"This feature depends on another which\n" +"has been configured as a module.\n" +"As a result, this feature will be built as a module."), +nohelp_text[] = N_( +"There is no help available for this kernel option.\n"), +load_config_text[] = N_( +"Enter the name of the configuration file you wish to load.\n" +"Accept the name shown to restore the configuration you\n" +"last retrieved. Leave blank to abort."), +load_config_help[] = N_( +"\n" +"For various reasons, one may wish to keep several different kernel\n" +"configurations available on a single machine.\n" +"\n" +"If you have saved a previous configuration in a file other than the\n" +"kernel's default, entering the name of the file here will allow you\n" +"to modify that configuration.\n" +"\n" +"If you are uncertain, then you have probably never used alternate\n" +"configuration files. You should therefor leave this blank to abort.\n"), +save_config_text[] = N_( +"Enter a filename to which this configuration should be saved\n" +"as an alternate. Leave blank to abort."), +save_config_help[] = N_( +"\n" +"For various reasons, one may wish to keep different kernel\n" +"configurations available on a single machine.\n" +"\n" +"Entering a file name here will allow you to later retrieve, modify\n" +"and use the current configuration as an alternate to whatever\n" +"configuration options you have selected at that time.\n" +"\n" +"If you are uncertain what all this means then you should probably\n" +"leave this blank.\n"), +search_help[] = N_( +"\n" +"Search for CONFIG_ symbols and display their relations.\n" +"Regular expressions are allowed.\n" +"Example: search for \"^FOO\"\n" +"Result:\n" +"-----------------------------------------------------------------\n" +"Symbol: FOO [ = m]\n" +"Prompt: Foo bus is used to drive the bar HW\n" +"Defined at drivers/pci/Kconfig:47\n" +"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" +"Location:\n" +" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" +" -> PCI support (PCI [ = y])\n" +" -> PCI access mode (<choice> [ = y])\n" +"Selects: LIBCRC32\n" +"Selected by: BAR\n" +"-----------------------------------------------------------------\n" +"o The line 'Prompt:' shows the text used in the menu structure for\n" +" this CONFIG_ symbol\n" +"o The 'Defined at' line tell at what file / line number the symbol\n" +" is defined\n" +"o The 'Depends on:' line tell what symbols needs to be defined for\n" +" this symbol to be visible in the menu (selectable)\n" +"o The 'Location:' lines tell where in the menu structure this symbol\n" +" is located\n" +" A location followed by a [ = y] indicate that this is a selectable\n" +" menu item - and current value is displayed inside brackets.\n" +"o The 'Selects:' line tell what symbol will be automatically\n" +" selected if this symbol is selected (y or m)\n" +"o The 'Selected by' line tell what symbol has selected this symbol\n" +"\n" +"Only relevant lines are shown.\n" +"\n\n" +"Search examples:\n" +"Examples: USB = > find all CONFIG_ symbols containing USB\n" +" ^USB => find all CONFIG_ symbols starting with USB\n" +" USB$ => find all CONFIG_ symbols ending with USB\n" +"\n"); + +struct mitem { + char str[256]; + char tag; + void *usrptr; + int is_hot; + int is_visible; +}; + +#define MAX_MENU_ITEMS 4096 +static int show_all_items; +static int indent; +static struct menu *current_menu; +static int child_count; +static int single_menu_mode; +/* the window in which all information appears */ +static WINDOW *main_window; +/* the largest size of the menu window */ +static int mwin_max_lines; +static int mwin_max_cols; +/* the window in which we show option buttons */ +static MENU *curses_menu; +static ITEM *curses_menu_items[MAX_MENU_ITEMS]; +static struct mitem k_menu_items[MAX_MENU_ITEMS]; +static int items_num; +static int global_exit; +/* the currently selected button */ +const char *current_instructions = menu_instructions; +/* this array is used to implement hot keys. it is updated in item_make and + * resetted in clean_items. It would be better to use a hash, but lets keep it + * simple... */ +#define MAX_SAME_KEY MAX_MENU_ITEMS +struct { + int count; + int ptrs[MAX_MENU_ITEMS]; +} hotkeys[1<<(sizeof(char)*8)]; + +static void conf(struct menu *menu); +static void conf_choice(struct menu *menu); +static void conf_string(struct menu *menu); +static void conf_load(void); +static void conf_save(void); +static void show_help(struct menu *menu); +static int do_exit(void); +static void setup_windows(void); + +typedef void (*function_key_handler_t)(int *key, struct menu *menu); +static void handle_f1(int *key, struct menu *current_item); +static void handle_f2(int *key, struct menu *current_item); +static void handle_f3(int *key, struct menu *current_item); +static void handle_f4(int *key, struct menu *current_item); +static void handle_f5(int *key, struct menu *current_item); +static void handle_f6(int *key, struct menu *current_item); +static void handle_f7(int *key, struct menu *current_item); +static void handle_f8(int *key, struct menu *current_item); + +struct function_keys { + const char *key_str; + const char *func; + function_key key; + function_key_handler_t handler; +}; + +static const int function_keys_num = 8; +struct function_keys function_keys[] = { + { + .key_str = "F1", + .func = "Help", + .key = F_HELP, + .handler = handle_f1, + }, + { + .key_str = "F2", + .func = "Symbol Info", + .key = F_SYMBOL, + .handler = handle_f2, + }, + { + .key_str = "F3", + .func = "Instructions", + .key = F_INSTS, + .handler = handle_f3, + }, + { + .key_str = "F4", + .func = "Config", + .key = F_CONF, + .handler = handle_f4, + }, + { + .key_str = "F5", + .func = "Back", + .key = F_BACK, + .handler = handle_f5, + }, + { + .key_str = "F6", + .func = "Save", + .key = F_SAVE, + .handler = handle_f6, + }, + { + .key_str = "F7", + .func = "Load", + .key = F_LOAD, + .handler = handle_f7, + }, + { + .key_str = "F8", + .func = "Exit", + .key = F_EXIT, + .handler = handle_f8, + }, +}; + +static void print_function_line(void) +{ + int i; + int offset = 1; + const int skip = 1; + + for (i = 0; i < function_keys_num; i++) { + wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]); + mvwprintw(main_window, LINES-3, offset, + "%s", + function_keys[i].key_str); + wattrset(main_window, attributes[FUNCTION_TEXT]); + offset += strlen(function_keys[i].key_str); + mvwprintw(main_window, LINES-3, + offset, "%s", + function_keys[i].func); + offset += strlen(function_keys[i].func) + skip; + } + wattrset(main_window, attributes[NORMAL]); +} + +/* help */ +static void handle_f1(int *key, struct menu *current_item) +{ + show_scroll_win(main_window, + _("README"), _(nconf_readme)); + return; +} + +/* symbole help */ +static void handle_f2(int *key, struct menu *current_item) +{ + show_help(current_item); + return; +} + +/* instructions */ +static void handle_f3(int *key, struct menu *current_item) +{ + show_scroll_win(main_window, + _("Instructions"), + _(current_instructions)); + return; +} + +/* config */ +static void handle_f4(int *key, struct menu *current_item) +{ + int res = btn_dialog(main_window, + _("Show all symbols?"), + 2, + " <Show All> ", + "<Don't show all>"); + if (res == 0) + show_all_items = 1; + else if (res == 1) + show_all_items = 0; + + return; +} + +/* back */ +static void handle_f5(int *key, struct menu *current_item) +{ + *key = KEY_LEFT; + return; +} + +/* save */ +static void handle_f6(int *key, struct menu *current_item) +{ + conf_save(); + return; +} + +/* load */ +static void handle_f7(int *key, struct menu *current_item) +{ + conf_load(); + return; +} + +/* exit */ +static void handle_f8(int *key, struct menu *current_item) +{ + do_exit(); + return; +} + +/* return != 0 to indicate the key was handles */ +int process_special_keys(int *key, struct menu *menu) +{ + int i; + + if (*key == KEY_RESIZE) { + setup_windows(); + return 1; + } + + for (i = 0; i < function_keys_num; i++) { + if (*key == KEY_F(function_keys[i].key) || + *key == '0' + function_keys[i].key){ + function_keys[i].handler(key, menu); + return 1; + } + } + + return 0; +} + +static void clean_items(void) +{ + int i; + for (i = 0; curses_menu_items[i]; i++) + free_item(curses_menu_items[i]); + bzero(curses_menu_items, sizeof(curses_menu_items)); + bzero(k_menu_items, sizeof(k_menu_items)); + bzero(hotkeys, sizeof(hotkeys)); + items_num = 0; +} + +/* return the index of the next hot item, or -1 if no such item exists */ +int get_next_hot(int c) +{ + static int hot_index; + static int hot_char; + + if (c < 0 || c > 255 || hotkeys[c].count <= 0) + return -1; + + if (hot_char == c) { + hot_index = (hot_index+1)%hotkeys[c].count; + return hotkeys[c].ptrs[hot_index]; + } else { + hot_char = c; + hot_index = 0; + return hotkeys[c].ptrs[0]; + } +} + +/* can the char c be a hot key? no, if c is a common shortcut used elsewhere */ +int canbhot(char c) +{ + c = tolower(c); + return isalnum(c) && c != 'y' && c != 'm' && c != 'h' && + c != 'n' && c != '?'; +} + +/* check if str already contains a hot key. */ +int is_hot(int index) +{ + return k_menu_items[index].is_hot; +} + +/* find the first possible hot key, and mark it. + * index is the index of the item in the menu + * return 0 on success*/ +int make_hot(char *dest, int len, const char *org, int index) +{ + int position = -1; + int i; + int tmp; + int c; + int org_len = strlen(org); + + if (org == NULL || is_hot(index)) + return 1; + + /* make sure not to make hot keys out of markers. + * find where to start looking for a hot key + */ + i = 0; + /* skip white space */ + while (i < org_len && org[i] == ' ') + i++; + if (i == org_len) + return -1; + /* if encountering '(' or '<' or '[', find the match and look from there + **/ + if (org[i] == '[' || org[i] == '<' || org[i] == '(') { + i++; + for (; i < org_len; i++) + if (org[i] == ']' || org[i] == '>' || org[i] == ')') + break; + } + if (i == org_len) + return -1; + for (; i < org_len; i++) { + if (canbhot(org[i]) && org[i-1] != '<' && org[i-1] != '(') { + position = i; + break; + } + } + if (position == -1) + return 1; + + /* ok, char at org[position] should be a hot key to this item */ + c = tolower(org[position]); + tmp = hotkeys[c].count; + hotkeys[c].ptrs[tmp] = index; + hotkeys[c].count++; + /* + snprintf(dest, len, "%.*s(%c)%s", position, org, org[position], + &org[position+1]); + */ + /* make org[position] uppercase, and all leading letter small case */ + strncpy(dest, org, len); + for (i = 0; i < position; i++) + dest[i] = tolower(dest[i]); + dest[position] = toupper(dest[position]); + k_menu_items[index].is_hot = 1; + return 0; +} + +/* Make a new item. Add a hotkey mark in the first possible letter. + * As ncurses does not allow any attributes inside menue item, we mark the + * hot key as the first capitalized letter in the string */ +void item_make(struct menu *menu, char tag, const char *fmt, ...) +{ + va_list ap; + char tmp_str[256]; + + if (items_num > MAX_MENU_ITEMS-1) + return; + + bzero(&k_menu_items[items_num], sizeof(k_menu_items[0])); + k_menu_items[items_num].tag = tag; + k_menu_items[items_num].usrptr = menu; + if (menu != NULL) + k_menu_items[items_num].is_visible = + menu_is_visible(menu); + else + k_menu_items[items_num].is_visible = 1; + + va_start(ap, fmt); + vsnprintf(tmp_str, sizeof(tmp_str), fmt, ap); + if (!k_menu_items[items_num].is_visible) + memcpy(tmp_str, "XXX", 3); + va_end(ap); + if (make_hot( + k_menu_items[items_num].str, + sizeof(k_menu_items[items_num].str), tmp_str, items_num) != 0) + strncpy(k_menu_items[items_num].str, + tmp_str, + sizeof(k_menu_items[items_num].str)); + + curses_menu_items[items_num] = new_item( + k_menu_items[items_num].str, + k_menu_items[items_num].str); + set_item_userptr(curses_menu_items[items_num], + &k_menu_items[items_num]); + /* + if (!k_menu_items[items_num].is_visible) + item_opts_off(curses_menu_items[items_num], O_SELECTABLE); + */ + + items_num++; + curses_menu_items[items_num] = NULL; +} + +/* very hackish. adds a string to the last item added */ +void item_add_str(const char *fmt, ...) +{ + va_list ap; + int index = items_num-1; + char new_str[256]; + char tmp_str[256]; + + if (index < 0) + return; + + va_start(ap, fmt); + vsnprintf(new_str, sizeof(new_str), fmt, ap); + va_end(ap); + snprintf(tmp_str, sizeof(tmp_str), "%s%s", + k_menu_items[index].str, new_str); + if (make_hot(k_menu_items[index].str, + sizeof(k_menu_items[index].str), tmp_str, index) != 0) + strncpy(k_menu_items[index].str, + tmp_str, + sizeof(k_menu_items[index].str)); + + free_item(curses_menu_items[index]); + curses_menu_items[index] = new_item( + k_menu_items[index].str, + k_menu_items[index].str); + set_item_userptr(curses_menu_items[index], + &k_menu_items[index]); +} + +/* get the tag of the currently selected item */ +char item_tag(void) +{ + ITEM *cur; + struct mitem *mcur; + + cur = current_item(curses_menu); + if (cur == NULL) + return 0; + mcur = (struct mitem *) item_userptr(cur); + return mcur->tag; +} + +int curses_item_index(void) +{ + return item_index(current_item(curses_menu)); +} + +void *item_data(void) +{ + ITEM *cur; + struct mitem *mcur; + + cur = current_item(curses_menu); + mcur = (struct mitem *) item_userptr(cur); + return mcur->usrptr; + +} + +int item_is_tag(char tag) +{ + return item_tag() == tag; +} + +static char filename[PATH_MAX+1]; +static char menu_backtitle[PATH_MAX+128]; +const char *set_config_filename(const char *config_filename) +{ + int size; + struct symbol *sym; + + sym = sym_lookup("KERNELVERSION", 0); + sym_calc_value(sym); + size = snprintf(menu_backtitle, sizeof(menu_backtitle), + _("%s - Linux Kernel v%s Configuration"), + config_filename, sym_get_string_value(sym)); + if (size >= sizeof(menu_backtitle)) + menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + + size = snprintf(filename, sizeof(filename), "%s", config_filename); + if (size >= sizeof(filename)) + filename[sizeof(filename)-1] = '\0'; + return menu_backtitle; +} + +/* command = 0 is supress, 1 is restore */ +static void supress_stdout(int command) +{ + static FILE *org_stdout; + static FILE *org_stderr; + + if (command == 0) { + org_stdout = stdout; + org_stderr = stderr; + stdout = fopen("/dev/null", "a"); + stderr = fopen("/dev/null", "a"); + } else { + fclose(stdout); + fclose(stderr); + stdout = org_stdout; + stderr = org_stderr; + } +} + +/* return = 0 means we are successful. + * -1 means go on doing what you were doing + */ +static int do_exit(void) +{ + int res; + if (!conf_get_changed()) { + global_exit = 1; + return 0; + } + res = btn_dialog(main_window, + _("Do you wish to save your " + "new kernel configuration?\n" + "<ESC> to cancel and resume nconfig."), + 2, + " <save> ", + "<don't save>"); + if (res == KEY_EXIT) { + global_exit = 0; + return -1; + } + + /* if we got here, the user really wants to exit */ + switch (res) { + case 0: + supress_stdout(0); + res = conf_write(filename); + supress_stdout(1); + if (res) + btn_dialog( + main_window, + _("Error during writing of the kernel " + "configuration.\n" + "Your kernel configuration " + "changes were NOT saved."), + 1, + "<OK>"); + else { + char buf[1024]; + snprintf(buf, 1024, + _("Configuration written to %s\n" + "End of Linux kernel configuration.\n" + "Execute 'make' to build the kernel or try" + " 'make help'."), filename); + btn_dialog( + main_window, + buf, + 1, + "<OK>"); + } + break; + default: + btn_dialog( + main_window, + _("Your kernel configuration changes were NOT saved."), + 1, + "<OK>"); + break; + } + global_exit = 1; + return 0; +} + + +static void search_conf(void) +{ + struct symbol **sym_arr; + struct gstr res; + char dialog_input_result[100]; + char *dialog_input; + int dres; +again: + dres = dialog_inputbox(main_window, + _("Search Configuration Parameter"), + _("Enter CONFIG_ (sub)string to search for " + "(with or without \"CONFIG\")"), + "", dialog_input_result, 99); + switch (dres) { + case 0: + break; + case 1: + show_scroll_win(main_window, + _("Search Configuration"), search_help); + goto again; + default: + return; + } + + /* strip CONFIG_ if necessary */ + dialog_input = dialog_input_result; + if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0) + dialog_input += 7; + + sym_arr = sym_re_search(dialog_input); + res = get_relations_str(sym_arr); + free(sym_arr); + show_scroll_win(main_window, + _("Search Results"), str_get(&res)); + str_free(&res); +} + + +static void build_conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + int type, tmp, doint = 2; + tristate val; + char ch; + + if (!menu || (!show_all_items && !menu_is_visible(menu))) + return; + + sym = menu->sym; + prop = menu->prompt; + if (!sym) { + if (prop && menu != current_menu) { + const char *prompt = menu_get_prompt(menu); + enum prop_type ptype; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + switch (ptype) { + case P_MENU: + child_count++; + prompt = _(prompt); + if (single_menu_mode) { + item_make(menu, 'm', + "%s%*c%s", + menu->data ? "-->" : "++>", + indent + 1, ' ', prompt); + } else + item_make(menu, 'm', + " %*c%s --->", + indent + 1, + ' ', prompt); + + if (single_menu_mode && menu->data) + goto conf_childs; + return; + case P_COMMENT: + if (prompt) { + child_count++; + item_make(menu, ':', + " %*c*** %s ***", + indent + 1, ' ', + _(prompt)); + } + break; + default: + if (prompt) { + child_count++; + item_make(menu, ':', "---%*c%s", + indent + 1, ' ', + _(prompt)); + } + } + } else + doint = 0; + goto conf_childs; + } + + type = sym_get_type(sym); + if (sym_is_choice(sym)) { + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + child_count++; + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) && child->sym == def_sym) + def_menu = child; + } + + val = sym_get_tristate_value(sym); + if (sym_is_changable(sym)) { + switch (type) { + case S_BOOLEAN: + item_make(menu, 't', "[%c]", + val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: + ch = '*'; + break; + case mod: + ch = 'M'; + break; + default: + ch = ' '; + break; + } + item_make(menu, 't', "<%c>", ch); + break; + } + } else { + item_make(menu, def_menu ? 't' : ':', " "); + } + + item_add_str("%*c%s", indent + 1, + ' ', _(menu_get_prompt(menu))); + if (val == yes) { + if (def_menu) { + item_add_str(" (%s)", + _(menu_get_prompt(def_menu))); + item_add_str(" --->"); + if (def_menu->list) { + indent += 2; + build_conf(def_menu); + indent -= 2; + } + } + return; + } + } else { + if (menu == current_menu) { + item_make(menu, ':', + "---%*c%s", indent + 1, + ' ', _(menu_get_prompt(menu))); + goto conf_childs; + } + child_count++; + val = sym_get_tristate_value(sym); + if (sym_is_choice_value(sym) && val == yes) { + item_make(menu, ':', " "); + } else { + switch (type) { + case S_BOOLEAN: + if (sym_is_changable(sym)) + item_make(menu, 't', "[%c]", + val == no ? ' ' : '*'); + else + item_make(menu, 't', "-%c-", + val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: + ch = '*'; + break; + case mod: + ch = 'M'; + break; + default: + ch = ' '; + break; + } + if (sym_is_changable(sym)) { + if (sym->rev_dep.tri == mod) + item_make(menu, + 't', "{%c}", ch); + else + item_make(menu, + 't', "<%c>", ch); + } else + item_make(menu, 't', "-%c-", ch); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); + item_make(menu, 's', "(%s)", + sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', + _(menu_get_prompt(menu)), + (sym_has_value(sym) || + !sym_is_changable(sym)) ? "" : + _(" (NEW)")); + goto conf_childs; + } + } + item_add_str("%*c%s%s", indent + 1, ' ', + _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + if (menu->prompt && menu->prompt->type == P_MENU) { + item_add_str(" --->"); + return; + } + } + +conf_childs: + indent += doint; + for (child = menu->list; child; child = child->next) + build_conf(child); + indent -= doint; +} + +static void reset_menu(void) +{ + unpost_menu(curses_menu); + clean_items(); +} + +/* adjust the menu to show this item. + * prefer not to scroll the menu if possible*/ +static void center_item(int selected_index, int *last_top_row) +{ + int toprow; + int maxy, maxx; + + scale_menu(curses_menu, &maxy, &maxx); + set_top_row(curses_menu, *last_top_row); + toprow = top_row(curses_menu); + if (selected_index >= toprow && selected_index < toprow+maxy) { + /* we can only move the selected item. no need to scroll */ + set_current_item(curses_menu, + curses_menu_items[selected_index]); + } else { + toprow = max(selected_index-maxy/2, 0); + if (toprow >= item_count(curses_menu)-maxy) + toprow = item_count(curses_menu)-mwin_max_lines; + set_top_row(curses_menu, toprow); + set_current_item(curses_menu, + curses_menu_items[selected_index]); + } + *last_top_row = toprow; + post_menu(curses_menu); + refresh_all_windows(main_window); +} + +/* this function assumes reset_menu has been called before */ +static void show_menu(const char *prompt, const char *instructions, + int selected_index, int *last_top_row) +{ + int maxx, maxy; + WINDOW *menu_window; + + current_instructions = instructions; + + clear(); + wattrset(main_window, attributes[NORMAL]); + print_in_middle(stdscr, 1, 0, COLS, + menu_backtitle, + attributes[MAIN_HEADING]); + + wattrset(main_window, attributes[MAIN_MENU_BOX]); + box(main_window, 0, 0); + wattrset(main_window, attributes[MAIN_MENU_HEADING]); + mvwprintw(main_window, 0, 3, " %s ", prompt); + wattrset(main_window, attributes[NORMAL]); + + set_menu_items(curses_menu, curses_menu_items); + + /* position the menu at the middle of the screen */ + scale_menu(curses_menu, &maxy, &maxx); + maxx = min(maxx, mwin_max_cols); + maxy = mwin_max_lines-1; + menu_window = derwin(main_window, + maxy, + maxx, + 2, + (mwin_max_cols-maxx)/2); + keypad(menu_window, TRUE); + set_menu_win(curses_menu, menu_window); + set_menu_sub(curses_menu, menu_window); + + /* must reassert this after changing items, otherwise returns to a + * default of 16 + */ + set_menu_format(curses_menu, maxy, 1); + center_item(selected_index, last_top_row); + set_menu_format(curses_menu, maxy, 1); + + print_function_line(); + + /* Post the menu */ + post_menu(curses_menu); + refresh_all_windows(main_window); +} + + +static void conf(struct menu *menu) +{ + char pattern[256]; + struct menu *submenu = 0; + const char *prompt = menu_get_prompt(menu); + struct symbol *sym; + struct menu *active_menu = NULL; + int res; + int current_index = 0; + int last_top_row = 0; + + bzero(pattern, sizeof(pattern)); + + while (!global_exit) { + reset_menu(); + current_menu = menu; + build_conf(menu); + if (!child_count) + break; + + show_menu(prompt ? _(prompt) : _("Main Menu"), + _(menu_instructions), + current_index, &last_top_row); + keypad((menu_win(curses_menu)), TRUE); + while (!global_exit && (res = wgetch(menu_win(curses_menu)))) { + if (process_special_keys(&res, + (struct menu *) item_data())) + break; + switch (res) { + case KEY_DOWN: + menu_driver(curses_menu, REQ_DOWN_ITEM); + break; + case KEY_UP: + menu_driver(curses_menu, REQ_UP_ITEM); + break; + case KEY_NPAGE: + menu_driver(curses_menu, REQ_SCR_DPAGE); + break; + case KEY_PPAGE: + menu_driver(curses_menu, REQ_SCR_UPAGE); + break; + case KEY_HOME: + menu_driver(curses_menu, REQ_FIRST_ITEM); + break; + case KEY_END: + menu_driver(curses_menu, REQ_LAST_ITEM); + break; + case 'h': + case '?': + show_help((struct menu *) item_data()); + break; + } + if (res == 10 || res == 27 || + res == 32 || res == 'n' || res == 'y' || + res == KEY_LEFT || res == KEY_RIGHT || + res == 'm' || res == '/') + break; + else if (canbhot(res)) { + /* check for hot keys: */ + int tmp = get_next_hot(res); + if (tmp != -1) + center_item(tmp, &last_top_row); + } + refresh_all_windows(main_window); + } + + refresh_all_windows(main_window); + /* if ESC or left*/ + if (res == 27 || (menu != &rootmenu && res == KEY_LEFT)) + break; + + /* remember location in the menu */ + last_top_row = top_row(curses_menu); + current_index = curses_item_index(); + + if (!item_tag()) + continue; + + submenu = (struct menu *) item_data(); + active_menu = (struct menu *)item_data(); + if (!submenu || !menu_is_visible(submenu)) + continue; + if (submenu) + sym = submenu->sym; + else + sym = NULL; + + switch (res) { + case ' ': + if (item_is_tag('t')) + sym_toggle_tristate_value(sym); + else if (item_is_tag('m')) + conf(submenu); + break; + case KEY_RIGHT: + case 10: /* ENTER WAS PRESSED */ + switch (item_tag()) { + case 'm': + if (single_menu_mode) + submenu->data = + (void *) (long) !submenu->data; + else + conf(submenu); + break; + case 't': + if (sym_is_choice(sym) && + sym_get_tristate_value(sym) == yes) + conf_choice(submenu); + else if (submenu->prompt && + submenu->prompt->type == P_MENU) + conf(submenu); + else if (res == 10) + sym_toggle_tristate_value(sym); + break; + case 's': + conf_string(submenu); + break; + } + break; + case 'y': + if (item_is_tag('t')) { + if (sym_set_tristate_value(sym, yes)) + break; + if (sym_set_tristate_value(sym, mod)) + btn_dialog(main_window, setmod_text, 0); + } + break; + case 'n': + if (item_is_tag('t')) + sym_set_tristate_value(sym, no); + break; + case 'm': + if (item_is_tag('t')) + sym_set_tristate_value(sym, mod); + break; + case '/': + search_conf(); + break; + } + } +} + +static void show_help(struct menu *menu) +{ + struct gstr help = str_new(); + + if (menu && menu->sym && menu_has_help(menu)) { + if (menu->sym->name) { + str_printf(&help, "CONFIG_%s:\n\n", menu->sym->name); + str_append(&help, _(menu_get_help(menu))); + str_append(&help, "\n"); + get_symbol_str(&help, menu->sym); + } + } else { + str_append(&help, nohelp_text); + } + show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help)); + str_free(&help); +} + +static void conf_choice(struct menu *menu) +{ + const char *prompt = _(menu_get_prompt(menu)); + struct menu *child = 0; + struct symbol *active; + int selected_index = 0; + int last_top_row = 0; + int res, i = 0; + + active = sym_get_choice_value(menu->sym); + /* this is mostly duplicated from the conf() function. */ + while (!global_exit) { + reset_menu(); + + for (i = 0, child = menu->list; child; child = child->next) { + if (!show_all_items && !menu_is_visible(child)) + continue; + + if (child->sym == sym_get_choice_value(menu->sym)) + item_make(child, ':', "<X> %s", + _(menu_get_prompt(child))); + else + item_make(child, ':', " %s", + _(menu_get_prompt(child))); + if (child->sym == active){ + last_top_row = top_row(curses_menu); + selected_index = i; + } + i++; + } + show_menu(prompt ? _(prompt) : _("Choice Menu"), + _(radiolist_instructions), + selected_index, + &last_top_row); + while (!global_exit && (res = wgetch(menu_win(curses_menu)))) { + if (process_special_keys( + &res, + (struct menu *) item_data())) + break; + switch (res) { + case KEY_DOWN: + menu_driver(curses_menu, REQ_DOWN_ITEM); + break; + case KEY_UP: + menu_driver(curses_menu, REQ_UP_ITEM); + break; + case KEY_NPAGE: + menu_driver(curses_menu, REQ_SCR_DPAGE); + break; + case KEY_PPAGE: + menu_driver(curses_menu, REQ_SCR_UPAGE); + break; + case KEY_HOME: + menu_driver(curses_menu, REQ_FIRST_ITEM); + break; + case KEY_END: + menu_driver(curses_menu, REQ_LAST_ITEM); + break; + case 'h': + case '?': + show_help((struct menu *) item_data()); + break; + } + if (res == 10 || res == 27 || res == ' ' || + res == KEY_LEFT) + break; + else if (canbhot(res)) { + /* check for hot keys: */ + int tmp = get_next_hot(res); + if (tmp != -1) + center_item(tmp, &last_top_row); + } + refresh_all_windows(main_window); + } + /* if ESC or left */ + if (res == 27 || res == KEY_LEFT) + break; + + child = item_data(); + if (!child || !menu_is_visible(child)) + continue; + switch (res) { + case ' ': + case 10: + case KEY_RIGHT: + sym_set_tristate_value(child->sym, yes); + return; + case 'h': + case '?': + show_help(child); + active = child->sym; + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_string(struct menu *menu) +{ + const char *prompt = menu_get_prompt(menu); + char dialog_input_result[256]; + + while (1) { + int res; + const char *heading; + + switch (sym_get_type(menu->sym)) { + case S_INT: + heading = _(inputbox_instructions_int); + break; + case S_HEX: + heading = _(inputbox_instructions_hex); + break; + case S_STRING: + heading = _(inputbox_instructions_string); + break; + default: + heading = _("Internal nconf error!"); + } + res = dialog_inputbox(main_window, + prompt ? _(prompt) : _("Main Menu"), + heading, + sym_get_string_value(menu->sym), + dialog_input_result, + sizeof(dialog_input_result)); + switch (res) { + case 0: + if (sym_set_string_value(menu->sym, + dialog_input_result)) + return; + btn_dialog(main_window, + _("You have made an invalid entry."), 0); + break; + case 1: + show_help(menu); + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_load(void) +{ + char dialog_input_result[256]; + while (1) { + int res; + res = dialog_inputbox(main_window, + NULL, load_config_text, + filename, + dialog_input_result, + sizeof(dialog_input_result)); + switch (res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_read(dialog_input_result)) { + set_config_filename(dialog_input_result); + sym_set_change_count(1); + return; + } + btn_dialog(main_window, _("File does not exist!"), 0); + break; + case 1: + show_scroll_win(main_window, + _("Load Alternate Configuration"), + load_config_help); + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_save(void) +{ + char dialog_input_result[256]; + while (1) { + int res; + res = dialog_inputbox(main_window, + NULL, save_config_text, + filename, + dialog_input_result, + sizeof(dialog_input_result)); + switch (res) { + case 0: + if (!dialog_input_result[0]) + return; + supress_stdout(0); + res = conf_write(dialog_input_result); + supress_stdout(1); + if (!res) { + char buf[1024]; + sprintf(buf, "%s %s", + _("configuration file saved to: "), + dialog_input_result); + btn_dialog(main_window, + buf, 1, "<OK>"); + set_config_filename(dialog_input_result); + return; + } + btn_dialog(main_window, _("Can't create file! " + "Probably a nonexistent directory."), + 1, "<OK>"); + break; + case 1: + show_scroll_win(main_window, + _("Save Alternate Configuration"), + save_config_help); + break; + case KEY_EXIT: + return; + } + } +} + +void setup_windows(void) +{ + if (main_window != NULL) + delwin(main_window); + + /* set up the menu and menu window */ + main_window = newwin(LINES-2, COLS-2, 2, 1); + keypad(main_window, TRUE); + mwin_max_lines = LINES-6; + mwin_max_cols = COLS-6; + + /* panels order is from bottom to top */ + new_panel(main_window); +} + +int main(int ac, char **av) +{ + char *mode; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + conf_parse(av[1]); + conf_read(NULL); + + mode = getenv("NCONFIG_MODE"); + if (mode) { + if (!strcasecmp(mode, "single_menu")) + single_menu_mode = 1; + } + + /* Initialize curses */ + initscr(); + /* set color theme */ + set_colors(); + + cbreak(); + noecho(); + keypad(stdscr, TRUE); + curs_set(0); + + if (COLS < 75 || LINES < 20) { + endwin(); + printf("Your terminal should have at " + "least 20 lines and 75 columns\n"); + return 1; + } + + notimeout(stdscr, FALSE); + ESCDELAY = 1; + + /* set btns menu */ + curses_menu = new_menu(curses_menu_items); + menu_opts_off(curses_menu, O_SHOWDESC); + menu_opts_off(curses_menu, O_SHOWMATCH); + menu_opts_on(curses_menu, O_ONEVALUE); + menu_opts_on(curses_menu, O_NONCYCLIC); + set_menu_mark(curses_menu, " "); + set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]); + set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]); + set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]); + + set_config_filename(conf_get_configname()); + setup_windows(); + + /* check for KEY_FUNC(1) */ + if (has_key(KEY_F(1)) == FALSE) { + show_scroll_win(main_window, + _("Instructions"), + _(menu_no_f_instructions)); + } + + + + /* do the work */ + while (!global_exit) { + conf(&rootmenu); + if (!global_exit && do_exit() == 0) + break; + } + /* ok, we are done */ + unpost_menu(curses_menu); + free_menu(curses_menu); + delwin(main_window); + clear(); + refresh(); + endwin(); + return 0; +} + diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c new file mode 100644 index 000000000000..879ade6dd604 --- /dev/null +++ b/scripts/kconfig/nconf.gui.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com? + * Released under the terms of the GNU GPL v2.0. + * + * Derived from menuconfig. + * + */ +#include "nconf.h" + +/* a list of all the different widgets we use */ +attributes_t attributes[ATTR_MAX+1] = {0}; + +/* available colors: + COLOR_BLACK 0 + COLOR_RED 1 + COLOR_GREEN 2 + COLOR_YELLOW 3 + COLOR_BLUE 4 + COLOR_MAGENTA 5 + COLOR_CYAN 6 + COLOR_WHITE 7 + */ +void set_normal_colors(void) +{ + init_pair(NORMAL, -1, -1); + init_pair(MAIN_HEADING, COLOR_MAGENTA, -1); + + /* FORE is for the selected item */ + init_pair(MAIN_MENU_FORE, -1, -1); + /* BACK for all the rest */ + init_pair(MAIN_MENU_BACK, -1, -1); + init_pair(MAIN_MENU_GREY, -1, -1); + init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1); + init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1); + + init_pair(SCROLLWIN_TEXT, -1, -1); + init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1); + init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1); + + init_pair(DIALOG_TEXT, -1, -1); + init_pair(DIALOG_BOX, COLOR_YELLOW, -1); + init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1); + init_pair(DIALOG_MENU_FORE, COLOR_RED, -1); + + init_pair(INPUT_BOX, COLOR_YELLOW, -1); + init_pair(INPUT_HEADING, COLOR_GREEN, -1); + init_pair(INPUT_TEXT, -1, -1); + init_pair(INPUT_FIELD, -1, -1); + + init_pair(FUNCTION_HIGHLIGHT, -1, -1); + init_pair(FUNCTION_TEXT, COLOR_BLUE, -1); +} + +/* available attributes: + A_NORMAL Normal display (no highlight) + A_STANDOUT Best highlighting mode of the terminal. + A_UNDERLINE Underlining + A_REVERSE Reverse video + A_BLINK Blinking + A_DIM Half bright + A_BOLD Extra bright or bold + A_PROTECT Protected mode + A_INVIS Invisible or blank mode + A_ALTCHARSET Alternate character set + A_CHARTEXT Bit-mask to extract a character + COLOR_PAIR(n) Color-pair number n + */ +void normal_color_theme(void) +{ + /* automatically add color... */ +#define mkattr(name, attr) do { \ +attributes[name] = attr | COLOR_PAIR(name); } while (0) + mkattr(NORMAL, NORMAL); + mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE); + + mkattr(MAIN_MENU_FORE, A_REVERSE); + mkattr(MAIN_MENU_BACK, A_NORMAL); + mkattr(MAIN_MENU_GREY, A_NORMAL); + mkattr(MAIN_MENU_HEADING, A_BOLD); + mkattr(MAIN_MENU_BOX, A_NORMAL); + + mkattr(SCROLLWIN_TEXT, A_NORMAL); + mkattr(SCROLLWIN_HEADING, A_BOLD); + mkattr(SCROLLWIN_BOX, A_BOLD); + + mkattr(DIALOG_TEXT, A_BOLD); + mkattr(DIALOG_BOX, A_BOLD); + mkattr(DIALOG_MENU_FORE, A_STANDOUT); + mkattr(DIALOG_MENU_BACK, A_NORMAL); + + mkattr(INPUT_BOX, A_NORMAL); + mkattr(INPUT_HEADING, A_BOLD); + mkattr(INPUT_TEXT, A_NORMAL); + mkattr(INPUT_FIELD, A_UNDERLINE); + + mkattr(FUNCTION_HIGHLIGHT, A_BOLD); + mkattr(FUNCTION_TEXT, A_REVERSE); +} + +void no_colors_theme(void) +{ + /* automatically add highlight, no color */ +#define mkattrn(name, attr) { attributes[name] = attr; } + + mkattrn(NORMAL, NORMAL); + mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE); + + mkattrn(MAIN_MENU_FORE, A_STANDOUT); + mkattrn(MAIN_MENU_BACK, A_NORMAL); + mkattrn(MAIN_MENU_GREY, A_NORMAL); + mkattrn(MAIN_MENU_HEADING, A_BOLD); + mkattrn(MAIN_MENU_BOX, A_NORMAL); + + mkattrn(SCROLLWIN_TEXT, A_NORMAL); + mkattrn(SCROLLWIN_HEADING, A_BOLD); + mkattrn(SCROLLWIN_BOX, A_BOLD); + + mkattrn(DIALOG_TEXT, A_NORMAL); + mkattrn(DIALOG_BOX, A_BOLD); + mkattrn(DIALOG_MENU_FORE, A_STANDOUT); + mkattrn(DIALOG_MENU_BACK, A_NORMAL); + + mkattrn(INPUT_BOX, A_BOLD); + mkattrn(INPUT_HEADING, A_BOLD); + mkattrn(INPUT_TEXT, A_NORMAL); + mkattrn(INPUT_FIELD, A_UNDERLINE); + + mkattrn(FUNCTION_HIGHLIGHT, A_BOLD); + mkattrn(FUNCTION_TEXT, A_REVERSE); +} + +void set_colors() +{ + start_color(); + use_default_colors(); + set_normal_colors(); + if (has_colors()) { + normal_color_theme(); + } else { + /* give deafults */ + no_colors_theme(); + } +} + + +/* this changes the windows attributes !!! */ +void print_in_middle(WINDOW *win, + int starty, + int startx, + int width, + const char *string, + chtype color) +{ int length, x, y; + float temp; + + + if (win == NULL) + win = stdscr; + getyx(win, y, x); + if (startx != 0) + x = startx; + if (starty != 0) + y = starty; + if (width == 0) + width = 80; + + length = strlen(string); + temp = (width - length) / 2; + x = startx + (int)temp; + wattrset(win, color); + mvwprintw(win, y, x, "%s", string); + refresh(); +} + +int get_line_no(const char *text) +{ + int i; + int total = 1; + + if (!text) + return 0; + + for (i = 0; text[i] != '\0'; i++) + if (text[i] == '\n') + total++; + return total; +} + +const char *get_line(const char *text, int line_no) +{ + int i; + int lines = 0; + + if (!text) + return 0; + + for (i = 0; text[i] != '\0' && lines < line_no; i++) + if (text[i] == '\n') + lines++; + return text+i; +} + +int get_line_length(const char *line) +{ + int res = 0; + while (*line != '\0' && *line != '\n') { + line++; + res++; + } + return res; +} + +/* print all lines to the window. */ +void fill_window(WINDOW *win, const char *text) +{ + int x, y; + int total_lines = get_line_no(text); + int i; + + getmaxyx(win, y, x); + /* do not go over end of line */ + total_lines = min(total_lines, y); + for (i = 0; i < total_lines; i++) { + char tmp[x+10]; + const char *line = get_line(text, i); + int len = get_line_length(line); + strncpy(tmp, line, min(len, x)); + tmp[len] = '\0'; + mvwprintw(win, i, 0, tmp); + } +} + +/* get the message, and buttons. + * each button must be a char* + * return the selected button + * + * this dialog is used for 2 different things: + * 1) show a text box, no buttons. + * 2) show a dialog, with horizontal buttons + */ +int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...) +{ + va_list ap; + char *btn; + int btns_width = 0; + int msg_lines = 0; + int msg_width = 0; + int total_width; + int win_rows = 0; + WINDOW *win; + WINDOW *msg_win; + WINDOW *menu_win; + MENU *menu; + ITEM *btns[btn_num+1]; + int i, x, y; + int res = -1; + + + va_start(ap, btn_num); + for (i = 0; i < btn_num; i++) { + btn = va_arg(ap, char *); + btns[i] = new_item(btn, ""); + btns_width += strlen(btn)+1; + } + va_end(ap); + btns[btn_num] = NULL; + + /* find the widest line of msg: */ + msg_lines = get_line_no(msg); + for (i = 0; i < msg_lines; i++) { + const char *line = get_line(msg, i); + int len = get_line_length(line); + if (msg_width < len) + msg_width = len; + } + + total_width = max(msg_width, btns_width); + /* place dialog in middle of screen */ + y = (LINES-(msg_lines+4))/2; + x = (COLS-(total_width+4))/2; + + + /* create the windows */ + if (btn_num > 0) + win_rows = msg_lines+4; + else + win_rows = msg_lines+2; + + win = newwin(win_rows, total_width+4, y, x); + keypad(win, TRUE); + menu_win = derwin(win, 1, btns_width, win_rows-2, + 1+(total_width+2-btns_width)/2); + menu = new_menu(btns); + msg_win = derwin(win, win_rows-2, msg_width, 1, + 1+(total_width+2-msg_width)/2); + + set_menu_fore(menu, attributes[DIALOG_MENU_FORE]); + set_menu_back(menu, attributes[DIALOG_MENU_BACK]); + + wattrset(win, attributes[DIALOG_BOX]); + box(win, 0, 0); + + /* print message */ + wattrset(msg_win, attributes[DIALOG_TEXT]); + fill_window(msg_win, msg); + + set_menu_win(menu, win); + set_menu_sub(menu, menu_win); + set_menu_format(menu, 1, btn_num); + menu_opts_off(menu, O_SHOWDESC); + menu_opts_off(menu, O_SHOWMATCH); + menu_opts_on(menu, O_ONEVALUE); + menu_opts_on(menu, O_NONCYCLIC); + set_menu_mark(menu, ""); + post_menu(menu); + + + touchwin(win); + refresh_all_windows(main_window); + while ((res = wgetch(win))) { + switch (res) { + case KEY_LEFT: + menu_driver(menu, REQ_LEFT_ITEM); + break; + case KEY_RIGHT: + menu_driver(menu, REQ_RIGHT_ITEM); + break; + case 10: /* ENTER */ + case 27: /* ESCAPE */ + case ' ': + case KEY_F(F_BACK): + case KEY_F(F_EXIT): + break; + } + touchwin(win); + refresh_all_windows(main_window); + + if (res == 10 || res == ' ') { + res = item_index(current_item(menu)); + break; + } else if (res == 27 || res == KEY_F(F_BACK) || + res == KEY_F(F_EXIT)) { + res = KEY_EXIT; + break; + } + } + + unpost_menu(menu); + free_menu(menu); + for (i = 0; i < btn_num; i++) + free_item(btns[i]); + + delwin(win); + return res; +} + +int dialog_inputbox(WINDOW *main_window, + const char *title, const char *prompt, + const char *init, char *result, int result_len) +{ + int prompt_lines = 0; + int prompt_width = 0; + WINDOW *win; + WINDOW *prompt_win; + WINDOW *form_win; + PANEL *panel; + int i, x, y; + int res = -1; + int cursor_position = strlen(init); + + + /* find the widest line of msg: */ + prompt_lines = get_line_no(prompt); + for (i = 0; i < prompt_lines; i++) { + const char *line = get_line(prompt, i); + int len = get_line_length(line); + prompt_width = max(prompt_width, len); + } + + if (title) + prompt_width = max(prompt_width, strlen(title)); + + /* place dialog in middle of screen */ + y = (LINES-(prompt_lines+4))/2; + x = (COLS-(prompt_width+4))/2; + + strncpy(result, init, result_len); + + /* create the windows */ + win = newwin(prompt_lines+6, prompt_width+7, y, x); + prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2); + form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2); + keypad(form_win, TRUE); + + wattrset(form_win, attributes[INPUT_FIELD]); + + wattrset(win, attributes[INPUT_BOX]); + box(win, 0, 0); + wattrset(win, attributes[INPUT_HEADING]); + if (title) + mvwprintw(win, 0, 3, "%s", title); + + /* print message */ + wattrset(prompt_win, attributes[INPUT_TEXT]); + fill_window(prompt_win, prompt); + + mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); + mvwprintw(form_win, 0, 0, "%s", result); + + /* create panels */ + panel = new_panel(win); + + /* show the cursor */ + curs_set(1); + + touchwin(win); + refresh_all_windows(main_window); + while ((res = wgetch(form_win))) { + int len = strlen(result); + switch (res) { + case 10: /* ENTER */ + case 27: /* ESCAPE */ + case KEY_F(F_HELP): + case KEY_F(F_EXIT): + case KEY_F(F_BACK): + break; + case 127: + case KEY_BACKSPACE: + if (cursor_position > 0) { + memmove(&result[cursor_position-1], + &result[cursor_position], + len-cursor_position+1); + cursor_position--; + } + break; + case KEY_DC: + if (cursor_position >= 0 && cursor_position < len) { + memmove(&result[cursor_position], + &result[cursor_position+1], + len-cursor_position+1); + } + break; + case KEY_UP: + case KEY_RIGHT: + if (cursor_position < len && + cursor_position < min(result_len, prompt_width)) + cursor_position++; + break; + case KEY_DOWN: + case KEY_LEFT: + if (cursor_position > 0) + cursor_position--; + break; + default: + if ((isgraph(res) || isspace(res)) && + len-2 < result_len) { + /* insert the char at the proper position */ + memmove(&result[cursor_position+1], + &result[cursor_position], + len+1); + result[cursor_position] = res; + cursor_position++; + } else { + mvprintw(0, 0, "unknow key: %d\n", res); + } + break; + } + wmove(form_win, 0, 0); + wclrtoeol(form_win); + mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); + mvwprintw(form_win, 0, 0, "%s", result); + wmove(form_win, 0, cursor_position); + touchwin(win); + refresh_all_windows(main_window); + + if (res == 10) { + res = 0; + break; + } else if (res == 27 || res == KEY_F(F_BACK) || + res == KEY_F(F_EXIT)) { + res = KEY_EXIT; + break; + } else if (res == KEY_F(F_HELP)) { + res = 1; + break; + } + } + + /* hide the cursor */ + curs_set(0); + del_panel(panel); + delwin(prompt_win); + delwin(form_win); + delwin(win); + return res; +} + +/* refresh all windows in the correct order */ +void refresh_all_windows(WINDOW *main_window) +{ + update_panels(); + touchwin(main_window); + refresh(); +} + +/* layman's scrollable window... */ +void show_scroll_win(WINDOW *main_window, + const char *title, + const char *text) +{ + int res; + int total_lines = get_line_no(text); + int x, y; + int start_x = 0, start_y = 0; + int text_lines = 0, text_cols = 0; + int total_cols = 0; + int win_cols = 0; + int win_lines = 0; + int i = 0; + WINDOW *win; + WINDOW *pad; + PANEL *panel; + + /* find the widest line of msg: */ + total_lines = get_line_no(text); + for (i = 0; i < total_lines; i++) { + const char *line = get_line(text, i); + int len = get_line_length(line); + total_cols = max(total_cols, len+2); + } + + /* create the pad */ + pad = newpad(total_lines+10, total_cols+10); + wattrset(pad, attributes[SCROLLWIN_TEXT]); + fill_window(pad, text); + + win_lines = min(total_lines+4, LINES-2); + win_cols = min(total_cols+2, COLS-2); + text_lines = max(win_lines-4, 0); + text_cols = max(win_cols-2, 0); + + /* place window in middle of screen */ + y = (LINES-win_lines)/2; + x = (COLS-win_cols)/2; + + win = newwin(win_lines, win_cols, y, x); + keypad(win, TRUE); + /* show the help in the help window, and show the help panel */ + wattrset(win, attributes[SCROLLWIN_BOX]); + box(win, 0, 0); + wattrset(win, attributes[SCROLLWIN_HEADING]); + mvwprintw(win, 0, 3, " %s ", title); + panel = new_panel(win); + + /* handle scrolling */ + do { + + copywin(pad, win, start_y, start_x, 2, 2, text_lines, + text_cols, 0); + print_in_middle(win, + text_lines+2, + 0, + text_cols, + "<OK>", + attributes[DIALOG_MENU_FORE]); + wrefresh(win); + + res = wgetch(win); + switch (res) { + case KEY_NPAGE: + case ' ': + start_y += text_lines-2; + break; + case KEY_PPAGE: + start_y -= text_lines+2; + break; + case KEY_HOME: + start_y = 0; + break; + case KEY_END: + start_y = total_lines-text_lines; + break; + case KEY_DOWN: + case 'j': + start_y++; + break; + case KEY_UP: + case 'k': + start_y--; + break; + case KEY_LEFT: + case 'h': + start_x--; + break; + case KEY_RIGHT: + case 'l': + start_x++; + break; + } + if (res == 10 || res == 27 || res == 'q' + || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) { + break; + } + if (start_y < 0) + start_y = 0; + if (start_y >= total_lines-text_lines) + start_y = total_lines-text_lines; + if (start_x < 0) + start_x = 0; + if (start_x >= total_cols-text_cols) + start_x = total_cols-text_cols; + } while (res); + + del_panel(panel); + delwin(win); + refresh_all_windows(main_window); +} diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h new file mode 100644 index 000000000000..fb4296666004 --- /dev/null +++ b/scripts/kconfig/nconf.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com? + * Released under the terms of the GNU GPL v2.0. + * + * Derived from menuconfig. + * + */ + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <locale.h> +#include <curses.h> +#include <menu.h> +#include <panel.h> +#include <form.h> + +#include <stdio.h> +#include <time.h> +#include <sys/time.h> + +#include "ncurses.h" + +#define max(a, b) ({\ + typeof(a) _a = a;\ + typeof(b) _b = b;\ + _a > _b ? _a : _b; }) + +#define min(a, b) ({\ + typeof(a) _a = a;\ + typeof(b) _b = b;\ + _a < _b ? _a : _b; }) + +typedef enum { + NORMAL = 1, + MAIN_HEADING, + MAIN_MENU_BOX, + MAIN_MENU_FORE, + MAIN_MENU_BACK, + MAIN_MENU_GREY, + MAIN_MENU_HEADING, + SCROLLWIN_TEXT, + SCROLLWIN_HEADING, + SCROLLWIN_BOX, + DIALOG_TEXT, + DIALOG_MENU_FORE, + DIALOG_MENU_BACK, + DIALOG_BOX, + INPUT_BOX, + INPUT_HEADING, + INPUT_TEXT, + INPUT_FIELD, + FUNCTION_TEXT, + FUNCTION_HIGHLIGHT, + ATTR_MAX +} attributes_t; +extern attributes_t attributes[]; + +typedef enum { + F_HELP = 1, + F_SYMBOL = 2, + F_INSTS = 3, + F_CONF = 4, + F_BACK = 5, + F_SAVE = 6, + F_LOAD = 7, + F_EXIT = 8 +} function_key; + +void set_colors(void); + +/* this changes the windows attributes !!! */ +void print_in_middle(WINDOW *win, + int starty, + int startx, + int width, + const char *string, + chtype color); +int get_line_length(const char *line); +int get_line_no(const char *text); +const char *get_line(const char *text, int line_no); +void fill_window(WINDOW *win, const char *text); +int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...); +int dialog_inputbox(WINDOW *main_window, + const char *title, const char *prompt, + const char *init, char *result, int result_len); +void refresh_all_windows(WINDOW *main_window); +void show_scroll_win(WINDOW *main_window, + const char *title, + const char *text); diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped index 6e9dcd59aa87..8a0867a32b0f 100644 --- a/scripts/kconfig/zconf.tab.c_shipped +++ b/scripts/kconfig/zconf.tab.c_shipped @@ -2220,7 +2220,7 @@ void conf_parse(const char *name) zconf_initscan(name); sym_init(); - menu_init(); + _menu_init(); modules_sym = sym_lookup(NULL, 0); modules_sym->type = S_BOOLEAN; modules_sym->flags |= SYMBOL_AUTO; diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index 8c43491f8cc9..361b54318c8d 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -475,7 +475,7 @@ void conf_parse(const char *name) zconf_initscan(name); sym_init(); - menu_init(); + _menu_init(); modules_sym = sym_lookup(NULL, 0); modules_sym->type = S_BOOLEAN; modules_sym->flags |= SYMBOL_AUTO; -- GitLab From 851190c9304154b7d65596801415229c05994e91 Mon Sep 17 00:00:00 2001 From: Michal Marek <mmarek@suse.cz> Date: Thu, 7 Jan 2010 13:59:57 +0100 Subject: [PATCH 014/842] nconfig: mark local functions as such scripts/kconfig/nconf.gui.c:23: warning: no previous prototype for 'set_normal_colors' scripts/kconfig/nconf.gui.c:68: warning: no previous prototype for 'normal_color_theme' scripts/kconfig/nconf.gui.c:100: warning: no previous prototype for 'no_colors_theme' scripts/kconfig/nconf.c:455: warning: no previous prototype for 'process_special_keys' scripts/kconfig/nconf.c:487: warning: no previous prototype for 'get_next_hot' scripts/kconfig/nconf.c:506: warning: no previous prototype for 'canbhot' scripts/kconfig/nconf.c:514: warning: no previous prototype for 'is_hot' scripts/kconfig/nconf.c:522: warning: no previous prototype for 'make_hot' scripts/kconfig/nconf.c:582: warning: no previous prototype for 'item_make' scripts/kconfig/nconf.c:626: warning: no previous prototype for 'item_add_str' scripts/kconfig/nconf.c:656: warning: no previous prototype for 'item_tag' scripts/kconfig/nconf.c:668: warning: no previous prototype for 'curses_item_index' scripts/kconfig/nconf.c:673: warning: no previous prototype for 'item_data' scripts/kconfig/nconf.c:684: warning: no previous prototype for 'item_is_tag' scripts/kconfig/nconf.c:691: warning: no previous prototype for 'set_config_filename' Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/nconf.c | 24 ++++++++++++------------ scripts/kconfig/nconf.gui.c | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 8c56150a757d..fb54c98874bc 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -452,7 +452,7 @@ static void handle_f8(int *key, struct menu *current_item) } /* return != 0 to indicate the key was handles */ -int process_special_keys(int *key, struct menu *menu) +static int process_special_keys(int *key, struct menu *menu) { int i; @@ -484,7 +484,7 @@ static void clean_items(void) } /* return the index of the next hot item, or -1 if no such item exists */ -int get_next_hot(int c) +static int get_next_hot(int c) { static int hot_index; static int hot_char; @@ -503,7 +503,7 @@ int get_next_hot(int c) } /* can the char c be a hot key? no, if c is a common shortcut used elsewhere */ -int canbhot(char c) +static int canbhot(char c) { c = tolower(c); return isalnum(c) && c != 'y' && c != 'm' && c != 'h' && @@ -511,7 +511,7 @@ int canbhot(char c) } /* check if str already contains a hot key. */ -int is_hot(int index) +static int is_hot(int index) { return k_menu_items[index].is_hot; } @@ -519,7 +519,7 @@ int is_hot(int index) /* find the first possible hot key, and mark it. * index is the index of the item in the menu * return 0 on success*/ -int make_hot(char *dest, int len, const char *org, int index) +static int make_hot(char *dest, int len, const char *org, int index) { int position = -1; int i; @@ -579,7 +579,7 @@ int make_hot(char *dest, int len, const char *org, int index) /* Make a new item. Add a hotkey mark in the first possible letter. * As ncurses does not allow any attributes inside menue item, we mark the * hot key as the first capitalized letter in the string */ -void item_make(struct menu *menu, char tag, const char *fmt, ...) +static void item_make(struct menu *menu, char tag, const char *fmt, ...) { va_list ap; char tmp_str[256]; @@ -623,7 +623,7 @@ void item_make(struct menu *menu, char tag, const char *fmt, ...) } /* very hackish. adds a string to the last item added */ -void item_add_str(const char *fmt, ...) +static void item_add_str(const char *fmt, ...) { va_list ap; int index = items_num-1; @@ -653,7 +653,7 @@ void item_add_str(const char *fmt, ...) } /* get the tag of the currently selected item */ -char item_tag(void) +static char item_tag(void) { ITEM *cur; struct mitem *mcur; @@ -665,12 +665,12 @@ char item_tag(void) return mcur->tag; } -int curses_item_index(void) +static int curses_item_index(void) { return item_index(current_item(curses_menu)); } -void *item_data(void) +static void *item_data(void) { ITEM *cur; struct mitem *mcur; @@ -681,14 +681,14 @@ void *item_data(void) } -int item_is_tag(char tag) +static int item_is_tag(char tag) { return item_tag() == tag; } static char filename[PATH_MAX+1]; static char menu_backtitle[PATH_MAX+128]; -const char *set_config_filename(const char *config_filename) +static const char *set_config_filename(const char *config_filename) { int size; struct symbol *sym; diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index 879ade6dd604..115edb437fb1 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -20,7 +20,7 @@ attributes_t attributes[ATTR_MAX+1] = {0}; COLOR_CYAN 6 COLOR_WHITE 7 */ -void set_normal_colors(void) +static void set_normal_colors(void) { init_pair(NORMAL, -1, -1); init_pair(MAIN_HEADING, COLOR_MAGENTA, -1); @@ -65,7 +65,7 @@ void set_normal_colors(void) A_CHARTEXT Bit-mask to extract a character COLOR_PAIR(n) Color-pair number n */ -void normal_color_theme(void) +static void normal_color_theme(void) { /* automatically add color... */ #define mkattr(name, attr) do { \ @@ -97,7 +97,7 @@ attributes[name] = attr | COLOR_PAIR(name); } while (0) mkattr(FUNCTION_TEXT, A_REVERSE); } -void no_colors_theme(void) +static void no_colors_theme(void) { /* automatically add highlight, no color */ #define mkattrn(name, attr) { attributes[name] = attr; } -- GitLab From 68c16edddf41044410fab59d4c179c023cb25afb Mon Sep 17 00:00:00 2001 From: Nir Tzachar <nir.tzachar@gmail.com> Date: Wed, 13 Jan 2010 07:32:35 +0200 Subject: [PATCH 015/842] nconfig: minor fix This patch fixes two problems reported by Jan Engelhardt: 1) Border is now properly placed, to always be visible 2) Long menu items are properly displayed Reported-by: Jan Engelhardt <jengelh@medozas.de> Signed-off-by: Nir Tzachar <nir.tzachar@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/nconf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index fb54c98874bc..762caf80ce37 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -984,7 +984,7 @@ static void build_conf(struct menu *menu) break; default: tmp = 2 + strlen(sym_get_string_value(sym)); - item_make(menu, 's', "(%s)", + item_make(menu, 's', " (%s)", sym_get_string_value(sym)); tmp = indent - tmp + 4; if (tmp < 0) @@ -1072,8 +1072,8 @@ static void show_menu(const char *prompt, const char *instructions, /* position the menu at the middle of the screen */ scale_menu(curses_menu, &maxy, &maxx); - maxx = min(maxx, mwin_max_cols); - maxy = mwin_max_lines-1; + maxx = min(maxx, mwin_max_cols-2); + maxy = mwin_max_lines-2; menu_window = derwin(main_window, maxy, maxx, -- GitLab From 85a256d8e0116c8f5ad276730830f5d4d473344d Mon Sep 17 00:00:00 2001 From: David Rientjes <rientjes@google.com> Date: Wed, 13 Jan 2010 13:01:05 -0800 Subject: [PATCH 016/842] kbuild: improve version string logic The LOCALVERSION= string passed to "make" will now always be appended to the kernel version after CONFIG_LOCALVERSION, if it exists, regardless of whether CONFIG_LOCALVERSION_AUTO is set or not. This allows users to uniquely identify their kernel builds with a string. If CONFIG_LOCALVERSION_AUTO is enabled, the unique SCM tag reported by setlocalversion (or .scmversion) is appended to the kernel version, if it exists. When CONFIG_LOCALVERSION_AUTO is not enabled, a `+' is appended to the kernel version to represent that the kernel has been revised since the last release unless "make LOCALVERSION=" was used to uniquely identify the build. The end result is this: - when LOCALVERSION= is passed to "make", it is appended to the kernel version, - when CONFIG_LOCALVERSION_AUTO is enabled, a unique SCM identifier is appended if the respository has been revised beyond a tagged commit, and - when CONFIG_LOCALVERSION_AUTO is disabled, a `+' is appended if the repository has been revised beyond a tagged commit and LOCALVERSION= was not passed to "make". Examples: With CONFIG_LOCALVERSION_AUTO: "make" results in v2.6.32-rc4-00149-ga3ccf63. If there are uncommited changes to the respository, it results in v2.6.32-rc4-00149-ga3ccf63-dirty. If "make LOCALVERSION=kbuild" were used, it results in v2.6.32-rc4-kbuild-00149-ga3ccf63-dirty. Without CONFIG_LOCALVERSION_AUTO, "make" results in v2.6.32-rc4+ unless the repository is at the Linux v2.6.32-rc4 commit (in which case the version would be v2.6.32-rc4). If "make LOCALVERSION=kbuild" were used, it results in v2.6.32-rc4-kbuild. Also renames variables such as localver-auto and _localver-auto to more accurately describe what they represent: localver-extra and scm-identifier, respectively. Signed-off-by: David Rientjes <rientjes@google.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Makefile | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index f9dc25cd9b2e..faa320a67bf8 100644 --- a/Makefile +++ b/Makefile @@ -910,14 +910,19 @@ endif # $(localver) # localversion* (files without backups, containing '~') # $(CONFIG_LOCALVERSION) (from kernel config setting) -# $(localver-auto) (only if CONFIG_LOCALVERSION_AUTO is set) -# ./scripts/setlocalversion (SCM tag, if one exists) -# $(LOCALVERSION) (from make command line if provided) +# $(LOCALVERSION) (from make command line, if provided) +# $(localver-extra) +# $(scm-identifier) (unique SCM tag, if one exists) +# ./scripts/setlocalversion (only with CONFIG_LOCALVERSION_AUTO) +# .scmversion (only with CONFIG_LOCALVERSION_AUTO) +# + (only without CONFIG_LOCALVERSION_AUTO +# and without LOCALVERSION= and +# repository is at non-tagged commit) # -# Note how the final $(localver-auto) string is included *only* if the -# kernel config option CONFIG_LOCALVERSION_AUTO is selected. Also, at the -# moment, only git is supported but other SCMs can edit the script -# scripts/setlocalversion and add the appropriate checks as needed. +# For kernels without CONFIG_LOCALVERSION_AUTO compiled from an SCM that has +# been revised beyond a tagged commit, `+' is appended to the version string +# when not overridden by using "make LOCALVERSION=". This indicates that the +# kernel is not a vanilla release version and has been modified. pattern = ".*/localversion[^~]*" string = $(shell cat /dev/null \ @@ -926,26 +931,32 @@ string = $(shell cat /dev/null \ localver = $(subst $(space),, $(string) \ $(patsubst "%",%,$(CONFIG_LOCALVERSION))) -# If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called -# and if the SCM is know a tag from the SCM is appended. -# The appended tag is determined by the SCM used. +# scripts/setlocalversion is called to create a unique identifier if the source +# is managed by a known SCM and the repository has been revised since the last +# tagged (release) commit. The format of the identifier is determined by the +# SCM's implementation. # # .scmversion is used when generating rpm packages so we do not loose # the version information from the SCM when we do the build of the kernel # from the copied source -ifdef CONFIG_LOCALVERSION_AUTO - ifeq ($(wildcard .scmversion),) - _localver-auto = $(shell $(CONFIG_SHELL) \ + scm-identifier = $(shell $(CONFIG_SHELL) \ $(srctree)/scripts/setlocalversion $(srctree)) else - _localver-auto = $(shell cat .scmversion 2> /dev/null) + scm-identifier = $(shell cat .scmversion 2> /dev/null) endif - localver-auto = $(LOCALVERSION)$(_localver-auto) +ifdef CONFIG_LOCALVERSION_AUTO + localver-extra = $(scm-identifier) +else + ifneq ($scm-identifier,) + ifeq ($(LOCALVERSION),) + localver-extra = + + endif + endif endif -localver-full = $(localver)$(localver-auto) +localver-full = $(localver)$(LOCALVERSION)$(localver-extra) # Store (new) KERNELRELASE string in include/config/kernel.release kernelrelease = $(KERNELVERSION)$(localver-full) -- GitLab From 62718979780720e526a411dc66e810288aaa7bf6 Mon Sep 17 00:00:00 2001 From: Joe Perches <joe@perches.com> Date: Wed, 13 Jan 2010 09:31:44 -0800 Subject: [PATCH 017/842] Makefile: Document ability to make file.lst and file.S Signed-off-by: Joe Perches <joe@perches.com> Acked-by: WANG Cong <xiyou.wangcong@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index faa320a67bf8..03053c66bb3a 100644 --- a/Makefile +++ b/Makefile @@ -1261,7 +1261,9 @@ help: @echo ' firmware_install- Install all firmware to INSTALL_FW_PATH' @echo ' (default: $$(INSTALL_MOD_PATH)/lib/firmware)' @echo ' dir/ - Build all files in dir and below' - @echo ' dir/file.[ois] - Build specified target only' + @echo ' dir/file.[oisS] - Build specified target only' + @echo ' dir/file.lst - Build specified mixed source/assembly target only' + @echo ' (requires a recent binutils and recent build (System.map))' @echo ' dir/file.ko - Build module including final link' @echo ' modules_prepare - Set up for building external modules' @echo ' tags/TAGS - Generate tags file for editors' -- GitLab From e66f25d7d1be19e177cf55126a40799757efae89 Mon Sep 17 00:00:00 2001 From: Andi Kleen <andi@firstfloor.org> Date: Wed, 13 Jan 2010 17:02:44 +0100 Subject: [PATCH 018/842] Improve kconfig symbol hashing While looking for something else I noticed that the symbol hash function used by kconfig is quite poor. It doesn't use any of the standard hash techniques but simply adds up the string and then uses power of two masking, which is both known to perform poorly. The current x86 kconfig has over 7000 symbols. When I instrumented it showed that the minimum hash chain length was 16 and a significant number of them was over 30. It didn't help that the hash table size was only 256 buckets. This patch increases the hash table size to a larger prime and switches to a FNV32 hash. I played around with a couple of hash functions, but that one seemed to perform best with reasonable hash table sizes. Increasing the hash table size even further didn't seem like a good idea, because there are a couple of global walks which walk the complete hash table. I also moved the unnamed bucket to 0. It's still the longest of all the buckets (44 entries), but hopefully it's not often hit except for the global walk which doesn't care. The result is a much nicer distribution: (first column bucket length, second number of buckets with that length) 1: 3505 2: 1236 3: 294 4: 52 5: 3 47: 1 <--- this is the unnamed symbols bucket There are still some 5+ buckets, but increasing the hash table even more would be likely not worth it. This also cleans up the code slightly by removing hard coded magic numbers. I didn't notice a big performance difference either way on my Nehalem system, but I presume it'll help somewhat on slower systems. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/expr.h | 5 ++--- scripts/kconfig/symbol.c | 29 +++++++++++++++++------------ scripts/kconfig/zconf.tab.c_shipped | 2 +- scripts/kconfig/zconf.y | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 6408fefae083..891cd9ce9ba2 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -86,7 +86,7 @@ struct symbol { struct expr_value rev_dep; }; -#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) +#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) #define SYMBOL_CONST 0x0001 /* symbol is const */ #define SYMBOL_CHECK 0x0008 /* used during dependency checking */ @@ -108,8 +108,7 @@ struct symbol { #define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ #define SYMBOL_MAXLENGTH 256 -#define SYMBOL_HASHSIZE 257 -#define SYMBOL_HASHMASK 0xff +#define SYMBOL_HASHSIZE 9973 /* A property represent the config options that can be associated * with a config "symbol". diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 6c8fbbb66ebc..9ee3923117ee 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -651,12 +651,20 @@ bool sym_is_changable(struct symbol *sym) return sym->visible > sym->rev_dep.tri; } +static unsigned strhash(const char *s) +{ + /* fnv32 hash */ + unsigned hash = 2166136261U; + for (; *s; s++) + hash = (hash ^ *s) * 0x01000193; + return hash; +} + struct symbol *sym_lookup(const char *name, int flags) { struct symbol *symbol; - const char *ptr; char *new_name; - int hash = 0; + int hash; if (name) { if (name[0] && !name[1]) { @@ -666,12 +674,11 @@ struct symbol *sym_lookup(const char *name, int flags) case 'n': return &symbol_no; } } - for (ptr = name; *ptr; ptr++) - hash += *ptr; - hash &= 0xff; + hash = strhash(name) % SYMBOL_HASHSIZE; for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { - if (!strcmp(symbol->name, name) && + if (symbol->name && + !strcmp(symbol->name, name) && (flags ? symbol->flags & flags : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) return symbol; @@ -679,7 +686,7 @@ struct symbol *sym_lookup(const char *name, int flags) new_name = strdup(name); } else { new_name = NULL; - hash = 256; + hash = 0; } symbol = malloc(sizeof(*symbol)); @@ -697,7 +704,6 @@ struct symbol *sym_lookup(const char *name, int flags) struct symbol *sym_find(const char *name) { struct symbol *symbol = NULL; - const char *ptr; int hash = 0; if (!name) @@ -710,12 +716,11 @@ struct symbol *sym_find(const char *name) case 'n': return &symbol_no; } } - for (ptr = name; *ptr; ptr++) - hash += *ptr; - hash &= 0xff; + hash = strhash(name) % SYMBOL_HASHSIZE; for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { - if (!strcmp(symbol->name, name) && + if (symbol->name && + !strcmp(symbol->name, name) && !(symbol->flags & SYMBOL_CONST)) break; } diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped index 8a0867a32b0f..7df3264c3f3d 100644 --- a/scripts/kconfig/zconf.tab.c_shipped +++ b/scripts/kconfig/zconf.tab.c_shipped @@ -104,7 +104,7 @@ static void zconf_error(const char *err, ...); static void zconferror(const char *err); static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); -struct symbol *symbol_hash[257]; +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; static struct menu *current_menu, *current_entry; diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index 361b54318c8d..258f16608ec0 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -27,7 +27,7 @@ static void zconf_error(const char *err, ...); static void zconferror(const char *err); static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); -struct symbol *symbol_hash[257]; +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; static struct menu *current_menu, *current_entry; -- GitLab From d4987bd7ae8401bd88896a6f76dc7af31fe55732 Mon Sep 17 00:00:00 2001 From: Michal Marek <mmarek@suse.cz> Date: Wed, 27 Jan 2010 09:46:23 +0100 Subject: [PATCH 019/842] scripts/mkcompile_h: don't test for hardcoded paths Don't test for /bin/{dnsdomainname,domainname}, simply try to execute the command and check if it returned something. Reported-by: Glenn Sommer <glemsom@gmail.com> Acked-by: WANG Cong <xiyou.wangcong@gmail.com> Tested-by: Glenn Sommer <glemsom@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/mkcompile_h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index 23dbad80cce9..50ad317a4bf9 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -67,9 +67,8 @@ UTS_TRUNCATE="cut -b -$UTS_LEN" echo \#define LINUX_COMPILE_BY \"`whoami`\" echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\" - if [ -x /bin/dnsdomainname ]; then - domain=`dnsdomainname 2> /dev/null` - elif [ -x /bin/domainname ]; then + domain=`dnsdomainname 2> /dev/null` + if [ -z "$domain" ]; then domain=`domainname 2> /dev/null` fi -- GitLab From 71d41aed9468a1239cff1b2d928954885b09de6c Mon Sep 17 00:00:00 2001 From: Himanshu Chauhan <hschauhan@nulltrace.org> Date: Wed, 27 Jan 2010 16:53:20 -0800 Subject: [PATCH 020/842] scripts/kallsyms: suppress build warning Suppress a warn_unused_result warning. fgets is called as a part of error handling. It is called just to drop a line and return immediately. read_map is reading the file in a loop and read_symbol reads line by line. So I think there is no point in using return value for useful checking. Other checks like 3 items were returned or !EOF have already been done. Signed-off-by: Himanshu Chauhan <hschauhan@nulltrace.org> Cc: WANG Cong <xiyou.wangcong@gmail.com> Cc: Michal Marek <mmarek@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kallsyms.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 86c3896a1e01..e3902fb39afd 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -108,8 +108,10 @@ static int read_symbol(FILE *in, struct sym_entry *s) rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str); if (rc != 3) { if (rc != EOF) { - /* skip line */ - fgets(str, 500, in); + /* skip line. sym is used as dummy to + * shut of "warn_unused_result" warning. + */ + sym = fgets(str, 500, in); } return -1; } -- GitLab From 94a47083522ec4bcfc03134ebe908f1bfb393057 Mon Sep 17 00:00:00 2001 From: Don Zickus <dzickus@redhat.com> Date: Tue, 26 Jan 2010 22:20:41 +0000 Subject: [PATCH 021/842] scripts: change scripts to use system python instead of env Just a small change to a couple of scripts to go from #!/usr/bin/env python to #!/usr/bin/python This shouldn't effect anyone, unless they don't install python there. In preparation for python3, Fedora is doing a big push to change the scripts to use the system python. This allows developers to put the python3 in their path without fear of breaking existing scripts. Now I am pretty sure anyone using python3 for testing purposes will probably not run any of the scripts I changed, but Fedora has this automated tool that checks for this stuff so I thought I would try to push it upstream. Signed-off-by: Don Zickus <dzickus@redhat.com> Acked-by: WANG Cong <xiyou.wangcong@gmail.com> Acked-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/ia64/scripts/unwcheck.py | 2 +- scripts/rt-tester/rt-tester.py | 2 +- scripts/show_delta | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ia64/scripts/unwcheck.py b/arch/ia64/scripts/unwcheck.py index c27849889e19..2bfd941ff7c7 100644 --- a/arch/ia64/scripts/unwcheck.py +++ b/arch/ia64/scripts/unwcheck.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python # # Usage: unwcheck.py FILE # diff --git a/scripts/rt-tester/rt-tester.py b/scripts/rt-tester/rt-tester.py index 4c79660793cf..44423b4dcb82 100644 --- a/scripts/rt-tester/rt-tester.py +++ b/scripts/rt-tester/rt-tester.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python # # rt-mutex tester # diff --git a/scripts/show_delta b/scripts/show_delta index 48a706ab3d0c..17df3051747a 100755 --- a/scripts/show_delta +++ b/scripts/show_delta @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python # # show_deltas: Read list of printk messages instrumented with # time data, and format with time deltas. -- GitLab From 0139f1d9539395ca341e17060ae26f44f5f31434 Mon Sep 17 00:00:00 2001 From: Hui Zhu <hui.zhu@windriver.com> Date: Thu, 28 Jan 2010 06:58:02 +0000 Subject: [PATCH 022/842] markup_oops.pl: fix for faulting instruction in the first line of a range I got a "No matching code found" when I use markup_oops.pl parse a error in a x86_64 module. cat e.c int init_module(void) { char *buf = 0; buf[0] = 3; return 0; } void cleanup_module(void) { //char *buf = 0; //buf[0] = 3; } MODULE_AUTHOR("Hui Zhu"); MODULE_LICENSE("GPL"); 0000000000000000 <init_module>: init_module(): /home/teawater/study/kernel/stack2core/example/e.c:10 0: c6 04 25 00 00 00 00 movb $0x3,0x0 7: 03 /home/teawater/study/kernel/stack2core/example/e.c:13 8: 31 c0 xor %eax,%eax a: c3 retq b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 0000000000000010 <cleanup_module>: cleanup_module(): /home/teawater/study/kernel/stack2core/example/e.c:20 10: f3 c3 repz retq 12: 90 nop 13: 90 nop Disassembly of section .modinfo: This is because the faulting instruction "movb $0x3,0x0" is the first line of the range. In the markup_oops.pl: main::(./scripts/markup_oops.pl:245): 245: if (InRange($1, $target)) { DB<2> p $line ffffffffa001b000: c6 04 25 00 00 00 00 movb $0x3,0x0 DB<3> p $counter 0 It just set $center in next loop. So it cannot get the $center. And even if $center is set to the right value 0. if ($center == 0) { print "No matching code found \n"; exit; } The first line $center will be 0, so I change the default value to -1. Signed-off-by: Hui Zhu <teawater@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/markup_oops.pl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/markup_oops.pl b/scripts/markup_oops.pl index ce3e40b01e48..4a95539c807a 100644 --- a/scripts/markup_oops.pl +++ b/scripts/markup_oops.pl @@ -204,7 +204,7 @@ if ($module ne "") { my $counter = 0; my $state = 0; -my $center = 0; +my $center = -1; my @lines; my @reglines; @@ -236,7 +236,8 @@ while (<FILE>) { $state = 1; } } - } else { + } + if ($state == 1) { if ($line =~ /^([a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]+)\:/) { my $val = $1; if (!InRange($val, $target)) { @@ -259,7 +260,7 @@ if ($counter == 0) { exit; } -if ($center == 0) { +if ($center == -1) { print "No matching code found \n"; exit; } -- GitLab From 880df92fa0bb2ebaf057ea1cc1e309b351fd73bc Mon Sep 17 00:00:00 2001 From: John Saalwaechter <saalwaechter@gmail.com> Date: Sun, 31 Jan 2010 16:18:58 -0800 Subject: [PATCH 023/842] scripts: use %_tmppath in "make rpm-pkg" The mkspec script hardcodes "/var/tmp" into the generated rpm spec file's BuildRoot. The user, however, may have a custom setting for %_tmppath, which should be used in BuildRoot. This patch changes mkspec's BuildRoot output to appropriately use %_tmppath. Signed-off-by: John Saalwaechter <saalwaechter@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/package/mkspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 47bdd2f99b78..16ae0dd746e1 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -39,7 +39,7 @@ if ! $PREBUILT; then echo "Source: kernel-$__KERNELRELEASE.tar.gz" fi -echo "BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root" +echo "BuildRoot: %{_tmppath}/%{name}-%{PACKAGE_VERSION}-root" echo "Provides: $PROVIDES" echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :" echo "%define debug_package %{nil}" -- GitLab From 70fb7ba652e8bdb05aa99ef46e3183684e0742f7 Mon Sep 17 00:00:00 2001 From: Michal Marek <mmarek@suse.cz> Date: Fri, 29 Jan 2010 14:22:43 +0100 Subject: [PATCH 024/842] MAINTAINERS: add a few more patterns to kbuild Also, add a note that "unmaintained" files below scripts/ should go via the kbuild tree (best current practice). Signed-off-by: Michal Marek <mmarek@suse.cz> --- MAINTAINERS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 03f38c18f323..ce3601e5e3c8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3086,7 +3086,7 @@ L: autofs@linux.kernel.org S: Maintained F: fs/autofs4/ -KERNEL BUILD +KERNEL BUILD + files below scripts/ (unless maintained elsewhere) M: Michal Marek <mmarek@suse.cz> T: git git://repo.or.cz/linux-kbuild.git for-next T: git git://repo.or.cz/linux-kbuild.git for-linus @@ -3095,6 +3095,9 @@ S: Maintained F: Documentation/kbuild/ F: Makefile F: scripts/Makefile.* +F: scripts/basic/ +F: scripts/mk* +F: scripts/package/ KERNEL JANITORS L: kernel-janitors@vger.kernel.org -- GitLab From 52e13e219d5930fb8fb774050e6ecffa244a60a9 Mon Sep 17 00:00:00 2001 From: Hui Zhu <hui.zhu@windriver.com> Date: Tue, 26 Jan 2010 17:13:07 +0800 Subject: [PATCH 025/842] markup_oops.pl: add options to improve cross-sompilation environments The markup_oops.pl have 3 troubles to support cross-compiler environment: 1. It use objdump directly. 2. It use modinfo to get the message of module. 3. It use hex function that cannot support 64-bit number in 32-bit arch. This patch add 3 options to markup_oops.pl: 1. -c CROSS_COMPILE Specify the prefix used for toolchain. 2. -m MODULE_DIRNAME Specify the module directory name. 3. Change hex function to Math::BigInt->from_hex. After this patch, parse the x8664 oops in x86, we can: cat amd64m | perl ~/kernel/tmp/m.pl -c /home/teawater/kernel/bin/x8664- -m ./e.ko vmlinux Thanks, Hui Signed-off-by: Hui Zhu <teawater@gmail.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: ozan@pardus.org.tr Cc: Matthew Wilcox <willy@linux.intel.com> Acked-by: WANG Cong <xiyou.wangcong@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/markup_oops.pl | 49 +++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/scripts/markup_oops.pl b/scripts/markup_oops.pl index 4a95539c807a..a7e8e019e03d 100644 --- a/scripts/markup_oops.pl +++ b/scripts/markup_oops.pl @@ -2,6 +2,7 @@ use File::Basename; use Math::BigInt; +use Getopt::Long; # Copyright 2008, Intel Corporation # @@ -15,7 +16,17 @@ use Math::BigInt; # Arjan van de Ven <arjan@linux.intel.com> -my $vmlinux_name = $ARGV[0]; +my $cross_compile = ""; +my $vmlinux_name = ""; +my $modulefile = ""; + +# Get options +Getopt::Long::GetOptions( + 'cross-compile|c=s' => \$cross_compile, + 'module|m=s' => \$modulefile, + 'help|h' => \&usage, +); +my $vmlinux_name = $ARGV[$#ARGV]; if (!defined($vmlinux_name)) { my $kerver = `uname -r`; chomp($kerver); @@ -23,9 +34,8 @@ if (!defined($vmlinux_name)) { print "No vmlinux specified, assuming $vmlinux_name\n"; } my $filename = $vmlinux_name; -# -# Step 1: Parse the oops to find the EIP value -# + +# Parse the oops to find the EIP value my $target = "0"; my $function; @@ -177,26 +187,26 @@ my $decodestart = Math::BigInt->from_hex("0x$target") - Math::BigInt->from_hex(" my $decodestop = Math::BigInt->from_hex("0x$target") + 8192; if ($target eq "0") { print "No oops found!\n"; - print "Usage: \n"; - print " dmesg | perl scripts/markup_oops.pl vmlinux\n"; - exit; + usage(); } # if it's a module, we need to find the .ko file and calculate a load offset if ($module ne "") { - my $modulefile = `modinfo $module | grep '^filename:' | awk '{ print \$2 }'`; - chomp($modulefile); + if ($modulefile eq "") { + my $modulefile = `modinfo $module | grep '^filename:' | awk '{ print \$2 }'`; + chomp($modulefile); + } $filename = $modulefile; if ($filename eq "") { print "Module .ko file for $module not found. Aborting\n"; exit; } # ok so we found the module, now we need to calculate the vma offset - open(FILE, "objdump -dS $filename |") || die "Cannot start objdump"; + open(FILE, $cross_compile."objdump -dS $filename |") || die "Cannot start objdump"; while (<FILE>) { if ($_ =~ /^([0-9a-f]+) \<$function\>\:/) { my $fu = $1; - $vmaoffset = hex($target) - hex($fu) - hex($func_offset); + $vmaoffset = Math::BigInt->from_hex("0x$target") - Math::BigInt->from_hex("0x$fu") - Math::BigInt->from_hex("0x$func_offset"); } } close(FILE); @@ -212,7 +222,7 @@ sub InRange { my ($address, $target) = @_; my $ad = "0x".$address; my $ta = "0x".$target; - my $delta = hex($ad) - hex($ta); + my $delta = Math::BigInt->from_hex($ad) - Math::BigInt->from_hex($ta); if (($delta > -4096) && ($delta < 4096)) { return 1; @@ -225,7 +235,7 @@ sub InRange { # first, parse the input into the lines array, but to keep size down, # we only do this for 4Kb around the sweet spot -open(FILE, "objdump -dS --adjust-vma=$vmaoffset --start-address=$decodestart --stop-address=$decodestop $filename |") || die "Cannot start objdump"; +open(FILE, $cross_compile."objdump -dS --adjust-vma=$vmaoffset --start-address=$decodestart --stop-address=$decodestop $filename |") || die "Cannot start objdump"; while (<FILE>) { my $line = $_; @@ -345,3 +355,16 @@ while ($i < $finish) { $i = $i +1; } +sub usage { + print <<EOT; +Usage: + dmesg | perl $0 [OPTION] [VMLINUX] + +OPTION: + -c, --cross-compile CROSS_COMPILE Specify the prefix used for toolchain. + -m, --module MODULE_DIRNAME Specify the module directory name. + -h, --help Help. +EOT + exit; +} + -- GitLab From 59dde3853e07aaadc2b63abd16c954d5b0606cf1 Mon Sep 17 00:00:00 2001 From: Hui Zhu <hui.zhu@windriver.com> Date: Mon, 1 Feb 2010 13:41:22 +0800 Subject: [PATCH 026/842] markup_oops.pl: minor fixes 1. Fix a little format issue. 2. Check the return of "Getopt::Long::GetOptions". Output usage and exit if it get error. 3. Change $ARGV[$#ARGV] to $ARGV[0]. 4. Change the code which get $modulefile from modinfo. Replace the pipeline with `modinfo -F filename $module`. 4. Change usage from "Specify the module directory name" to "Specify the module filename". Signed-off-by: Hui Zhu <teawater@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/markup_oops.pl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/markup_oops.pl b/scripts/markup_oops.pl index a7e8e019e03d..90e1d9aa35b5 100644 --- a/scripts/markup_oops.pl +++ b/scripts/markup_oops.pl @@ -23,10 +23,10 @@ my $modulefile = ""; # Get options Getopt::Long::GetOptions( 'cross-compile|c=s' => \$cross_compile, - 'module|m=s' => \$modulefile, + 'module|m=s' => \$modulefile, 'help|h' => \&usage, -); -my $vmlinux_name = $ARGV[$#ARGV]; +) || usage (); +my $vmlinux_name = $ARGV[0]; if (!defined($vmlinux_name)) { my $kerver = `uname -r`; chomp($kerver); @@ -193,7 +193,7 @@ if ($target eq "0") { # if it's a module, we need to find the .ko file and calculate a load offset if ($module ne "") { if ($modulefile eq "") { - my $modulefile = `modinfo $module | grep '^filename:' | awk '{ print \$2 }'`; + $modulefile = `modinfo -F filename $module`; chomp($modulefile); } $filename = $modulefile; @@ -362,7 +362,7 @@ Usage: OPTION: -c, --cross-compile CROSS_COMPILE Specify the prefix used for toolchain. - -m, --module MODULE_DIRNAME Specify the module directory name. + -m, --module MODULE_DIRNAME Specify the module filename. -h, --help Help. EOT exit; -- GitLab From d0679c730395d0bde9a46939e7ba255b4ba7dd7c Mon Sep 17 00:00:00 2001 From: Andi Kleen <andi@firstfloor.org> Date: Tue, 2 Feb 2010 14:40:02 -0800 Subject: [PATCH 027/842] kbuild: move -fno-dwarf2-cfi-asm to powerpc only Better dwarf2 unwind information is a good thing, it allows better debugging with kgdb and crash and helps systemtap. Commit 003086497f07f7f1e67c0c295e261740f822b377 ("Build with -fno-dwarf2-cfi-asm") disabled some CFI information globally to work around a module loader bug on powerpc. But this disables the better unwind tables for all architectures, not just powerpc. Move the workaround to powerpc and also add a suitable comment that's it really a workaround. This improves dwarf2 unwind tables on x86 at least. Signed-off-by: Andi Kleen <ak@linux.intel.com> Cc: Kyle McMartin <kyle@mcmartin.ca> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Makefile | 3 --- arch/powerpc/Makefile | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 03053c66bb3a..2e74a68878c7 100644 --- a/Makefile +++ b/Makefile @@ -579,9 +579,6 @@ KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,) # disable invalid "can't wrap" optimizations for signed / pointers KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow) -# revert to pre-gcc-4.4 behaviour of .eh_frame -KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm) - # conserve stack if available KBUILD_CFLAGS += $(call cc-option,-fconserve-stack) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 1a54a3b3a3fa..42dcd3f4ad7b 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -112,6 +112,11 @@ KBUILD_CFLAGS += $(call cc-option,-mspe=no) # kernel considerably. KBUILD_CFLAGS += $(call cc-option,-funit-at-a-time) +# FIXME: the module load should be taught about the additional relocs +# generated by this. +# revert to pre-gcc-4.4 behaviour of .eh_frame +KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm) + # Never use string load/store instructions as they are # often slow when they are implemented at all KBUILD_CFLAGS += -mno-string -- GitLab From f81b1be40c44b33b9706d64c117edd29e627ad12 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Date: Mon, 8 Feb 2010 00:25:59 +0100 Subject: [PATCH 028/842] tags: include headers before source files Currently looking up a structure definition in TAGS / tags takes one to one of multiple "static struct X" definitions in arch sources, which makes it for many structs practically impossible to get to the required header. This patch changes the order of sources being tagged to first scan architecture includes, then the top-level include/ directory, and only then the rest. It also takes into account, that many architectures have more than one include directory, i.e., not only arch/$ARCH/include, but also arch/$ARCH/mach-X/include etc. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Reviewed-by: WANG Cong <xiyou.wangcong@gmail.com> [mmarek@suse.cz: fix 'var+=text' bashism] Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/tags.sh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/scripts/tags.sh b/scripts/tags.sh index 1a0c44d7c4a7..c1220419e59d 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -32,13 +32,20 @@ fi # find sources in arch/$ARCH find_arch_sources() { - find ${tree}arch/$1 $ignore -name "$2" -print; + for i in $archincludedir; do + prune="$prune -wholename $i -prune -o" + done + find ${tree}arch/$1 $ignore $prune -name "$2" -print; } # find sources in arch/$1/include find_arch_include_sources() { - find ${tree}arch/$1/include $ignore -name "$2" -print; + include=$(find ${tree}arch/$1/ -name include -type d); + if [ -n "$include" ]; then + archincludedir="$archincludedir $include" + find $include $ignore -name "$2" -print; + fi } # find sources in include/ @@ -63,14 +70,15 @@ find_sources() all_sources() { - for arch in $ALLSOURCE_ARCHS - do - find_sources $arch '*.[chS]' - done + find_arch_include_sources ${ARCH} '*.[chS]' if [ ! -z "$archinclude" ]; then find_arch_include_sources $archinclude '*.[chS]' fi find_include_sources '*.[chS]' + for arch in $ALLSOURCE_ARCHS + do + find_sources $arch '*.[chS]' + done find_other_sources '*.[chS]' } -- GitLab From e8d400a933fa44e2fba3849b084e1ae5814d7fca Mon Sep 17 00:00:00 2001 From: Kirill Smelkov <kirr@mns.spb.ru> Date: Wed, 17 Feb 2010 11:45:33 +0300 Subject: [PATCH 029/842] kbuild: fix a couple of typos in Documentation Signed-off-by: Kirill Smelkov <kirr@mns.spb.ru> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Documentation/kbuild/kbuild.txt | 2 +- Documentation/kbuild/makefiles.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt index 6f8c1cabbc5d..84725b72675a 100644 --- a/Documentation/kbuild/kbuild.txt +++ b/Documentation/kbuild/kbuild.txt @@ -65,7 +65,7 @@ CROSS_COMPILE Specify an optional fixed part of the binutils filename. CROSS_COMPILE can be a part of the filename or the full path. -CROSS_COMPILE is also used for ccache is some setups. +CROSS_COMPILE is also used for ccache in some setups. CF -------------------------------------------------- diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 71c602d61680..01351554df60 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -320,7 +320,7 @@ more details, with real examples. subdir-ccflags-y, subdir-asflags-y The two flags listed above are similar to ccflags-y and as-falgs-y. The difference is that the subdir- variants has effect for the kbuild - file where tey are present and all subdirectories. + file where they are present and all subdirectories. Options specified using subdir-* are added to the commandline before the options specified using the non-subdir variants. -- GitLab From a8bac511c8c18878908eb49f33f7257610b15180 Mon Sep 17 00:00:00 2001 From: Michal Marek <mmarek@suse.cz> Date: Fri, 19 Feb 2010 16:18:41 +0100 Subject: [PATCH 030/842] tags: Use $SRCARCH $ make mrproper $ make tags GEN tags find: `arch/x86_64/': No such file or directory Caused by commit f81b1be (tags: include headers before source files) Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Acked-by: WANG Cong <xiyou.wangcong@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/tags.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tags.sh b/scripts/tags.sh index c1220419e59d..9f459536f289 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -5,7 +5,7 @@ # mode may be any of: tags, TAGS, cscope # # Uses the following environment variables: -# ARCH, SUBARCH, srctree, src, obj +# ARCH, SUBARCH, SRCARCH, srctree, src, obj if [ "$KBUILD_VERBOSE" = "1" ]; then set -x @@ -70,7 +70,7 @@ find_sources() all_sources() { - find_arch_include_sources ${ARCH} '*.[chS]' + find_arch_include_sources ${SRCARCH} '*.[chS]' if [ ! -z "$archinclude" ]; then find_arch_include_sources $archinclude '*.[chS]' fi -- GitLab From 4431d4ce996de2cd2c45583209ba0dbbc9bf2795 Mon Sep 17 00:00:00 2001 From: John Kacur <jkacur@redhat.com> Date: Tue, 2 Mar 2010 15:38:10 +0100 Subject: [PATCH 031/842] tags: Fix spelling error in comment (is->if) Signed-off-by: John Kacur <jkacur@redhat.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/tags.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tags.sh b/scripts/tags.sh index 9f459536f289..caa867dba16d 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -17,7 +17,7 @@ ignore="( -name SCCS -o -name BitKeeper -o -name .svn -o \ -name .git ) \ -prune -o" -# Do not use full path is we do not use O=.. builds +# Do not use full path if we do not use O=.. builds if [ "${KBUILD_SRC}" = "" ]; then tree= else -- GitLab From bc75cc6b5636eed5f6a481cba808e906f71cfd94 Mon Sep 17 00:00:00 2001 From: John Kacur <jkacur@redhat.com> Date: Tue, 2 Mar 2010 16:57:52 +0100 Subject: [PATCH 032/842] tags: Add the ability to make tags for all archs using "all" make ALLSOURCE_ARCHS=all tags - Document this in kbuild.txt Without this change you have to type each arch separately. Signed-off-by: John Kacur <jkacur@redhat.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Documentation/kbuild/kbuild.txt | 4 ++++ scripts/tags.sh | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt index 84725b72675a..634c625da8ce 100644 --- a/Documentation/kbuild/kbuild.txt +++ b/Documentation/kbuild/kbuild.txt @@ -162,3 +162,7 @@ For tags/TAGS/cscope targets, you can specify more than one arch to be included in the databases, separated by blank space. E.g.: $ make ALLSOURCE_ARCHS="x86 mips arm" tags + +To get all available archs you can also specify all. E.g.: + + $ make ALLSOURCE_ARCHS=all tags diff --git a/scripts/tags.sh b/scripts/tags.sh index caa867dba16d..868b4c8fc25f 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -24,9 +24,20 @@ else tree=${srctree}/ fi +# Find all available archs +find_all_archs() +{ + ALLSOURCE_ARCHS="" + for arch in `ls ${tree}arch`; do + ALLSOURCE_ARCHS="${ALLSOURCE_ARCHS} "${arch##\/} + done +} + # Detect if ALLSOURCE_ARCHS is set. If not, we assume SRCARCH if [ "${ALLSOURCE_ARCHS}" = "" ]; then ALLSOURCE_ARCHS=${SRCARCH} +elif [ "${ALLSOURCE_ARCHS}" = "all" ]; then + find_all_archs fi # find sources in arch/$ARCH -- GitLab From 4af57b787b4be09419a2bb48aa705fa87ef41cca Mon Sep 17 00:00:00 2001 From: Tim Abbott <tabbott@ksplice.com> Date: Sat, 20 Feb 2010 01:03:34 +0100 Subject: [PATCH 033/842] Rename .data.cacheline_aligned to .data..cacheline_aligned. Signed-off-by: Tim Abbott <tabbott@ksplice.com> Cc: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/powerpc/kernel/vmlinux.lds.S | 2 +- arch/x86/kernel/init_task.c | 2 +- include/asm-generic/vmlinux.lds.h | 2 +- include/linux/cache.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index dcd01c82e701..3229c0622161 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -231,7 +231,7 @@ SECTIONS PAGE_ALIGNED_DATA(PAGE_SIZE) } - .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { + .data..cacheline_aligned : AT(ADDR(.data..cacheline_aligned) - LOAD_OFFSET) { CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES) } diff --git a/arch/x86/kernel/init_task.c b/arch/x86/kernel/init_task.c index 3a54dcb9cd0e..43e9ccf44947 100644 --- a/arch/x86/kernel/init_task.c +++ b/arch/x86/kernel/init_task.c @@ -34,7 +34,7 @@ EXPORT_SYMBOL(init_task); /* * per-CPU TSS segments. Threads are completely 'soft' on Linux, * no more per-task TSS's. The TSS size is kept cacheline-aligned - * so they are allowed to end up in the .data.cacheline_aligned + * so they are allowed to end up in the .data..cacheline_aligned * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 67e652068e0e..78450aaab9ef 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -189,7 +189,7 @@ #define CACHELINE_ALIGNED_DATA(align) \ . = ALIGN(align); \ - *(.data.cacheline_aligned) + *(.data..cacheline_aligned) #define INIT_TASK_DATA(align) \ . = ALIGN(align); \ diff --git a/include/linux/cache.h b/include/linux/cache.h index 97e24881c4c6..4c570653ab84 100644 --- a/include/linux/cache.h +++ b/include/linux/cache.h @@ -31,7 +31,7 @@ #ifndef __cacheline_aligned #define __cacheline_aligned \ __attribute__((__aligned__(SMP_CACHE_BYTES), \ - __section__(".data.cacheline_aligned"))) + __section__(".data..cacheline_aligned"))) #endif /* __cacheline_aligned */ #ifndef __cacheline_aligned_in_smp -- GitLab From 2af7687f1ad2c4571b9835f9bb2e3db9a738d258 Mon Sep 17 00:00:00 2001 From: Tim Abbott <tabbott@ksplice.com> Date: Sat, 20 Feb 2010 01:03:35 +0100 Subject: [PATCH 034/842] Rename .data.init_task to .data..init_task. Signed-off-by: Tim Abbott <tabbott@ksplice.com> Cc: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/ia64/kernel/init_task.c | 2 +- arch/powerpc/kernel/vmlinux.lds.S | 4 +--- include/asm-generic/vmlinux.lds.h | 4 ++-- include/linux/init_task.h | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c index e253ab8fcbc8..f9efe9739d3f 100644 --- a/arch/ia64/kernel/init_task.c +++ b/arch/ia64/kernel/init_task.c @@ -23,7 +23,7 @@ static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); * Initial task structure. * * We need to make sure that this is properly aligned due to the way process stacks are - * handled. This is done by having a special ".data.init_task" section... + * handled. This is done by having a special ".data..init_task" section... */ #define init_thread_info init_task_mem.s.thread_info diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 3229c0622161..136dcf3ce7bd 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -223,9 +223,7 @@ SECTIONS #endif /* The initial task and kernel stack */ - .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { - INIT_TASK_DATA(THREAD_SIZE) - } + INIT_TASK_DATA_SECTION(THREAD_SIZE) .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { PAGE_ALIGNED_DATA(PAGE_SIZE) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 78450aaab9ef..9cb9a9021e6e 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -193,7 +193,7 @@ #define INIT_TASK_DATA(align) \ . = ALIGN(align); \ - *(.data.init_task) + *(.data..init_task) /* * Read only Data @@ -435,7 +435,7 @@ */ #define INIT_TASK_DATA_SECTION(align) \ . = ALIGN(align); \ - .data.init_task : { \ + .data..init_task : { \ INIT_TASK_DATA(align) \ } diff --git a/include/linux/init_task.h b/include/linux/init_task.h index abec69b63d7e..f00253b3fc47 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -191,7 +191,7 @@ extern struct cred init_cred; } /* Attach to the init_task data structure for proper alignment */ -#define __init_task_data __attribute__((__section__(".data.init_task"))) +#define __init_task_data __attribute__((__section__(".data..init_task"))) #endif -- GitLab From 5f547f51a2205d18a507b88756e6988639db5f25 Mon Sep 17 00:00:00 2001 From: Tim Abbott <tabbott@ksplice.com> Date: Sat, 20 Feb 2010 01:03:36 +0100 Subject: [PATCH 035/842] powerpc: remove unused __page_aligned definition. There is already an architecture-independent __page_aligned_data macro for this purpose, so removing the powerpc-specific macro should be harmless. Signed-off-by: Tim Abbott <tabbott@ksplice.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/powerpc/include/asm/page_64.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h index bfc4e027e2ad..358ff14ea25e 100644 --- a/arch/powerpc/include/asm/page_64.h +++ b/arch/powerpc/include/asm/page_64.h @@ -162,14 +162,6 @@ do { \ #endif /* !CONFIG_HUGETLB_PAGE */ -#ifdef MODULE -#define __page_aligned __attribute__((__aligned__(PAGE_SIZE))) -#else -#define __page_aligned \ - __attribute__((__aligned__(PAGE_SIZE), \ - __section__(".data.page_aligned"))) -#endif - #define VM_DATA_DEFAULT_FLAGS \ (test_thread_flag(TIF_32BIT) ? \ VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64) -- GitLab From 75b134837263eb919d91678f7fcf3d54cd088c8d Mon Sep 17 00:00:00 2001 From: Tim Abbott <tabbott@ksplice.com> Date: Sat, 20 Feb 2010 01:03:37 +0100 Subject: [PATCH 036/842] Rename .data.page_aligned to .data..page_aligned. Signed-off-by: Tim Abbott <tabbott@ksplice.com> Cc: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/ia64/kernel/vmlinux.lds.S | 2 +- arch/powerpc/kernel/vmlinux.lds.S | 2 +- include/asm-generic/vmlinux.lds.h | 2 +- include/linux/linkage.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 1295ba327f6f..7fb1198611fe 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -175,7 +175,7 @@ SECTIONS . = ALIGN(PAGE_SIZE); __init_end = .; - .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) + .data..page_aligned : AT(ADDR(.data..page_aligned) - LOAD_OFFSET) { PAGE_ALIGNED_DATA(PAGE_SIZE) . = ALIGN(PAGE_SIZE); diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 136dcf3ce7bd..951e6c5b2c8e 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -225,7 +225,7 @@ SECTIONS /* The initial task and kernel stack */ INIT_TASK_DATA_SECTION(THREAD_SIZE) - .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { + .data..page_aligned : AT(ADDR(.data..page_aligned) - LOAD_OFFSET) { PAGE_ALIGNED_DATA(PAGE_SIZE) } diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 9cb9a9021e6e..569c25a85558 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -181,7 +181,7 @@ #define PAGE_ALIGNED_DATA(page_align) \ . = ALIGN(page_align); \ - *(.data.page_aligned) + *(.data..page_aligned) #define READ_MOSTLY_DATA(align) \ . = ALIGN(align); \ diff --git a/include/linux/linkage.h b/include/linux/linkage.h index 5126cceb6ae9..05f4406d5995 100644 --- a/include/linux/linkage.h +++ b/include/linux/linkage.h @@ -18,7 +18,7 @@ # define asmregparm #endif -#define __page_aligned_data __section(.data.page_aligned) __aligned(PAGE_SIZE) +#define __page_aligned_data __section(.data..page_aligned) __aligned(PAGE_SIZE) #define __page_aligned_bss __section(.bss.page_aligned) __aligned(PAGE_SIZE) /* @@ -27,7 +27,7 @@ * Note when using these that you must specify the appropriate * alignment directives yourself */ -#define __PAGE_ALIGNED_DATA .section ".data.page_aligned", "aw" +#define __PAGE_ALIGNED_DATA .section ".data..page_aligned", "aw" #define __PAGE_ALIGNED_BSS .section ".bss.page_aligned", "aw" /* -- GitLab From 7c74df07f90cabe61d700727bca04682b4e477f3 Mon Sep 17 00:00:00 2001 From: Tim Abbott <tabbott@ksplice.com> Date: Sat, 20 Feb 2010 01:03:38 +0100 Subject: [PATCH 037/842] Rename .bss.page_aligned to .bss..page_aligned. Signed-off-by: Tim Abbott <tabbott@ksplice.com> Cc: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/x86/kernel/vmlinux.lds.S | 2 +- include/asm-generic/vmlinux.lds.h | 2 +- include/linux/linkage.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index f92a0da608cb..8b6bb4e7f5c5 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -305,7 +305,7 @@ SECTIONS . = ALIGN(PAGE_SIZE); .bss : AT(ADDR(.bss) - LOAD_OFFSET) { __bss_start = .; - *(.bss.page_aligned) + *(.bss..page_aligned) *(.bss) . = ALIGN(4); __bss_stop = .; diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 569c25a85558..32cddc155940 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -499,7 +499,7 @@ #define BSS(bss_align) \ . = ALIGN(bss_align); \ .bss : AT(ADDR(.bss) - LOAD_OFFSET) { \ - *(.bss.page_aligned) \ + *(.bss..page_aligned) \ *(.dynbss) \ *(.bss) \ *(COMMON) \ diff --git a/include/linux/linkage.h b/include/linux/linkage.h index 05f4406d5995..7135ebc8428c 100644 --- a/include/linux/linkage.h +++ b/include/linux/linkage.h @@ -19,7 +19,7 @@ #endif #define __page_aligned_data __section(.data..page_aligned) __aligned(PAGE_SIZE) -#define __page_aligned_bss __section(.bss.page_aligned) __aligned(PAGE_SIZE) +#define __page_aligned_bss __section(.bss..page_aligned) __aligned(PAGE_SIZE) /* * For assembly routines. @@ -28,7 +28,7 @@ * alignment directives yourself */ #define __PAGE_ALIGNED_DATA .section ".data..page_aligned", "aw" -#define __PAGE_ALIGNED_BSS .section ".bss.page_aligned", "aw" +#define __PAGE_ALIGNED_BSS .section ".bss..page_aligned", "aw" /* * This is used by architectures to keep arguments on the stack -- GitLab From 1360e0707090c763d0d06cbc74b04f9c9588b582 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:39 +0100 Subject: [PATCH 038/842] Rename .bss.stack to .bss..stack. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/frv/kernel/break.S | 2 +- arch/frv/kernel/vmlinux.lds.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/frv/kernel/break.S b/arch/frv/kernel/break.S index bd0bdf908d93..c5388b756c72 100644 --- a/arch/frv/kernel/break.S +++ b/arch/frv/kernel/break.S @@ -21,7 +21,7 @@ # # the break handler has its own stack # - .section .bss.stack + .section .bss..stack .globl __break_user_context .balign THREAD_SIZE __break_stack: diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S index cbe811fccfcc..472eb8c8a1b4 100644 --- a/arch/frv/kernel/vmlinux.lds.S +++ b/arch/frv/kernel/vmlinux.lds.S @@ -114,7 +114,7 @@ SECTIONS .sbss : { *(.sbss .sbss.*) } .bss : { *(.bss .bss.*) } - .bss.stack : { *(.bss) } + .bss..stack : { *(.bss) } __bss_stop = .; _end = . ; -- GitLab From e1cb14b85f802c7717a46b1a38e1fba23ead86c3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:40 +0100 Subject: [PATCH 039/842] Rename .data.gate to .data..gate. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/ia64/kernel/Makefile.gate | 2 +- arch/ia64/kernel/gate-data.S | 2 +- arch/ia64/kernel/vmlinux.lds.S | 4 ++-- arch/ia64/xen/gate-data.S | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/ia64/kernel/Makefile.gate b/arch/ia64/kernel/Makefile.gate index ab9b03a9adcc..ceeffc509764 100644 --- a/arch/ia64/kernel/Makefile.gate +++ b/arch/ia64/kernel/Makefile.gate @@ -21,7 +21,7 @@ GATECFLAGS_gate-syms.o = -r $(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE $(call if_changed,gate) -# gate-data.o contains the gate DSO image as data in section .data.gate. +# gate-data.o contains the gate DSO image as data in section .data..gate. # We must build gate.so before we can assemble it. # Note: kbuild does not track this dependency due to usage of .incbin $(obj)/gate-data.o: $(obj)/gate.so diff --git a/arch/ia64/kernel/gate-data.S b/arch/ia64/kernel/gate-data.S index 258c0a3238fb..b3ef1c72e132 100644 --- a/arch/ia64/kernel/gate-data.S +++ b/arch/ia64/kernel/gate-data.S @@ -1,3 +1,3 @@ - .section .data.gate, "aw" + .section .data..gate, "aw" .incbin "arch/ia64/kernel/gate.so" diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 7fb1198611fe..3e338093c551 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -180,12 +180,12 @@ SECTIONS PAGE_ALIGNED_DATA(PAGE_SIZE) . = ALIGN(PAGE_SIZE); __start_gate_section = .; - *(.data.gate) + *(.data..gate) __stop_gate_section = .; #ifdef CONFIG_XEN . = ALIGN(PAGE_SIZE); __xen_start_gate_section = .; - *(.data.gate.xen) + *(.data..gate.xen) __xen_stop_gate_section = .; #endif } diff --git a/arch/ia64/xen/gate-data.S b/arch/ia64/xen/gate-data.S index 7d4830afc91d..6f95b6b32a4e 100644 --- a/arch/ia64/xen/gate-data.S +++ b/arch/ia64/xen/gate-data.S @@ -1,3 +1,3 @@ - .section .data.gate.xen, "aw" + .section .data..gate.xen, "aw" .incbin "arch/ia64/xen/gate.so" -- GitLab From 9d1578a3ba7fe9d3eecf86615ee427789792c2d6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:41 +0100 Subject: [PATCH 040/842] Rename .data.init_irqstack to .data..init_irqstack. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/um/kernel/dyn.lds.S | 2 +- arch/um/kernel/init_task.c | 2 +- arch/um/kernel/uml.lds.S | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index 7fcad58e216d..69268014dd8e 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -94,7 +94,7 @@ SECTIONS .data : { INIT_TASK_DATA(KERNEL_STACK_SIZE) . = ALIGN(KERNEL_STACK_SIZE); - *(.data.init_irqstack) + *(.data..init_irqstack) DATA_DATA *(.data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index 8aa77b61a5ff..ddc9698b66ed 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c @@ -34,5 +34,5 @@ union thread_union init_thread_union __init_task_data = { INIT_THREAD_INFO(init_task) }; union thread_union cpu0_irqstack - __attribute__((__section__(".data.init_irqstack"))) = + __attribute__((__section__(".data..init_irqstack"))) = { INIT_THREAD_INFO(init_task) }; diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index e7a6cca667aa..ec6378550671 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -50,7 +50,7 @@ SECTIONS { INIT_TASK_DATA(KERNEL_STACK_SIZE) . = ALIGN(KERNEL_STACK_SIZE); - *(.data.init_irqstack) + *(.data..init_irqstack) DATA_DATA *(.gnu.linkonce.d*) CONSTRUCTORS -- GitLab From dafb9320671316fbd030b1d2e0ab9b96597223cb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:42 +0100 Subject: [PATCH 041/842] Rename .data..patch.XXX to .data..patch.XXX. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/ia64/include/asm/asmmacro.h | 12 ++++++------ arch/ia64/kernel/gate.S | 8 ++++---- arch/ia64/kernel/gate.lds.S | 10 +++++----- arch/ia64/kernel/minstate.h | 4 ++-- arch/ia64/kernel/vmlinux.lds.S | 16 ++++++++-------- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/arch/ia64/include/asm/asmmacro.h b/arch/ia64/include/asm/asmmacro.h index c1642fd64029..3ab6d75aa3db 100644 --- a/arch/ia64/include/asm/asmmacro.h +++ b/arch/ia64/include/asm/asmmacro.h @@ -70,12 +70,12 @@ name: * path (ivt.S - TLB miss processing) or in places where it might not be * safe to use a "tpa" instruction (mca_asm.S - error recovery). */ - .section ".data.patch.vtop", "a" // declare section & section attributes + .section ".data..patch.vtop", "a" // declare section & section attributes .previous #define LOAD_PHYSICAL(pr, reg, obj) \ [1:](pr)movl reg = obj; \ - .xdata4 ".data.patch.vtop", 1b-. + .xdata4 ".data..patch.vtop", 1b-. /* * For now, we always put in the McKinley E9 workaround. On CPUs that don't need it, @@ -84,11 +84,11 @@ name: #define DO_MCKINLEY_E9_WORKAROUND #ifdef DO_MCKINLEY_E9_WORKAROUND - .section ".data.patch.mckinley_e9", "a" + .section ".data..patch.mckinley_e9", "a" .previous /* workaround for Itanium 2 Errata 9: */ # define FSYS_RETURN \ - .xdata4 ".data.patch.mckinley_e9", 1f-.; \ + .xdata4 ".data..patch.mckinley_e9", 1f-.; \ 1:{ .mib; \ nop.m 0; \ mov r16=ar.pfs; \ @@ -107,11 +107,11 @@ name: * If physical stack register size is different from DEF_NUM_STACK_REG, * dynamically patch the kernel for correct size. */ - .section ".data.patch.phys_stack_reg", "a" + .section ".data..patch.phys_stack_reg", "a" .previous #define LOAD_PHYS_STACK_REG_SIZE(reg) \ [1:] adds reg=IA64_NUM_PHYS_STACK_REG*8+8,r0; \ - .xdata4 ".data.patch.phys_stack_reg", 1b-. + .xdata4 ".data..patch.phys_stack_reg", 1b-. /* * Up until early 2004, use of .align within a function caused bad unwind info. diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S index cf5e0a105e16..245d3e1ec7e1 100644 --- a/arch/ia64/kernel/gate.S +++ b/arch/ia64/kernel/gate.S @@ -21,18 +21,18 @@ * to targets outside the shared object) and to avoid multi-phase kernel builds, we * simply create minimalistic "patch lists" in special ELF sections. */ - .section ".data.patch.fsyscall_table", "a" + .section ".data..patch.fsyscall_table", "a" .previous #define LOAD_FSYSCALL_TABLE(reg) \ [1:] movl reg=0; \ - .xdata4 ".data.patch.fsyscall_table", 1b-. + .xdata4 ".data..patch.fsyscall_table", 1b-. - .section ".data.patch.brl_fsys_bubble_down", "a" + .section ".data..patch.brl_fsys_bubble_down", "a" .previous #define BRL_COND_FSYS_BUBBLE_DOWN(pr) \ [1:](pr)brl.cond.sptk 0; \ ;; \ - .xdata4 ".data.patch.brl_fsys_bubble_down", 1b-. + .xdata4 ".data..patch.brl_fsys_bubble_down", 1b-. GLOBAL_ENTRY(__kernel_syscall_via_break) .prologue diff --git a/arch/ia64/kernel/gate.lds.S b/arch/ia64/kernel/gate.lds.S index 88c64ed47c36..d32b0855110a 100644 --- a/arch/ia64/kernel/gate.lds.S +++ b/arch/ia64/kernel/gate.lds.S @@ -33,21 +33,21 @@ SECTIONS */ . = GATE_ADDR + 0x600; - .data.patch : { + .data..patch : { __paravirt_start_gate_mckinley_e9_patchlist = .; - *(.data.patch.mckinley_e9) + *(.data..patch.mckinley_e9) __paravirt_end_gate_mckinley_e9_patchlist = .; __paravirt_start_gate_vtop_patchlist = .; - *(.data.patch.vtop) + *(.data..patch.vtop) __paravirt_end_gate_vtop_patchlist = .; __paravirt_start_gate_fsyscall_patchlist = .; - *(.data.patch.fsyscall_table) + *(.data..patch.fsyscall_table) __paravirt_end_gate_fsyscall_patchlist = .; __paravirt_start_gate_brl_fsys_bubble_down_patchlist = .; - *(.data.patch.brl_fsys_bubble_down) + *(.data..patch.brl_fsys_bubble_down) __paravirt_end_gate_brl_fsys_bubble_down_patchlist = .; } :readable diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h index 292e214a3b84..d56753a11636 100644 --- a/arch/ia64/kernel/minstate.h +++ b/arch/ia64/kernel/minstate.h @@ -16,7 +16,7 @@ #define ACCOUNT_SYS_ENTER #endif -.section ".data.patch.rse", "a" +.section ".data..patch.rse", "a" .previous /* @@ -215,7 +215,7 @@ (pUStk) extr.u r17=r18,3,6; \ (pUStk) sub r16=r18,r22; \ [1:](pKStk) br.cond.sptk.many 1f; \ - .xdata4 ".data.patch.rse",1b-. \ + .xdata4 ".data..patch.rse",1b-. \ ;; \ cmp.ge p6,p7 = 33,r17; \ ;; \ diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 3e338093c551..b943eff2129e 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -75,10 +75,10 @@ SECTIONS __stop___mca_table = .; } - .data.patch.phys_stack_reg : AT(ADDR(.data.patch.phys_stack_reg) - LOAD_OFFSET) + .data..patch.phys_stack_reg : AT(ADDR(.data..patch.phys_stack_reg) - LOAD_OFFSET) { __start___phys_stack_reg_patchlist = .; - *(.data.patch.phys_stack_reg) + *(.data..patch.phys_stack_reg) __end___phys_stack_reg_patchlist = .; } @@ -110,24 +110,24 @@ SECTIONS INIT_TEXT_SECTION(PAGE_SIZE) INIT_DATA_SECTION(16) - .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET) + .data..patch.vtop : AT(ADDR(.data..patch.vtop) - LOAD_OFFSET) { __start___vtop_patchlist = .; - *(.data.patch.vtop) + *(.data..patch.vtop) __end___vtop_patchlist = .; } - .data.patch.rse : AT(ADDR(.data.patch.rse) - LOAD_OFFSET) + .data..patch.rse : AT(ADDR(.data..patch.rse) - LOAD_OFFSET) { __start___rse_patchlist = .; - *(.data.patch.rse) + *(.data..patch.rse) __end___rse_patchlist = .; } - .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET) + .data..patch.mckinley_e9 : AT(ADDR(.data..patch.mckinley_e9) - LOAD_OFFSET) { __start___mckinley_e9_bundles = .; - *(.data.patch.mckinley_e9) + *(.data..patch.mckinley_e9) __end___mckinley_e9_bundles = .; } -- GitLab From 3d9a854c2dac3e888393b23ba7adafcce4d6d4b9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:43 +0100 Subject: [PATCH 042/842] Rename .data[.percpu][.XXX] to .data[..percpu][..XXX]. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/ia64/include/asm/percpu.h | 2 +- include/asm-generic/percpu.h | 10 +++++----- include/asm-generic/vmlinux.lds.h | 24 ++++++++++++------------ include/linux/percpu-defs.h | 4 ++-- kernel/module.c | 2 +- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/arch/ia64/include/asm/percpu.h b/arch/ia64/include/asm/percpu.h index 30cf46534dd2..35d9aeb6d85f 100644 --- a/arch/ia64/include/asm/percpu.h +++ b/arch/ia64/include/asm/percpu.h @@ -31,7 +31,7 @@ extern void *per_cpu_init(void); #endif /* SMP */ -#define PER_CPU_BASE_SECTION ".data.percpu" +#define PER_CPU_BASE_SECTION ".data..percpu" /* * Be extremely careful when taking the address of this variable! Due to virtual diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index 8087b90d4673..1202a1550e91 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h @@ -76,7 +76,7 @@ extern void setup_per_cpu_areas(void); #ifndef PER_CPU_BASE_SECTION #ifdef CONFIG_SMP -#define PER_CPU_BASE_SECTION ".data.percpu" +#define PER_CPU_BASE_SECTION ".data..percpu" #else #define PER_CPU_BASE_SECTION ".data" #endif @@ -88,15 +88,15 @@ extern void setup_per_cpu_areas(void); #define PER_CPU_SHARED_ALIGNED_SECTION "" #define PER_CPU_ALIGNED_SECTION "" #else -#define PER_CPU_SHARED_ALIGNED_SECTION ".shared_aligned" -#define PER_CPU_ALIGNED_SECTION ".shared_aligned" +#define PER_CPU_SHARED_ALIGNED_SECTION "..shared_aligned" +#define PER_CPU_ALIGNED_SECTION "..shared_aligned" #endif -#define PER_CPU_FIRST_SECTION ".first" +#define PER_CPU_FIRST_SECTION "..first" #else #define PER_CPU_SHARED_ALIGNED_SECTION "" -#define PER_CPU_ALIGNED_SECTION ".shared_aligned" +#define PER_CPU_ALIGNED_SECTION "..shared_aligned" #define PER_CPU_FIRST_SECTION "" #endif diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 32cddc155940..e304fcd10bc7 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -666,16 +666,16 @@ */ #define PERCPU_VADDR(vaddr, phdr) \ VMLINUX_SYMBOL(__per_cpu_load) = .; \ - .data.percpu vaddr : AT(VMLINUX_SYMBOL(__per_cpu_load) \ + .data..percpu vaddr : AT(VMLINUX_SYMBOL(__per_cpu_load) \ - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__per_cpu_start) = .; \ - *(.data.percpu.first) \ - *(.data.percpu.page_aligned) \ - *(.data.percpu) \ - *(.data.percpu.shared_aligned) \ + *(.data..percpu..first) \ + *(.data..percpu..page_aligned) \ + *(.data..percpu) \ + *(.data..percpu..shared_aligned) \ VMLINUX_SYMBOL(__per_cpu_end) = .; \ } phdr \ - . = VMLINUX_SYMBOL(__per_cpu_load) + SIZEOF(.data.percpu); + . = VMLINUX_SYMBOL(__per_cpu_load) + SIZEOF(.data..percpu); /** * PERCPU - define output section for percpu area, simple version @@ -687,18 +687,18 @@ * * This macro is equivalent to ALIGN(align); PERCPU_VADDR( , ) except * that __per_cpu_load is defined as a relative symbol against - * .data.percpu which is required for relocatable x86_32 + * .data..percpu which is required for relocatable x86_32 * configuration. */ #define PERCPU(align) \ . = ALIGN(align); \ - .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { \ + .data..percpu : AT(ADDR(.data..percpu) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__per_cpu_load) = .; \ VMLINUX_SYMBOL(__per_cpu_start) = .; \ - *(.data.percpu.first) \ - *(.data.percpu.page_aligned) \ - *(.data.percpu) \ - *(.data.percpu.shared_aligned) \ + *(.data..percpu..first) \ + *(.data..percpu..page_aligned) \ + *(.data..percpu) \ + *(.data..percpu..shared_aligned) \ VMLINUX_SYMBOL(__per_cpu_end) = .; \ } diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h index 5a5d6ce4bd55..2351191f8c82 100644 --- a/include/linux/percpu-defs.h +++ b/include/linux/percpu-defs.h @@ -127,11 +127,11 @@ * Declaration/definition used for per-CPU variables that must be page aligned. */ #define DECLARE_PER_CPU_PAGE_ALIGNED(type, name) \ - DECLARE_PER_CPU_SECTION(type, name, ".page_aligned") \ + DECLARE_PER_CPU_SECTION(type, name, "..page_aligned") \ __aligned(PAGE_SIZE) #define DEFINE_PER_CPU_PAGE_ALIGNED(type, name) \ - DEFINE_PER_CPU_SECTION(type, name, ".page_aligned") \ + DEFINE_PER_CPU_SECTION(type, name, "..page_aligned") \ __aligned(PAGE_SIZE) /* diff --git a/kernel/module.c b/kernel/module.c index f82386bd9ee9..5daf0abd63c1 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -397,7 +397,7 @@ static unsigned int find_pcpusec(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, const char *secstrings) { - return find_sec(hdr, sechdrs, secstrings, ".data.percpu"); + return find_sec(hdr, sechdrs, secstrings, ".data..percpu"); } static void percpu_modcopy(void *pcpudest, const void *from, unsigned long size) -- GitLab From 54cb27a71f51d304342c79e62fd7667f2171062b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:44 +0100 Subject: [PATCH 043/842] Rename .data.read_mostly to .data..read_mostly. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/ia64/include/asm/cache.h | 2 +- arch/ia64/kernel/paravirtentry.S | 2 +- arch/ia64/xen/xensetup.S | 2 +- arch/parisc/include/asm/cache.h | 2 +- arch/parisc/kernel/head.S | 2 +- arch/powerpc/include/asm/cache.h | 2 +- arch/powerpc/kernel/vmlinux.lds.S | 2 +- arch/s390/include/asm/cache.h | 2 +- arch/sh/include/asm/cache.h | 2 +- arch/sparc/include/asm/cache.h | 2 +- arch/x86/include/asm/cache.h | 2 +- include/asm-generic/vmlinux.lds.h | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/ia64/include/asm/cache.h b/arch/ia64/include/asm/cache.h index e7482bd628ff..988254a7d349 100644 --- a/arch/ia64/include/asm/cache.h +++ b/arch/ia64/include/asm/cache.h @@ -24,6 +24,6 @@ # define SMP_CACHE_BYTES (1 << 3) #endif -#define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) #endif /* _ASM_IA64_CACHE_H */ diff --git a/arch/ia64/kernel/paravirtentry.S b/arch/ia64/kernel/paravirtentry.S index 6158560d7f17..92d880c4d3d1 100644 --- a/arch/ia64/kernel/paravirtentry.S +++ b/arch/ia64/kernel/paravirtentry.S @@ -28,7 +28,7 @@ #include "entry.h" #define DATA8(sym, init_value) \ - .pushsection .data.read_mostly ; \ + .pushsection .data..read_mostly ; \ .align 8 ; \ .global sym ; \ sym: ; \ diff --git a/arch/ia64/xen/xensetup.S b/arch/ia64/xen/xensetup.S index aff8346ea193..b820ed02ab9f 100644 --- a/arch/ia64/xen/xensetup.S +++ b/arch/ia64/xen/xensetup.S @@ -14,7 +14,7 @@ #include <linux/init.h> #include <xen/interface/elfnote.h> - .section .data.read_mostly + .section .data..read_mostly .align 8 .global xen_domain_type xen_domain_type: diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h index 32c2cca74345..45effe6978fa 100644 --- a/arch/parisc/include/asm/cache.h +++ b/arch/parisc/include/asm/cache.h @@ -28,7 +28,7 @@ #define SMP_CACHE_BYTES L1_CACHE_BYTES -#define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) void parisc_cache_init(void); /* initializes cache-flushing */ void disable_sr_hashing_asm(int); /* low level support for above */ diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index 0e3d9f9b9e33..4dbdf0ed6fa0 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -345,7 +345,7 @@ smp_slave_stext: ENDPROC(stext) #ifndef CONFIG_64BIT - .section .data.read_mostly + .section .data..read_mostly .align 4 .export $global$,data diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index 81de6eb3455d..3f41ab9c1e4e 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -38,7 +38,7 @@ extern struct ppc64_caches ppc64_caches; #endif /* __powerpc64__ && ! __ASSEMBLY__ */ #if !defined(__ASSEMBLY__) -#define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) #endif #endif /* __KERNEL__ */ diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 951e6c5b2c8e..8a0deefac08d 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -233,7 +233,7 @@ SECTIONS CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES) } - .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { + .data..read_mostly : AT(ADDR(.data..read_mostly) - LOAD_OFFSET) { READ_MOSTLY_DATA(L1_CACHE_BYTES) } diff --git a/arch/s390/include/asm/cache.h b/arch/s390/include/asm/cache.h index 9b866816863c..24aafa68b643 100644 --- a/arch/s390/include/asm/cache.h +++ b/arch/s390/include/asm/cache.h @@ -14,6 +14,6 @@ #define L1_CACHE_BYTES 256 #define L1_CACHE_SHIFT 8 -#define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) #endif diff --git a/arch/sh/include/asm/cache.h b/arch/sh/include/asm/cache.h index 02df18ea9608..455a9a9bd7dd 100644 --- a/arch/sh/include/asm/cache.h +++ b/arch/sh/include/asm/cache.h @@ -14,7 +14,7 @@ #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -#define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) #ifndef __ASSEMBLY__ struct cache_info { diff --git a/arch/sparc/include/asm/cache.h b/arch/sparc/include/asm/cache.h index 41f85ae4bd4a..2909f0ab6f9e 100644 --- a/arch/sparc/include/asm/cache.h +++ b/arch/sparc/include/asm/cache.h @@ -19,7 +19,7 @@ #define SMP_CACHE_BYTES (1 << SMP_CACHE_BYTES_SHIFT) -#define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) #ifdef CONFIG_SPARC32 #include <asm/asi.h> diff --git a/arch/x86/include/asm/cache.h b/arch/x86/include/asm/cache.h index 2f9047cfaaca..48f99f15452e 100644 --- a/arch/x86/include/asm/cache.h +++ b/arch/x86/include/asm/cache.h @@ -7,7 +7,7 @@ #define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -#define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) #define INTERNODE_CACHE_SHIFT CONFIG_X86_INTERNODE_CACHE_SHIFT #define INTERNODE_CACHE_BYTES (1 << INTERNODE_CACHE_SHIFT) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index e304fcd10bc7..6f6da4f080f2 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -185,7 +185,7 @@ #define READ_MOSTLY_DATA(align) \ . = ALIGN(align); \ - *(.data.read_mostly) + *(.data..read_mostly) #define CACHELINE_ALIGNED_DATA(align) \ . = ALIGN(align); \ -- GitLab From d56a3c1a9faa3a1703ce696e111143bfd9f071f1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:45 +0100 Subject: [PATCH 044/842] Rename .data.vmpages and .data.vm0.XXX to .data..vmpages and .data..vm0.XXX. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/parisc/kernel/init_task.c | 6 +++--- arch/parisc/kernel/vmlinux.lds.S | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/parisc/kernel/init_task.c b/arch/parisc/kernel/init_task.c index d020eae6525c..4a91e433416f 100644 --- a/arch/parisc/kernel/init_task.c +++ b/arch/parisc/kernel/init_task.c @@ -53,11 +53,11 @@ union thread_union init_thread_union __init_task_data * guarantee that global objects will be laid out in memory in the same order * as the order of declaration, so put these in different sections and use * the linker script to order them. */ -pmd_t pmd0[PTRS_PER_PMD] __attribute__ ((__section__ (".data.vm0.pmd"), aligned(PAGE_SIZE))); +pmd_t pmd0[PTRS_PER_PMD] __attribute__ ((__section__ (".data..vm0.pmd"), aligned(PAGE_SIZE))); #endif -pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((__section__ (".data.vm0.pgd"), aligned(PAGE_SIZE))); -pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((__section__ (".data.vm0.pte"), aligned(PAGE_SIZE))); +pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((__section__ (".data..vm0.pgd"), aligned(PAGE_SIZE))); +pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((__section__ (".data..vm0.pte"), aligned(PAGE_SIZE))); /* * Initial task structure. diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 9dab4a4e09f7..33ec31ddb06d 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -105,10 +105,10 @@ SECTIONS __bss_start = .; /* page table entries need to be PAGE_SIZE aligned */ . = ALIGN(PAGE_SIZE); - .data.vmpages : { - *(.data.vm0.pmd) - *(.data.vm0.pgd) - *(.data.vm0.pte) + .data..vmpages : { + *(.data..vm0.pmd) + *(.data..vm0.pgd) + *(.data..vm0.pte) } .bss : { *(.bss) -- GitLab From 041d5f94c4d67444c40584db0d1cacf32a47a25b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:46 +0100 Subject: [PATCH 045/842] Rename .rodata.compressed to .rodata..compressed. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/sh/boot/compressed/vmlinux.scr | 2 +- arch/x86/boot/compressed/mkpiggy.c | 2 +- arch/x86/boot/compressed/vmlinux.lds.S | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/sh/boot/compressed/vmlinux.scr b/arch/sh/boot/compressed/vmlinux.scr index f02382ae5c48..862d74808236 100644 --- a/arch/sh/boot/compressed/vmlinux.scr +++ b/arch/sh/boot/compressed/vmlinux.scr @@ -1,6 +1,6 @@ SECTIONS { - .rodata.compressed : { + .rodata..compressed : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index bcbd36c41432..5c228129d175 100644 --- a/arch/x86/boot/compressed/mkpiggy.c +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -77,7 +77,7 @@ int main(int argc, char *argv[]) offs += 32*1024 + 18; /* Add 32K + 18 bytes slack */ offs = (offs+4095) & ~4095; /* Round to a 4K boundary */ - printf(".section \".rodata.compressed\",\"a\",@progbits\n"); + printf(".section \".rodata..compressed\",\"a\",@progbits\n"); printf(".globl z_input_len\n"); printf("z_input_len = %lu\n", ilen); printf(".globl z_output_len\n"); diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index a6f1a59a5b0c..5ddabceee124 100644 --- a/arch/x86/boot/compressed/vmlinux.lds.S +++ b/arch/x86/boot/compressed/vmlinux.lds.S @@ -26,8 +26,8 @@ SECTIONS HEAD_TEXT _ehead = . ; } - .rodata.compressed : { - *(.rodata.compressed) + .rodata..compressed : { + *(.rodata..compressed) } .text : { _text = .; /* Text */ -- GitLab From 2b55f3672c77e76b62efd0dba6bf29addac071fd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:47 +0100 Subject: [PATCH 046/842] Rename .text.ivt to .text..ivt. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/ia64/kernel/ivt.S | 2 +- arch/ia64/kernel/vmlinux.lds.S | 2 +- arch/ia64/kvm/vmm_ivt.S | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index ec9a5fdfa1b9..0c14512b12dc 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -83,7 +83,7 @@ mov r19=n;; /* prepare to save predicates */ \ br.sptk.many dispatch_to_fault_handler - .section .text.ivt,"ax" + .section .text..ivt,"ax" .align 32768 // align on 32KB boundary .global ia64_ivt diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index b943eff2129e..5c01d3c7020d 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -8,7 +8,7 @@ #define IVT_TEXT \ VMLINUX_SYMBOL(__start_ivt_text) = .; \ - *(.text.ivt) \ + *(.text..ivt) \ VMLINUX_SYMBOL(__end_ivt_text) = .; OUTPUT_FORMAT("elf64-ia64-little") diff --git a/arch/ia64/kvm/vmm_ivt.S b/arch/ia64/kvm/vmm_ivt.S index 40920c630649..24018484c6e9 100644 --- a/arch/ia64/kvm/vmm_ivt.S +++ b/arch/ia64/kvm/vmm_ivt.S @@ -104,7 +104,7 @@ GLOBAL_ENTRY(kvm_vmm_panic) br.call.sptk.many b6=vmm_panic_handler; END(kvm_vmm_panic) - .section .text.ivt,"ax" + .section .text..ivt,"ax" .align 32768 // align on 32KB boundary .global kvm_ia64_ivt -- GitLab From 75ddb0e87d0d31ad44d574e7fe2e962e4efecadb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:48 +0100 Subject: [PATCH 047/842] Rename .text.lock to .text..lock. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Documentation/mutex-design.txt | 4 ++-- arch/ia64/kernel/vmlinux.lds.S | 4 ++-- arch/m68knommu/kernel/vmlinux.lds.S | 2 +- include/linux/spinlock.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/mutex-design.txt b/Documentation/mutex-design.txt index aa60d1f627e5..c91ccc0720fa 100644 --- a/Documentation/mutex-design.txt +++ b/Documentation/mutex-design.txt @@ -66,14 +66,14 @@ of advantages of mutexes: c0377ccb <mutex_lock>: c0377ccb: f0 ff 08 lock decl (%eax) - c0377cce: 78 0e js c0377cde <.text.lock.mutex> + c0377cce: 78 0e js c0377cde <.text..lock.mutex> c0377cd0: c3 ret the unlocking fastpath is equally tight: c0377cd1 <mutex_unlock>: c0377cd1: f0 ff 00 lock incl (%eax) - c0377cd4: 7e 0f jle c0377ce5 <.text.lock.mutex+0x7> + c0377cd4: 7e 0f jle c0377ce5 <.text..lock.mutex+0x7> c0377cd6: c3 ret - 'struct mutex' semantics are well-defined and are enforced if diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 5c01d3c7020d..e07218a2577f 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -54,8 +54,8 @@ SECTIONS .text2 : AT(ADDR(.text2) - LOAD_OFFSET) { *(.text2) } #ifdef CONFIG_SMP - .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) - { *(.text.lock) } + .text..lock : AT(ADDR(.text..lock) - LOAD_OFFSET) + { *(.text..lock) } #endif _etext = .; diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S index 9f1784f586b9..fd3df56fc458 100644 --- a/arch/m68knommu/kernel/vmlinux.lds.S +++ b/arch/m68knommu/kernel/vmlinux.lds.S @@ -68,7 +68,7 @@ SECTIONS { TEXT_TEXT SCHED_TEXT LOCK_TEXT - *(.text.lock) + *(.text..lock) . = ALIGN(16); /* Exception table */ __start___ex_table = .; diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 86088213334a..dd57af413266 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -60,7 +60,7 @@ /* * Must define these before including other files, inline functions need them */ -#define LOCK_SECTION_NAME ".text.lock."KBUILD_BASENAME +#define LOCK_SECTION_NAME ".text..lock."KBUILD_BASENAME #define LOCK_SECTION_START(extra) \ ".subsection 1\n\t" \ -- GitLab From 819d67621edba0822352f7ae2a7ccb0387223675 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:49 +0100 Subject: [PATCH 048/842] Rename .text.page_aligned to .text..page_aligned. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/x86/kernel/acpi/wakeup_32.S | 2 +- arch/x86/kernel/vmlinux.lds.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S index 8ded418b0593..13ab720573e3 100644 --- a/arch/x86/kernel/acpi/wakeup_32.S +++ b/arch/x86/kernel/acpi/wakeup_32.S @@ -1,4 +1,4 @@ - .section .text.page_aligned + .section .text..page_aligned #include <linux/linkage.h> #include <asm/segment.h> #include <asm/page_types.h> diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 8b6bb4e7f5c5..f3d77d729d54 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -97,7 +97,7 @@ SECTIONS HEAD_TEXT #ifdef CONFIG_X86_32 . = ALIGN(PAGE_SIZE); - *(.text.page_aligned) + *(.text..page_aligned) #endif . = ALIGN(8); _stext = .; -- GitLab From 9bf59424862ef5c1ba5d7ad6699a0b474916c4e3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:51 +0100 Subject: [PATCH 049/842] Rename .text.startup to .text..startup. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/h8300/boot/compressed/head.S | 2 +- arch/h8300/boot/compressed/vmlinux.lds | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/h8300/boot/compressed/head.S b/arch/h8300/boot/compressed/head.S index 985a81a2435a..10e9a2d1cc6c 100644 --- a/arch/h8300/boot/compressed/head.S +++ b/arch/h8300/boot/compressed/head.S @@ -9,7 +9,7 @@ #define SRAM_START 0xff4000 - .section .text.startup + .section .text..startup .global startup startup: mov.l #SRAM_START+0x8000, sp diff --git a/arch/h8300/boot/compressed/vmlinux.lds b/arch/h8300/boot/compressed/vmlinux.lds index 65e2a0d1ae39..a0a3a0ed54ef 100644 --- a/arch/h8300/boot/compressed/vmlinux.lds +++ b/arch/h8300/boot/compressed/vmlinux.lds @@ -4,7 +4,7 @@ SECTIONS { __stext = . ; __text = .; - *(.text.startup) + *(.text..startup) *(.text) __etext = . ; } -- GitLab From 07b3bb1ef211fdf20eddcae902d1098788ea2f6e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:52 +0100 Subject: [PATCH 050/842] Rename .data.nosave to .data..nosave. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/s390/kernel/swsusp_asm64.S | 2 +- include/asm-generic/vmlinux.lds.h | 2 +- include/linux/init.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index 0c26cc1898ec..e5cd623cb025 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S @@ -261,7 +261,7 @@ restore_registers: lghi %r2,0 br %r14 - .section .data.nosave,"aw",@progbits + .section .data..nosave,"aw",@progbits .align 8 .Ldisabled_wait_31: .long 0x000a0000,0x00000000 diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 6f6da4f080f2..ea3660526e91 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -175,7 +175,7 @@ #define NOSAVE_DATA \ . = ALIGN(PAGE_SIZE); \ VMLINUX_SYMBOL(__nosave_begin) = .; \ - *(.data.nosave) \ + *(.data..nosave) \ . = ALIGN(PAGE_SIZE); \ VMLINUX_SYMBOL(__nosave_end) = .; diff --git a/include/linux/init.h b/include/linux/init.h index ab1d31f9352b..de994304e0bb 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -301,7 +301,7 @@ void __init parse_early_options(char *cmdline); #endif /* Data marked not to be saved by software suspend */ -#define __nosavedata __section(.data.nosave) +#define __nosavedata __section(.data..nosave) /* This means "can be init if no module support, otherwise module load may call it." */ -- GitLab From c273fb3b5d0490d3058f6cce77a92860671ee7b6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:53 +0100 Subject: [PATCH 051/842] Rename .data.init to .data..init. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/sparc/boot/btfixupprep.c | 2 +- arch/x86/kernel/setup_percpu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sparc/boot/btfixupprep.c b/arch/sparc/boot/btfixupprep.c index bbf91b9c3d39..e7f2940bd270 100644 --- a/arch/sparc/boot/btfixupprep.c +++ b/arch/sparc/boot/btfixupprep.c @@ -325,7 +325,7 @@ main1: (*rr)->next = NULL; } printf("! Generated by btfixupprep. Do not edit.\n\n"); - printf("\t.section\t\".data.init\",#alloc,#write\n\t.align\t4\n\n"); + printf("\t.section\t\".data..init\",#alloc,#write\n\t.align\t4\n\n"); printf("\t.global\t___btfixup_start\n___btfixup_start:\n\n"); for (i = 0; i < last; i++) { f = array + i; diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index 35abcb8b00e9..8c9f68ec97ab 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c @@ -241,7 +241,7 @@ void __init setup_per_cpu_areas(void) #endif #endif /* - * Up to this point, the boot CPU has been using .data.init + * Up to this point, the boot CPU has been using .init.data * area. Reload any changed state for the boot CPU. */ if (cpu == boot_cpu_id) -- GitLab From 2c31c341a827b99eef743753aa9adb917b9ea6db Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:54 +0100 Subject: [PATCH 052/842] Rename .data.initvect to .data..initvect. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/m68knommu/kernel/vmlinux.lds.S | 2 +- arch/m68knommu/platform/68360/head-ram.S | 2 +- arch/m68knommu/platform/68360/head-rom.S | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S index fd3df56fc458..a91b2713451d 100644 --- a/arch/m68knommu/kernel/vmlinux.lds.S +++ b/arch/m68knommu/kernel/vmlinux.lds.S @@ -57,7 +57,7 @@ SECTIONS { .romvec : { __rom_start = . ; _romvec = .; - *(.data.initvect) + *(.data..initvect) } > romvec #endif diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68knommu/platform/68360/head-ram.S index 2ef06242398b..8eb94fb6b971 100644 --- a/arch/m68knommu/platform/68360/head-ram.S +++ b/arch/m68knommu/platform/68360/head-ram.S @@ -280,7 +280,7 @@ _dprbase: * and then overwritten as needed. */ -.section ".data.initvect","awx" +.section ".data..initvect","awx" .long RAMEND /* Reset: Initial Stack Pointer - 0. */ .long _start /* Reset: Initial Program Counter - 1. */ .long buserr /* Bus Error - 2. */ diff --git a/arch/m68knommu/platform/68360/head-rom.S b/arch/m68knommu/platform/68360/head-rom.S index 62ecf4144b3b..97510e55b802 100644 --- a/arch/m68knommu/platform/68360/head-rom.S +++ b/arch/m68knommu/platform/68360/head-rom.S @@ -291,7 +291,7 @@ _dprbase: * and then overwritten as needed. */ -.section ".data.initvect","awx" +.section ".data..initvect","awx" .long RAMEND /* Reset: Initial Stack Pointer - 0. */ .long _start /* Reset: Initial Program Counter - 1. */ .long buserr /* Bus Error - 2. */ -- GitLab From a7df554ea095da4f60ff7f7b90a94c2df91942e4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:55 +0100 Subject: [PATCH 053/842] Rename .data.lock_aligned to .data..lock_aligned. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/parisc/include/asm/system.h | 2 +- arch/parisc/kernel/vmlinux.lds.S | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/parisc/include/asm/system.h b/arch/parisc/include/asm/system.h index d91357bca5b4..4bbb67355ace 100644 --- a/arch/parisc/include/asm/system.h +++ b/arch/parisc/include/asm/system.h @@ -174,7 +174,7 @@ static inline void set_eiem(unsigned long val) }) #ifdef CONFIG_SMP -# define __lock_aligned __attribute__((__section__(".data.lock_aligned"))) +# define __lock_aligned __attribute__((__section__(".data..lock_aligned"))) #endif #define arch_align_stack(x) (x) diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 33ec31ddb06d..d64a6bbec2aa 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -94,8 +94,8 @@ SECTIONS /* PA-RISC locks requires 16-byte alignment */ . = ALIGN(16); - .data.lock_aligned : { - *(.data.lock_aligned) + .data..lock_aligned : { + *(.data..lock_aligned) } /* End of data section */ -- GitLab From b6f4e451de78547a369a8dbb7bcb56c1919a6b79 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:56 +0100 Subject: [PATCH 054/842] Rename special text sections in arch/frv from .text.XXX to .text..XXX. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/frv/kernel/break.S | 2 +- arch/frv/kernel/entry.S | 2 +- arch/frv/kernel/head.S | 2 +- arch/frv/kernel/vmlinux.lds.S | 8 ++++---- arch/frv/mm/tlb-miss.S | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/frv/kernel/break.S b/arch/frv/kernel/break.S index c5388b756c72..cbb6958a3147 100644 --- a/arch/frv/kernel/break.S +++ b/arch/frv/kernel/break.S @@ -63,7 +63,7 @@ __break_trace_through_exceptions: # entry point for Break Exceptions/Interrupts # ############################################################################### - .section .text.break + .section .text..break .balign 4 .globl __entry_break __entry_break: diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S index 189397ec012a..63d579bf1c29 100644 --- a/arch/frv/kernel/entry.S +++ b/arch/frv/kernel/entry.S @@ -38,7 +38,7 @@ #define nr_syscalls ((syscall_table_size)/4) - .section .text.entry + .section .text..entry .balign 4 .macro LEDS val diff --git a/arch/frv/kernel/head.S b/arch/frv/kernel/head.S index b825ef3f2d54..e9a8cc63ac94 100644 --- a/arch/frv/kernel/head.S +++ b/arch/frv/kernel/head.S @@ -542,7 +542,7 @@ __head_end: .size _boot, .-_boot # provide a point for GDB to place a break - .section .text.start,"ax" + .section .text..start,"ax" .globl _start .balign 4 _start: diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S index 472eb8c8a1b4..8b973f3cc90e 100644 --- a/arch/frv/kernel/vmlinux.lds.S +++ b/arch/frv/kernel/vmlinux.lds.S @@ -57,10 +57,10 @@ SECTIONS _text = .; _stext = .; .text : { - *(.text.start) - *(.text.entry) - *(.text.break) - *(.text.tlbmiss) + *(.text..start) + *(.text..entry) + *(.text..break) + *(.text..tlbmiss) TEXT_TEXT SCHED_TEXT LOCK_TEXT diff --git a/arch/frv/mm/tlb-miss.S b/arch/frv/mm/tlb-miss.S index 7f392bc651a3..f3ac019bb18b 100644 --- a/arch/frv/mm/tlb-miss.S +++ b/arch/frv/mm/tlb-miss.S @@ -15,7 +15,7 @@ #include <asm/pgtable.h> #include <asm/spr-regs.h> - .section .text.tlbmiss + .section .text..tlbmiss .balign 4 .globl __entry_insn_mmu_miss -- GitLab From e9cfaa9f4c99be6d6bfe468daa1dd3a3f326bc52 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sat, 20 Feb 2010 01:03:57 +0100 Subject: [PATCH 055/842] Rename .text.start to .text..start. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- arch/mips/lasat/image/head.S | 2 +- arch/mips/lasat/image/romscript.normal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/lasat/image/head.S b/arch/mips/lasat/image/head.S index efb95f2609c2..e0ecda92c40a 100644 --- a/arch/mips/lasat/image/head.S +++ b/arch/mips/lasat/image/head.S @@ -1,7 +1,7 @@ #include <asm/lasat/head.h> .text - .section .text.start, "ax" + .section .text..start, "ax" .set noreorder .set mips3 diff --git a/arch/mips/lasat/image/romscript.normal b/arch/mips/lasat/image/romscript.normal index 988f8ad189cb..0864c963e188 100644 --- a/arch/mips/lasat/image/romscript.normal +++ b/arch/mips/lasat/image/romscript.normal @@ -4,7 +4,7 @@ SECTIONS { .text : { - *(.text.start) + *(.text..start) } /* Data in ROM */ -- GitLab From b59a12258460b3d019918719b1bd2563cf37ad9a Mon Sep 17 00:00:00 2001 From: FEJES Jozsef <fejes@joco.name> Date: Fri, 5 Mar 2010 18:19:36 +0100 Subject: [PATCH 056/842] kbuild: deb-pkg md5sums This patch creates the standard md5sums file for 'make deb-pkg' just like the dh_md5sums debhelper script. Signed-off-by: Jozsef Fejes <fejes@joco.name> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/package/builddeb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 8b357b0bd250..07f2fbde2abf 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -18,6 +18,8 @@ create_package() { cp debian/copyright "$pdir/usr/share/doc/$pname/" cp debian/changelog "$pdir/usr/share/doc/$pname/changelog.Debian" gzip -9 "$pdir/usr/share/doc/$pname/changelog.Debian" + sh -c "cd '$pdir'; find . -type f ! -path './DEBIAN/*' -printf '%P\0' \ + | xargs -r0 md5sum > DEBIAN/md5sums" # Fix ownership and permissions chown -R root:root "$pdir" -- GitLab From 1f2a144f5ab5e836b5ca8f67bd76b759fa947751 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@vyatta.com> Date: Mon, 22 Feb 2010 15:17:09 -0800 Subject: [PATCH 057/842] scripts: improve checkstack Cleanup checkstack script: * Turn on strict checking * Fix resulting error message because the declaration syntax was incorrect. * Remove incorrect and misleading use of prototype - prototype not required for this type of sort function because $a and $b are being used in this contex - if prototype was being used it should be for both arguments * Use closure for sort function Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Arjan van de Ven <arjan@infradead.org> Cc: Cong Wang <amwang@redhat.com> Cc: Michal Marek <mmarek@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/checkstack.pl | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index 14ee68e991dd..1afff6658a7d 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -21,6 +21,8 @@ # # TODO : Port to all architectures (one regex per arch) +use strict; + # check for arch # # $re is used for two matches: @@ -104,19 +106,11 @@ my (@stack, $re, $dre, $x, $xs); } } -sub bysize($) { - my ($asize, $bsize); - ($asize = $a) =~ s/.*: *(.*)$/$1/; - ($bsize = $b) =~ s/.*: *(.*)$/$1/; - $bsize <=> $asize -} - # # main() # my $funcre = qr/^$x* <(.*)>:$/; -my $func; -my $file, $lastslash; +my ($func, $file, $lastslash); while (my $line = <STDIN>) { if ($line =~ m/$funcre/) { @@ -173,4 +167,6 @@ while (my $line = <STDIN>) { } } -print sort bysize @stack; +# Sort output by size (last field) +print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack; + -- GitLab From 3da27157316cbcce326d56faa0a7a5cadc7ae507 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@vyatta.com> Date: Mon, 22 Feb 2010 15:17:12 -0800 Subject: [PATCH 058/842] checkincludes: fix perlcritic warnings Turn on strict checking. Use local file handles. Use three argument open. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Cc: Cong Wang <amwang@redhat.com> Cc: Michal Marek <mmarek@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/checkincludes.pl | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/scripts/checkincludes.pl b/scripts/checkincludes.pl index 676ddc07d6fa..97b2c6143fe4 100755 --- a/scripts/checkincludes.pl +++ b/scripts/checkincludes.pl @@ -11,6 +11,8 @@ # you do have real dups and do not have them under #ifdef's. You # could also just review the results. +use strict; + sub usage { print "Usage: checkincludes.pl [-r]\n"; print "By default we just warn of duplicates\n"; @@ -35,23 +37,24 @@ if ($#ARGV >= 1) { } } -foreach $file (@ARGV) { - open(FILE, $file) or die "Cannot open $file: $!.\n"; +foreach my $file (@ARGV) { + open(my $f, '<', $file) + or die "Cannot open $file: $!.\n"; my %includedfiles = (); my @file_lines = (); - while (<FILE>) { + while (<$f>) { if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) { ++$includedfiles{$1}; } push(@file_lines, $_); } - close(FILE); + close($f); if (!$remove) { - foreach $filename (keys %includedfiles) { + foreach my $filename (keys %includedfiles) { if ($includedfiles{$filename} > 1) { print "$file: $filename is included more than once.\n"; } @@ -59,27 +62,28 @@ foreach $file (@ARGV) { next; } - open(FILE,">$file") || die("Cannot write to $file: $!"); + open($f, '>', $file) + or die("Cannot write to $file: $!"); my $dups = 0; foreach (@file_lines) { if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) { - foreach $filename (keys %includedfiles) { + foreach my $filename (keys %includedfiles) { if ($1 eq $filename) { if ($includedfiles{$filename} > 1) { $includedfiles{$filename}--; $dups++; } else { - print FILE $_; + print {$f} $_; } } } } else { - print FILE $_; + print {$f} $_; } } if ($dups > 0) { print "$file: removed $dups duplicate includes\n"; } - close(FILE); + close($f); } -- GitLab From a208868fc0a90f62a91893b0193459de957c8d8e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@vyatta.com> Date: Mon, 22 Feb 2010 15:17:14 -0800 Subject: [PATCH 059/842] checkversion: perl cleanup Turn on strict checking. Use three arguement open Standard practice in perl is to use undef not zero for false Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Cc: Cong Wang <amwang@redhat.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Michal Marek <mmarek@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/checkversion.pl | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/scripts/checkversion.pl b/scripts/checkversion.pl index ec7d21161bdc..b444e89a0095 100755 --- a/scripts/checkversion.pl +++ b/scripts/checkversion.pl @@ -5,23 +5,22 @@ # including <linux/version.h> that don't need it. # Copyright (C) 2003, Randy Dunlap <rdunlap@xenotime.net> +use strict; + $| = 1; -my $debugging = 0; +my $debugging; -foreach $file (@ARGV) -{ +foreach my $file (@ARGV) { # Open this file. - open(FILE, $file) || die "Can't open $file: $!\n"; + open( my $f, '<', $file ) + or die "Can't open $file: $!\n"; # Initialize variables. - my $fInComment = 0; - my $fInString = 0; - my $fUseVersion = 0; + my ($fInComment, $fInString, $fUseVersion); my $iLinuxVersion = 0; - LINE: while ( <FILE> ) - { + while (<$f>) { # Strip comments. $fInComment && (s+^.*?\*/+ +o ? ($fInComment = 0) : next); m+/\*+o && (s+/\*.*?\*/+ +go, (s+/\*.*$+ +o && ($fInComment = 1))); @@ -43,8 +42,8 @@ foreach $file (@ARGV) # Look for uses: LINUX_VERSION_CODE, KERNEL_VERSION, UTS_RELEASE if (($_ =~ /LINUX_VERSION_CODE/) || ($_ =~ /\WKERNEL_VERSION/)) { $fUseVersion = 1; - last LINE if $iLinuxVersion; - } + last if $iLinuxVersion; + } } # Report used version IDs without include? @@ -67,5 +66,5 @@ foreach $file (@ARGV) } } - close(FILE); + close($f); } -- GitLab From 86d08e569f63a71a2d259507e335beea32b4d2aa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@vyatta.com> Date: Mon, 22 Feb 2010 15:17:18 -0800 Subject: [PATCH 060/842] namespace: perlcritic warnings Use local file handle not global. Make loop and other variables local in scope. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Cc: Hui Zhu <teawater@gmail.com> Cc: Cong Wang <amwang@redhat.com> Cc: Michal Marek <mmarek@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/namespace.pl | 65 ++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/scripts/namespace.pl b/scripts/namespace.pl index c6e88c652c2f..361d0f71184b 100755 --- a/scripts/namespace.pl +++ b/scripts/namespace.pl @@ -175,12 +175,11 @@ sub do_nm } if (! -e "$source.c" && ! -e "$source.S") { # No obvious source, exclude the object if it is conglomerate - if (! open(OBJDUMPDATA, "$objdump $basename|")) { - printf STDERR "$objdump $fullname failed $!\n"; - return; - } + open(my $objdumpdata, "$objdump $basename|") + or die "$objdump $fullname failed $!\n"; + my $comment; - while (<OBJDUMPDATA>) { + while (<$objdumpdata>) { chomp(); if (/^In archive/) { # Archives are always conglomerate @@ -190,18 +189,18 @@ sub do_nm next if (! /^[ 0-9a-f]{5,} /); $comment .= substr($_, 43); } - close(OBJDUMPDATA); + close($objdumpdata); + if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) { printf STDERR "No source file found for $fullname\n"; } return; } - if (! open(NMDATA, "$nm $basename|")) { - printf STDERR "$nm $fullname failed $!\n"; - return; - } + open (my $nmdata, "$nm $basename|") + or die "$nm $fullname failed $!\n"; + my @nmdata; - while (<NMDATA>) { + while (<$nmdata>) { chop; ($type, $name) = (split(/ +/, $_, 3))[1..2]; # Expected types @@ -268,7 +267,8 @@ sub do_nm } } } - close(NMDATA); + close($nmdata); + if ($#nmdata < 0) { if ( $fullname ne "lib/brlock.o" @@ -316,8 +316,7 @@ sub drop_def sub list_multiply_defined { - my ($name, $module); - foreach $name (keys(%def)) { + foreach my $name (keys(%def)) { if ($#{$def{$name}} > 0) { # Special case for cond_syscall if ($#{$def{$name}} == 1 && $name =~ /^sys_/ && @@ -333,8 +332,9 @@ sub list_multiply_defined &drop_def("arch/x86/kernel/vsyscall-sysenter_32.o", $name); next; } + printf "$name is multiply defined in :-\n"; - foreach $module (@{$def{$name}}) { + foreach my $module (@{$def{$name}}) { printf "\t$module\n"; } } @@ -343,12 +343,13 @@ sub list_multiply_defined sub resolve_external_references { - my ($object, $type, $name, $i, $j, $kstrtab, $ksymtab, $export); + my ($kstrtab, $ksymtab, $export); + printf "\n"; - foreach $object (keys(%nmdata)) { + foreach my $object (keys(%nmdata)) { my $nmdata = $nmdata{$object}; - for ($i = 0; $i <= $#{$nmdata}; ++$i) { - ($type, $name) = split(' ', $nmdata->[$i], 2); + for (my $i = 0; $i <= $#{$nmdata}; ++$i) { + my ($type, $name) = split(' ', $nmdata->[$i], 2); if ($type eq "U" || $type eq "w") { if (exists($def{$name}) || exists($ksymtab{$name})) { # add the owning object to the nmdata @@ -357,7 +358,7 @@ sub resolve_external_references $kstrtab = "R __kstrtab_$name"; $ksymtab = "R __ksymtab_$name"; $export = 0; - for ($j = 0; $j <= $#{$nmdata}; ++$j) { + for (my $j = 0; $j <= $#{$nmdata}; ++$j) { if ($nmdata->[$j] eq $kstrtab || $nmdata->[$j] eq $ksymtab) { $export = 1; @@ -424,11 +425,11 @@ sub resolve_external_references sub list_extra_externals { my %noref = (); - my ($name, @module, $module, $export); - foreach $name (keys(%def)) { + + foreach my $name (keys(%def)) { if (! exists($ref{$name})) { - @module = @{$def{$name}}; - foreach $module (@module) { + my @module = @{$def{$name}}; + foreach my $module (@module) { if (! exists($noref{$module})) { $noref{$module} = []; } @@ -438,16 +439,16 @@ sub list_extra_externals } if (%noref) { printf "\nExternally defined symbols with no external references\n"; - foreach $module (sort(keys(%noref))) { + foreach my $module (sort(keys(%noref))) { printf " $module\n"; foreach (sort(@{$noref{$module}})) { - if (exists($export{$_})) { - $export = " (export only)"; - } - else { - $export = ""; - } - printf " $_$export\n"; + my $export; + if (exists($export{$_})) { + $export = " (export only)"; + } else { + $export = ""; + } + printf " $_$export\n"; } } } -- GitLab From 9c49fd307a6cb2d3255f9441bce5b7cb08dff79e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@vyatta.com> Date: Mon, 22 Feb 2010 15:17:20 -0800 Subject: [PATCH 061/842] profile2linkerlist: fix perl warnings Turn on strict checking. Simplify code by using "unless" statement. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Acked-by: WANG Cong <amwang@redhat.com> Cc: Michal Marek <mmarek@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/profile2linkerlist.pl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/profile2linkerlist.pl b/scripts/profile2linkerlist.pl index cb4260ebdb91..6943fa7cc95b 100644 --- a/scripts/profile2linkerlist.pl +++ b/scripts/profile2linkerlist.pl @@ -7,15 +7,13 @@ # usage: # readprofile | sort -rn | perl profile2linkerlist.pl > functionlist # +use strict; while (<>) { my $line = $_; $_ =~ /\W*[0-9]+\W*([a-zA-Z\_0-9]+)\W*[0-9]+/; - if ( ($line =~ /unknown/) || ($line =~ /total/)) { - - } else { - print "*(.text.$1)\n"; - } + print "*(.text.$1)\n" + unless ($line =~ /unknown/) || ($line =~ /total/); } -- GitLab From 91416cfdf98bdbc828fd3e5ca7208beba5979d63 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@vyatta.com> Date: Mon, 22 Feb 2010 15:17:22 -0800 Subject: [PATCH 062/842] export_report: fix perl warnings Use local file handles, use three argument open. Don't modify arguments in perl grep (use sed instead) Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Acked-by: WANG Cong <amwang@redhat.com> Cc: Michal Marek <mmarek@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/export_report.pl | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/scripts/export_report.pl b/scripts/export_report.pl index 705b5ba7c152..04dce7c15f83 100644 --- a/scripts/export_report.pl +++ b/scripts/export_report.pl @@ -49,10 +49,10 @@ sub usage { } sub collectcfiles { - my @file = `cat .tmp_versions/*.mod | grep '.*\.ko\$'`; - @file = grep {s/\.ko/.mod.c/} @file; - chomp @file; - return @file; + my @file + = `cat .tmp_versions/*.mod | grep '.*\.ko\$' | sed s/\.ko$/.mod.c/`; + chomp @file; + return @file; } my (%SYMBOL, %MODULE, %opt, @allcfiles); @@ -71,37 +71,40 @@ if (not defined $opt{'k'}) { $opt{'k'} = "Module.symvers"; } -unless (open(MODULE_SYMVERS, $opt{'k'})) { - die "Sorry, cannot open $opt{'k'}: $!\n"; -} +open (my $module_symvers, '<', $opt{'k'}) + or die "Sorry, cannot open $opt{'k'}: $!\n"; if (defined $opt{'o'}) { - unless (open(OUTPUT_HANDLE, ">$opt{'o'}")) { - die "Sorry, cannot open $opt{'o'} $!\n"; - } - select OUTPUT_HANDLE; + open (my $out, '>', $opt{'o'}) + or die "Sorry, cannot open $opt{'o'} $!\n"; + + select $out; } + # # collect all the symbols and their attributes from the # Module.symvers file # -while ( <MODULE_SYMVERS> ) { +while ( <$module_symvers> ) { chomp; my (undef, $symbol, $module, $gpl) = split; $SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl]; } -close(MODULE_SYMVERS); +close($module_symvers); # # collect the usage count of each symbol. # foreach my $thismod (@allcfiles) { - unless (open(MODULE_MODULE, $thismod)) { - print "Sorry, cannot open $thismod: $!\n"; + my $module; + + unless (open ($module, '<', $thismod)) { + warn "Sorry, cannot open $thismod: $!\n"; next; } + my $state=0; - while ( <MODULE_MODULE> ) { + while ( <$module> ) { chomp; if ($state == 0) { $state = 1 if ($_ =~ /static const struct modversion_info/); @@ -124,7 +127,7 @@ foreach my $thismod (@allcfiles) { if ($state != 2) { print "WARNING:$thismod is not built with CONFIG_MODVERSION enabled\n"; } - close(MODULE_MODULE); + close($module); } print "\tThis file reports the exported symbols usage patterns by in-tree\n", -- GitLab From dbbe33e99f41a6f07e61dbce455964112d8ac72b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@vyatta.com> Date: Mon, 22 Feb 2010 15:17:24 -0800 Subject: [PATCH 063/842] headers_check: fix perl warnings According to PBP; best way practice is to use local reference for file handle and three argument open. Also perl prototypes are a mistake. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Acked-by: WANG Cong <amwang@redhat.com> Cc: Michal Marek <mmarek@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/headers_check.pl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl index db1dd7a549f2..50d6cfd1fa77 100644 --- a/scripts/headers_check.pl +++ b/scripts/headers_check.pl @@ -28,11 +28,12 @@ my $lineno = 0; my $filename; foreach my $file (@files) { - local *FH; $filename = $file; - open(FH, "<$filename") or die "$filename: $!\n"; + + open(my $fh, '<', $filename) + or die "$filename: $!\n"; $lineno = 0; - while ($line = <FH>) { + while ($line = <$fh>) { $lineno++; &check_include(); &check_asm_types(); @@ -40,7 +41,7 @@ foreach my $file (@files) { &check_declarations(); # Dropped for now. Too much noise &check_config(); } - close FH; + close $fh; } exit $ret; @@ -78,7 +79,7 @@ sub check_config } my $linux_asm_types; -sub check_asm_types() +sub check_asm_types { if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) { return; -- GitLab From bae4cecc09db9d472d71cb262de3c976147ad628 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@vyatta.com> Date: Mon, 22 Feb 2010 15:17:26 -0800 Subject: [PATCH 064/842] headers_install: use local file handles Better practice to use 3 arg open and local file handles. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Acked-by: WANG Cong <amwang@redhat.com> Cc: Michal Marek <mmarek@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/headers_install.pl | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/scripts/headers_install.pl b/scripts/headers_install.pl index b89ca2c58fdb..4ca3be3b2e50 100644 --- a/scripts/headers_install.pl +++ b/scripts/headers_install.pl @@ -23,13 +23,13 @@ my ($readdir, $installdir, $arch, @files) = @ARGV; my $unifdef = "scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__"; foreach my $file (@files) { - local *INFILE; - local *OUTFILE; my $tmpfile = "$installdir/$file.tmp"; - open(INFILE, "<$readdir/$file") - or die "$readdir/$file: $!\n"; - open(OUTFILE, ">$tmpfile") or die "$tmpfile: $!\n"; - while (my $line = <INFILE>) { + + open(my $in, '<', "$readdir/$file") + or die "$readdir/$file: $!\n"; + open(my $out, '>', $tmpfile) + or die "$tmpfile: $!\n"; + while (my $line = <$in>) { $line =~ s/([\s(])__user\s/$1/g; $line =~ s/([\s(])__force\s/$1/g; $line =~ s/([\s(])__iomem\s/$1/g; @@ -39,10 +39,11 @@ foreach my $file (@files) { $line =~ s/(^|\s)(inline)\b/$1__$2__/g; $line =~ s/(^|\s)(asm)\b(\s|[(]|$)/$1__$2__$3/g; $line =~ s/(^|\s|[(])(volatile)\b(\s|[(]|$)/$1__$2__$3/g; - printf OUTFILE "%s", $line; + printf {$out} "%s", $line; } - close OUTFILE; - close INFILE; + close $out; + close $in; + system $unifdef . " $tmpfile > $installdir/$file"; unlink $tmpfile; } -- GitLab From a6c366324cacd5f71107dd01362b995a1c67b1ad Mon Sep 17 00:00:00 2001 From: Michal Marek <mmarek@suse.cz> Date: Mon, 8 Mar 2010 10:07:12 +0100 Subject: [PATCH 065/842] kbuild: Do not unnecessarily regenerate modules.builtin Only regenerate it if the configuration has changed. Also, do this after the modules build to fix errors with some weird Makefiles that are generated during build. Reported-by: Eric Miao <eric.y.miao@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Makefile | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 2e74a68878c7..160cadadc471 100644 --- a/Makefile +++ b/Makefile @@ -882,9 +882,6 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; PHONY += $(vmlinux-dirs) $(vmlinux-dirs): prepare scripts $(Q)$(MAKE) $(build)=$@ -ifdef CONFIG_MODULES - $(Q)$(MAKE) $(modbuiltin)=$@ -endif # Build the kernel release string # @@ -1089,7 +1086,7 @@ ifdef CONFIG_MODULES # By default, build modules as well -all: modules +all: modules modules.builtin # Build modules # @@ -1100,11 +1097,16 @@ all: modules PHONY += modules modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order - $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.builtin) > $(objtree)/modules.builtin @$(kecho) ' Building modules, stage 2.'; $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild +modules.builtin: $(vmlinux-dirs:%=%/modules.builtin) + $(Q)$(AWK) '!x[$$0]++' $^ > $(objtree)/modules.builtin + +%/modules.builtin: include/config/auto.conf | modules + $(Q)$(MAKE) $(modbuiltin)=$* + # Target to prepare building external modules PHONY += modules_prepare -- GitLab From e93bc1a0cab3e54e3c1947e01c8e73892e35630d Mon Sep 17 00:00:00 2001 From: Michal Marek <mmarek@suse.cz> Date: Mon, 8 Mar 2010 10:26:22 +0100 Subject: [PATCH 066/842] Revert "kbuild: specify absolute paths for cscope" This reverts commit eb8f844c0a41c4529a7d06b7801296eca9ae67aa. Ian Campbell writes: > I keep my kernel source tree on a more powerful build box where I run my > builds etc (including "make cscope") but run my editor from my > workstation with an NFS mount to the source. This worked fine for me > using relative paths for cscope. Using absolute paths in cscope breaks > this previously working setup because the root path is not the same on > both systems. I guess this is similar to moving the source tree around. > > Without wanting to start a flamewar it really sounds to me like we are > working around a vim (or cscope) bug here, emacs with cscope bindings > works fine in this configuration. Given that absolute paths can be forced by make O=. cscope, change the default back to relative paths. Ian Campbell <ijc@hellion.org.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/tags.sh | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/tags.sh b/scripts/tags.sh index 868b4c8fc25f..8509bb512935 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -18,6 +18,8 @@ ignore="( -name SCCS -o -name BitKeeper -o -name .svn -o \ -prune -o" # Do not use full path if we do not use O=.. builds +# Use make O=. {tags|cscope} +# to force full paths for a non-O= build if [ "${KBUILD_SRC}" = "" ]; then tree= else @@ -108,13 +110,7 @@ all_defconfigs() docscope() { - # always use absolute paths for cscope, as recommended by cscope - # upstream - case "$tree" in - /*) ;; - *) tree=$PWD/$tree ;; - esac - (cd /; echo \-k; echo \-q; all_sources) > cscope.files + (echo \-k; echo \-q; all_sources) > cscope.files cscope -b -f cscope.out } -- GitLab From 73d1393eb8507ed5fd7f8e696f6b1ecc18035ebe Mon Sep 17 00:00:00 2001 From: Michal Marek <mmarek@suse.cz> Date: Wed, 10 Mar 2010 12:28:58 +0100 Subject: [PATCH 067/842] kbuild: Generate modules.builtin in make modules_install The previous approach didn't work if one did make modules && make modules_install Add modules.builtin as dependency of _modinst_, which is the target that actually needs the file. Reported-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 160cadadc471..b98943a466c5 100644 --- a/Makefile +++ b/Makefile @@ -1086,7 +1086,7 @@ ifdef CONFIG_MODULES # By default, build modules as well -all: modules modules.builtin +all: modules # Build modules # @@ -1104,7 +1104,7 @@ modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin: $(vmlinux-dirs:%=%/modules.builtin) $(Q)$(AWK) '!x[$$0]++' $^ > $(objtree)/modules.builtin -%/modules.builtin: include/config/auto.conf | modules +%/modules.builtin: include/config/auto.conf $(Q)$(MAKE) $(modbuiltin)=$* @@ -1117,7 +1117,7 @@ PHONY += modules_install modules_install: _modinst_ _modinst_post PHONY += _modinst_ -_modinst_: +_modinst_: modules.builtin @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \ echo "Warning: you may need to install module-init-tools"; \ echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\ -- GitLab From 2d74b2c62cf8867d0762f6e6b5ed8906cb6a745f Mon Sep 17 00:00:00 2001 From: Wu Zhangjin <wuzhangjin@gmail.com> Date: Thu, 11 Mar 2010 17:42:14 +0800 Subject: [PATCH 068/842] scripts/Makefile.lib: Align the output of LZO The output of LZO is not aligned with the other output: ... CC drivers/usb/mon/usbmon.mod.o LZO arch/mips/boot/compressed/vmlinux.lzo ... This patch fixes it. Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/Makefile.lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index f9bdf264473d..f3ccdb1b302b 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -241,7 +241,7 @@ cmd_lzma = (cat $(filter-out FORCE,$^) | \ lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ (rm -f $@ ; false) -quiet_cmd_lzo = LZO $@ +quiet_cmd_lzo = LZO $@ cmd_lzo = (cat $(filter-out FORCE,$^) | \ lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ (rm -f $@ ; false) -- GitLab From 1dcd81002453f9f22c6c4fd6c3c7d8f1c7c891fa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@vyatta.com> Date: Mon, 8 Mar 2010 08:24:27 -0800 Subject: [PATCH 069/842] headerdep: perlcritic warning Minor perlcritic warning: headerdep.pl: "return" statement with explicit "undef" at line 84, column 2. See page 199 of PBP. (Severity: 5) The rationale according to PBP is that an explicit return of undef (contrary to most people's expectations) doesn't always evaluate as false. It has to with the fact that perl return value depends on context the function is called. If function is used in list context, the appropriate return value for false is an empty list; whereas in scalar context the return value for false is undefined. By just using a "return" both cases are handled. In the context of a trivial script this doesn't matter. But one script may be cut-paste into later code (most people like me only know 50% of perl), that is why perlcritic always complains Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/headerdep.pl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/headerdep.pl b/scripts/headerdep.pl index b7f6c560e24d..8dd019bc5a73 100755 --- a/scripts/headerdep.pl +++ b/scripts/headerdep.pl @@ -80,8 +80,7 @@ sub search { my $path = "$i/$filename"; return $path if -f $path; } - - return undef; + return; } sub parse_all { -- GitLab From 52b80025ebaa992688959b4cb2cd86c7e805b70f Mon Sep 17 00:00:00 2001 From: Philipp Kohlbecher <xt28@gmx.de> Date: Wed, 17 Mar 2010 19:52:12 +0100 Subject: [PATCH 070/842] .gitignore: ignore *.lzo files Ignore files compressed with lzop. Signed-off-by: Philipp Kohlbecher <xt28@gmx.de> Signed-off-by: Michal Marek <mmarek@suse.cz> --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index de6344e15706..0a5cf708c06d 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ modules.builtin *.gz *.bz2 *.lzma +*.lzo *.patch *.gcno -- GitLab From da6df879b9f88d2224174a9e4e76dc0e42e47ebc Mon Sep 17 00:00:00 2001 From: Li Zefan <lizf@cn.fujitsu.com> Date: Fri, 19 Mar 2010 14:57:47 +0800 Subject: [PATCH 071/842] kconfig: recalc symbol value before showing search results A symbol's value won't be recalc-ed until we save config file or enter the menu where the symbol sits. So If I enable OPTIMIZE_FOR_SIZE, and search FUNCTION_GRAPH_TRACER: Symbol: FUNCTION_GRAPH_TRACER [=y] Prompt: Kernel Function Graph Tracer Defined at kernel/trace/Kconfig:140 Depends on: ... [=y] && (!X86_32 [=y] || !CC_OPTIMIZE_FOR_SIZE [=y]) ... From the dependency it should result in FUNCTION_GRAPH_TRACER=n, but it still shows FUNCTION_GRAPH_TRACER=y. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/symbol.c | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 9ee3923117ee..2e7a048e0cfc 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -755,6 +755,7 @@ struct symbol **sym_re_search(const char *pattern) return NULL; } } + sym_calc_value(sym); sym_arr[cnt++] = sym; } if (sym_arr) -- GitLab From b83419363eff1535309df97a4bf319c42d900a9c Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Date: Mon, 22 Mar 2010 16:49:32 -0600 Subject: [PATCH 072/842] kbuild: Include gen_initramfs_list.sh and the file list in the .d file Expand the dependency set used for the initrd to include the CONFIG_INITRAMFS_SOURCE file and the generator script itself. Otherwise changing the initramfs file list does not rebuild the CPIO. Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/gen_initramfs_list.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh index 76af5f9623e3..f3b5c05ced40 100644 --- a/scripts/gen_initramfs_list.sh +++ b/scripts/gen_initramfs_list.sh @@ -202,6 +202,7 @@ input_file() { print_mtime "$1" >> ${output} cat "$1" >> ${output} else + echo "$1 \\" cat "$1" | while read type dir file perm ; do if [ "$type" == "file" ]; then echo "$file \\"; @@ -231,7 +232,7 @@ arg="$1" case "$arg" in "-l") # files included in initramfs - used by kbuild dep_list="list_" - echo "deps_initramfs := \\" + echo "deps_initramfs := $0 \\" shift ;; "-o") # generate compressed cpio image named $1 -- GitLab From 7926c09dea682be6f3b2e42f16c50d8554c6bbdc Mon Sep 17 00:00:00 2001 From: Jan III Sobieski <jan3sobi3ski@gmail.com> Date: Sun, 28 Mar 2010 15:38:31 +0200 Subject: [PATCH 073/842] add random binaries to .gitignore Signed-off-by: Jan III Sobieski <jan3sobi3ski@gmail.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Documentation/.gitignore | 7 +++++++ arch/x86/.gitignore | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 Documentation/.gitignore create mode 100644 arch/x86/.gitignore diff --git a/Documentation/.gitignore b/Documentation/.gitignore new file mode 100644 index 000000000000..bcd907b4141f --- /dev/null +++ b/Documentation/.gitignore @@ -0,0 +1,7 @@ +filesystems/dnotify_test +laptops/dslm +timers/hpet_example +vm/hugepage-mmap +vm/hugepage-shm +vm/map_hugetlb + diff --git a/arch/x86/.gitignore b/arch/x86/.gitignore new file mode 100644 index 000000000000..028079065af6 --- /dev/null +++ b/arch/x86/.gitignore @@ -0,0 +1,3 @@ +boot/compressed/vmlinux +tools/test_get_len + -- GitLab From 4280eae0990190d190dfa7dab9bca480215d5b19 Mon Sep 17 00:00:00 2001 From: Li Zefan <lizf@cn.fujitsu.com> Date: Wed, 14 Apr 2010 11:44:05 +0800 Subject: [PATCH 074/842] kconfig: some small fixes - fix a typo in documentation - fix a typo in a printk on error - fix comments in dialog_inputbox() Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Documentation/kbuild/kconfig-language.txt | 2 +- scripts/kconfig/lxdialog/inputbox.c | 4 ++-- scripts/kconfig/menu.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt index c412c245848f..b472e4e0ba67 100644 --- a/Documentation/kbuild/kconfig-language.txt +++ b/Documentation/kbuild/kconfig-language.txt @@ -181,7 +181,7 @@ Expressions are listed in decreasing order of precedence. (7) Returns the result of max(/expr/, /expr/). An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2 -respectively for calculations). A menu entry becomes visible when it's +respectively for calculations). A menu entry becomes visible when its expression evaluates to 'm' or 'y'. There are two types of symbols: constant and non-constant symbols. diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c index 616c60138183..dd8e587c50e2 100644 --- a/scripts/kconfig/lxdialog/inputbox.c +++ b/scripts/kconfig/lxdialog/inputbox.c @@ -180,7 +180,7 @@ do_resize: case KEY_LEFT: switch (button) { case -1: - button = 1; /* Indicates "Cancel" button is selected */ + button = 1; /* Indicates "Help" button is selected */ print_buttons(dialog, height, width, 1); break; case 0: @@ -204,7 +204,7 @@ do_resize: print_buttons(dialog, height, width, 0); break; case 0: - button = 1; /* Indicates "Cancel" button is selected */ + button = 1; /* Indicates "Help" button is selected */ print_buttons(dialog, height, width, 1); break; case 1: diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 21bfb3dbc87a..62e3f15ede0f 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -197,7 +197,7 @@ static void sym_check_prop(struct symbol *sym) if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && prop->expr->type != E_SYMBOL) prop_warn(prop, - "default for config symbol '%'" + "default for config symbol '%s'" " must be a single symbol", sym->name); break; case P_SELECT: -- GitLab From c6ccc30fd7870879981de03feeec61029754b0ea Mon Sep 17 00:00:00 2001 From: Li Zefan <lizf@cn.fujitsu.com> Date: Wed, 14 Apr 2010 11:44:20 +0800 Subject: [PATCH 075/842] kconfig: fix zconfdump() zconfdump(), which is used for debugging, can't recognize P_SELECT, P_RANGE and P_MENU (if associated with a symbol, aka "menuconfig"), and output something like this: config X86 boolean default y unknown prop 6! unknown prop 6! unknown prop 6! ... Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/zconf.tab.c_shipped | 21 +++++++++++++++++---- scripts/kconfig/zconf.y | 21 +++++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped index 7df3264c3f3d..32a9eefd842c 100644 --- a/scripts/kconfig/zconf.tab.c_shipped +++ b/scripts/kconfig/zconf.tab.c_shipped @@ -2336,9 +2336,9 @@ static void print_symbol(FILE *out, struct menu *menu) struct property *prop; if (sym_is_choice(sym)) - fprintf(out, "choice\n"); + fprintf(out, "\nchoice\n"); else - fprintf(out, "config %s\n", sym->name); + fprintf(out, "\nconfig %s\n", sym->name); switch (sym->type) { case S_BOOLEAN: fputs(" boolean\n", out); @@ -2384,6 +2384,21 @@ static void print_symbol(FILE *out, struct menu *menu) case P_CHOICE: fputs(" #choice value\n", out); break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; default: fprintf(out, " unknown prop %d!\n", prop->type); break; @@ -2395,7 +2410,6 @@ static void print_symbol(FILE *out, struct menu *menu) menu->help[len] = 0; fprintf(out, " help\n%s\n", menu->help); } - fputc('\n', out); } void zconfdump(FILE *out) @@ -2428,7 +2442,6 @@ void zconfdump(FILE *out) expr_fprint(prop->visible.expr, out); fputc('\n', out); } - fputs("\n", out); } if (menu->list) diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index 258f16608ec0..23dfd3baa7a1 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -591,9 +591,9 @@ static void print_symbol(FILE *out, struct menu *menu) struct property *prop; if (sym_is_choice(sym)) - fprintf(out, "choice\n"); + fprintf(out, "\nchoice\n"); else - fprintf(out, "config %s\n", sym->name); + fprintf(out, "\nconfig %s\n", sym->name); switch (sym->type) { case S_BOOLEAN: fputs(" boolean\n", out); @@ -639,6 +639,21 @@ static void print_symbol(FILE *out, struct menu *menu) case P_CHOICE: fputs(" #choice value\n", out); break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; default: fprintf(out, " unknown prop %d!\n", prop->type); break; @@ -650,7 +665,6 @@ static void print_symbol(FILE *out, struct menu *menu) menu->help[len] = 0; fprintf(out, " help\n%s\n", menu->help); } - fputc('\n', out); } void zconfdump(FILE *out) @@ -683,7 +697,6 @@ void zconfdump(FILE *out) expr_fprint(prop->visible.expr, out); fputc('\n', out); } - fputs("\n", out); } if (menu->list) -- GitLab From 2944235430c37970f82ad57b8ead343ee6065004 Mon Sep 17 00:00:00 2001 From: Li Zefan <lizf@cn.fujitsu.com> Date: Wed, 14 Apr 2010 11:44:34 +0800 Subject: [PATCH 076/842] gconfig: remove dbg_print_ptype() and dbg_print_stype() Just use sym_get_type() and prop_get_type_name(). Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/gconf.c | 67 +++-------------------------------------- 1 file changed, 4 insertions(+), 63 deletions(-) diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index 65464366fe38..80fe9ca2cbb3 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -76,36 +76,7 @@ static void conf_changed(void); /* Helping/Debugging Functions */ - -const char *dbg_print_stype(int val) -{ - static char buf[256]; - - bzero(buf, 256); - - if (val == S_UNKNOWN) - strcpy(buf, "unknown"); - if (val == S_BOOLEAN) - strcpy(buf, "boolean"); - if (val == S_TRISTATE) - strcpy(buf, "tristate"); - if (val == S_INT) - strcpy(buf, "int"); - if (val == S_HEX) - strcpy(buf, "hex"); - if (val == S_STRING) - strcpy(buf, "string"); - if (val == S_OTHER) - strcpy(buf, "other"); - -#ifdef DEBUG - printf("%s", buf); -#endif - - return buf; -} - -const char *dbg_print_flags(int val) +const char *dbg_sym_flags(int val) { static char buf[256]; @@ -131,40 +102,10 @@ const char *dbg_print_flags(int val) strcat(buf, "auto/"); buf[strlen(buf) - 1] = '\0'; -#ifdef DEBUG - printf("%s", buf); -#endif - - return buf; -} - -const char *dbg_print_ptype(int val) -{ - static char buf[256]; - - bzero(buf, 256); - - if (val == P_UNKNOWN) - strcpy(buf, "unknown"); - if (val == P_PROMPT) - strcpy(buf, "prompt"); - if (val == P_COMMENT) - strcpy(buf, "comment"); - if (val == P_MENU) - strcpy(buf, "menu"); - if (val == P_DEFAULT) - strcpy(buf, "default"); - if (val == P_CHOICE) - strcpy(buf, "choice"); - -#ifdef DEBUG - printf("%s", buf); -#endif return buf; } - void replace_button_icon(GladeXML * xml, GdkDrawable * window, GtkStyle * style, gchar * btn_name, gchar ** xpm) { @@ -1469,12 +1410,12 @@ static void display_tree(struct menu *menu) #ifdef DEBUG printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : ""); - dbg_print_ptype(ptype); + printf("%s", prop_get_type_name(ptype)); printf(" | "); if (sym) { - dbg_print_stype(sym->type); + printf("%s", sym_type_name(sym->type)); printf(" | "); - dbg_print_flags(sym->flags); + printf("%s", dbg_sym_flags(sym->flags)); printf("\n"); } else printf("\n"); -- GitLab From 7b5d87215b38359ecadf7a69575b11e140a00484 Mon Sep 17 00:00:00 2001 From: Li Zefan <lizf@cn.fujitsu.com> Date: Wed, 14 Apr 2010 11:44:51 +0800 Subject: [PATCH 077/842] gconfig: remove show_debug option This option is a no-op, so remove it. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/gconf.c | 9 --------- scripts/kconfig/gconf.glade | 10 ---------- 2 files changed, 19 deletions(-) diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index 80fe9ca2cbb3..c6aa5a5948a1 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -35,7 +35,6 @@ static gboolean show_name = TRUE; static gboolean show_range = TRUE; static gboolean show_value = TRUE; static gboolean show_all = FALSE; -static gboolean show_debug = FALSE; static gboolean resizeable = FALSE; GtkWidget *main_wnd = NULL; @@ -647,14 +646,6 @@ on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data) } -void -on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data) -{ - show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active; - update_tree(&rootmenu, NULL); -} - - void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) { GtkWidget *dialog; diff --git a/scripts/kconfig/gconf.glade b/scripts/kconfig/gconf.glade index b1c86c19292c..909f5a457ac0 100644 --- a/scripts/kconfig/gconf.glade +++ b/scripts/kconfig/gconf.glade @@ -200,16 +200,6 @@ </widget> </child> - <child> - <widget class="GtkCheckMenuItem" id="show_debug_info1"> - <property name="visible">True</property> - <property name="tooltip" translatable="yes">Show masked options</property> - <property name="label" translatable="yes">Show _debug info</property> - <property name="use_underline">True</property> - <property name="active">False</property> - <signal name="activate" handler="on_show_debug_info1_activate"/> - </widget> - </child> </widget> </child> </widget> -- GitLab From 22c7eca61e51296643bb0a379fc726fda8f3b015 Mon Sep 17 00:00:00 2001 From: Li Zefan <lizf@cn.fujitsu.com> Date: Wed, 14 Apr 2010 11:46:02 +0800 Subject: [PATCH 078/842] menuconfig: add support to show hidden options which have prompts Usage: Press <Z> to show all config symbols which have prompts. Quote Tim Bird: | I've been bitten by this numerous times. I most often | use ftrace on ARM, but when I go back to x86, I almost | always go through a sequence of searching for the | function graph tracer in the menus, then realizing it's | completely missing until I disable CC_OPTIMIZE_FOR_SIZE. | | Is there any way to have the menu item appear, but be | unsettable unless the SIZE option is disabled? I'm | not a Kconfig guru... I myself found this useful too. For example, I need to test ftrace/tracing and want to be sure all the tracing features are enabled, so I enter the "Tracers" menu, and press <Z> to see if there is any config hidden. I also noticed gconfig and xconfig have a button "Show all options", but that's a bit too much, and I think normally what we are not interested in those configs which have no prompt thus can't be changed by users. Exmaple: --- Tracers -*- Kernel Function Tracer - - Kernel Function Graph Tracer [*] Interrupts-off Latency Tracer - - Preemption-off Latency Tracer [*] Sysprof Tracer Here you can see 2 tracers are not selectable, and then can find out how to make them selectable. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/lkc_proto.h | 3 ++- scripts/kconfig/lxdialog/menubox.c | 22 +++++++++++----------- scripts/kconfig/mconf.c | 22 ++++++++++++++++++---- scripts/kconfig/menu.c | 10 ++++++++++ 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 41e652a8d1f6..7cadcad8233b 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -11,7 +11,8 @@ P(conf_set_changed_callback, void,(void (*fn)(void))); /* menu.c */ P(rootmenu,struct menu,); -P(menu_is_visible,bool,(struct menu *menu)); +P(menu_is_visible, bool, (struct menu *menu)); +P(menu_has_prompt, bool, (struct menu *menu)); P(menu_get_prompt,const char *,(struct menu *menu)); P(menu_get_root_menu,struct menu *,(struct menu *menu)); P(menu_get_parent_menu,struct menu *,(struct menu *menu)); diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c index fa9d633f293c..1d604738fa13 100644 --- a/scripts/kconfig/lxdialog/menubox.c +++ b/scripts/kconfig/lxdialog/menubox.c @@ -383,6 +383,10 @@ do_resize: case 'n': case 'm': case '/': + case 'h': + case '?': + case 'z': + case '\n': /* save scroll info */ *s_scroll = scroll; delwin(menu); @@ -390,8 +394,10 @@ do_resize: item_set(scroll + choice); item_set_selected(1); switch (key) { + case 'h': + case '?': + return 2; case 's': - return 3; case 'y': return 3; case 'n': @@ -402,18 +408,12 @@ do_resize: return 6; case '/': return 7; + case 'z': + return 8; + case '\n': + return button; } return 0; - case 'h': - case '?': - button = 2; - case '\n': - *s_scroll = scroll; - delwin(menu); - delwin(dialog); - item_set(scroll + choice); - item_set_selected(1); - return button; case 'e': case 'x': key = KEY_ESC; diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index a4a75190457c..2c83d3234d30 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -67,13 +67,15 @@ static const char mconf_readme[] = N_( " there is a delayed response which you may find annoying.\n" "\n" " Also, the <TAB> and cursor keys will cycle between <Select>,\n" -" <Exit> and <Help>\n" +" <Exit> and <Help>.\n" "\n" "o To get help with an item, use the cursor keys to highlight <Help>\n" -" and Press <ENTER>.\n" +" and press <ENTER>.\n" "\n" " Shortcut: Press <H> or <?>.\n" "\n" +"o To show hidden options, press <Z>.\n" +"\n" "\n" "Radiolists (Choice lists)\n" "-----------\n" @@ -272,6 +274,7 @@ static int indent; static struct menu *current_menu; static int child_count; static int single_menu_mode; +static int show_all_options; static void conf(struct menu *menu); static void conf_choice(struct menu *menu); @@ -346,8 +349,16 @@ static void build_conf(struct menu *menu) int type, tmp, doint = 2; tristate val; char ch; - - if (!menu_is_visible(menu)) + bool visible; + + /* + * note: menu_is_visible() has side effect that it will + * recalc the value of the symbol. + */ + visible = menu_is_visible(menu); + if (show_all_options && !menu_has_prompt(menu)) + return; + else if (!show_all_options && !visible) return; sym = menu->sym; @@ -606,6 +617,9 @@ static void conf(struct menu *menu) case 7: search_conf(); break; + case 8: + show_all_options = !show_all_options; + break; } } } diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 62e3f15ede0f..203632cc30bd 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -390,6 +390,13 @@ void menu_finalize(struct menu *parent) } } +bool menu_has_prompt(struct menu *menu) +{ + if (!menu->prompt) + return false; + return true; +} + bool menu_is_visible(struct menu *menu) { struct menu *child; @@ -398,6 +405,7 @@ bool menu_is_visible(struct menu *menu) if (!menu->prompt) return false; + sym = menu->sym; if (sym) { sym_calc_value(sym); @@ -407,12 +415,14 @@ bool menu_is_visible(struct menu *menu) if (visible != no) return true; + if (!sym || sym_get_tristate_value(menu->sym) == no) return false; for (child = menu->list; child; child = child->next) if (menu_is_visible(child)) return true; + return false; } -- GitLab From 06f9a55cf72b6aa19b4206a05d6f9af6fa9648ea Mon Sep 17 00:00:00 2001 From: Li Zefan <lizf@cn.fujitsu.com> Date: Wed, 14 Apr 2010 11:46:24 +0800 Subject: [PATCH 079/842] gconfig: add support to show hidden options that have prompts There's a button in gconfig to "Show all options", but I think normally we are not interested in those configs which have no prompt and thus can't be changed, so here I add a new button to show hidden options which have prompts. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/gconf.c | 47 ++++++++++++++++++++++++++++++------- scripts/kconfig/gconf.glade | 28 ++++++++++++++++++++-- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index c6aa5a5948a1..bef10411837f 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -30,12 +30,16 @@ enum { SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW }; +enum { + OPT_NORMAL, OPT_ALL, OPT_PROMPT +}; + static gint view_mode = FULL_VIEW; static gboolean show_name = TRUE; static gboolean show_range = TRUE; static gboolean show_value = TRUE; -static gboolean show_all = FALSE; static gboolean resizeable = FALSE; +static int opt_mode = OPT_NORMAL; GtkWidget *main_wnd = NULL; GtkWidget *tree1_w = NULL; // left frame @@ -637,12 +641,29 @@ void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data) void -on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data) +on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_NORMAL; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + + +void +on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data) { - show_all = GTK_CHECK_MENU_ITEM(menuitem)->active; + opt_mode = OPT_ALL; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + +void +on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_PROMPT; gtk_tree_store_clear(tree2); - display_tree(&rootmenu); // instead of update_tree to speed-up + display_tree(&rootmenu); /* instead of update_tree to speed-up */ } @@ -1095,7 +1116,10 @@ static gchar **fill_row(struct menu *menu) g_strdup_printf("%s %s", _(menu_get_prompt(menu)), sym && sym_has_value(sym) ? "(NEW)" : ""); - if (show_all && !menu_is_visible(menu)) + if (opt_mode == OPT_ALL && !menu_is_visible(menu)) + row[COL_COLOR] = g_strdup("DarkGray"); + else if (opt_mode == OPT_PROMPT && + menu_has_prompt(menu) && !menu_is_visible(menu)) row[COL_COLOR] = g_strdup("DarkGray"); else row[COL_COLOR] = g_strdup("Black"); @@ -1318,16 +1342,19 @@ static void update_tree(struct menu *src, GtkTreeIter * dst) menu2 ? menu_get_prompt(menu2) : "nil"); #endif - if (!menu_is_visible(child1) && !show_all) { // remove node + if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) || + (opt_mode == OPT_PROMPT && !menu_has_prompt(child1))) { + + /* remove node */ if (gtktree_iter_find_node(dst, menu1) != NULL) { memcpy(&tmp, child2, sizeof(GtkTreeIter)); valid = gtk_tree_model_iter_next(model2, child2); gtk_tree_store_remove(tree2, &tmp); if (!valid) - return; // next parent + return; /* next parent */ else - goto reparse; // next child + goto reparse; /* next child */ } else continue; } @@ -1396,7 +1423,9 @@ static void display_tree(struct menu *menu) && (tree == tree2)) continue; - if (menu_is_visible(child) || show_all) + if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) || + (opt_mode == OPT_PROMPT && menu_has_prompt(child)) || + (opt_mode == OPT_ALL)) place_node(child, fill_row(child)); #ifdef DEBUG printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); diff --git a/scripts/kconfig/gconf.glade b/scripts/kconfig/gconf.glade index 909f5a457ac0..d52b0a75d824 100644 --- a/scripts/kconfig/gconf.glade +++ b/scripts/kconfig/gconf.glade @@ -190,13 +190,37 @@ </child> <child> - <widget class="GtkCheckMenuItem" id="show_all_options1"> + <widget class="GtkRadioMenuItem" id="set_option_mode1"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Show normal options</property> + <property name="label" translatable="yes">Show normal options</property> + <property name="use_underline">True</property> + <property name="active">True</property> + <signal name="activate" handler="on_set_option_mode1_activate"/> + </widget> + </child> + + <child> + <widget class="GtkRadioMenuItem" id="set_option_mode2"> <property name="visible">True</property> <property name="tooltip" translatable="yes">Show all options</property> <property name="label" translatable="yes">Show all _options</property> <property name="use_underline">True</property> <property name="active">False</property> - <signal name="activate" handler="on_show_all_options1_activate"/> + <property name="group">set_option_mode1</property> + <signal name="activate" handler="on_set_option_mode2_activate"/> + </widget> + </child> + + <child> + <widget class="GtkRadioMenuItem" id="set_option_mode3"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Show all options with prompts</property> + <property name="label" translatable="yes">Show all prompt options</property> + <property name="use_underline">True</property> + <property name="active">False</property> + <property name="group">set_option_mode1</property> + <signal name="activate" handler="on_set_option_mode3_activate"/> </widget> </child> -- GitLab From f35d77645808d1b890abb1a36260bf228854259e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Tue, 27 Apr 2010 16:24:21 +0200 Subject: [PATCH 080/842] cris: push down BKL into some device drivers A number of cris specific device drivers still use the locked ->ioctl operation. Convert them to unlocked_ioctl with explicit lock_kernel calls. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com> --- arch/cris/arch-v10/drivers/ds1302.c | 20 +++++++++++++++----- arch/cris/arch-v10/drivers/pcf8563.c | 19 +++++++++++++++---- arch/cris/arch-v32/drivers/i2c.c | 22 ++++++++++++++-------- arch/cris/arch-v32/drivers/pcf8563.c | 21 ++++++++++++++++----- 4 files changed, 60 insertions(+), 22 deletions(-) diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c index 77630df94343..884275629ef7 100644 --- a/arch/cris/arch-v10/drivers/ds1302.c +++ b/arch/cris/arch-v10/drivers/ds1302.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/delay.h> +#include <linux/smp_lock.h> #include <linux/bcd.h> #include <linux/capability.h> @@ -238,9 +239,7 @@ static unsigned char days_in_mo[] = /* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */ -static int -rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static int rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned long flags; @@ -354,6 +353,17 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, } } +static long rtc_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret; + + lock_kernel(); + ret = rtc_ioctl(file, cmd, arg); + unlock_kernel(); + + return ret; +} + static void print_rtc_status(void) { @@ -375,8 +385,8 @@ print_rtc_status(void) /* The various file operations we support. */ static const struct file_operations rtc_fops = { - .owner = THIS_MODULE, - .ioctl = rtc_ioctl, + .owner = THIS_MODULE, + .unlocked_ioctl = rtc_unlocked_ioctl, }; /* Probe for the chip by writing something to its RAM and try reading it back. */ diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c index 1e90c1a9c849..7dcb1f85f42b 100644 --- a/arch/cris/arch-v10/drivers/pcf8563.c +++ b/arch/cris/arch-v10/drivers/pcf8563.c @@ -27,6 +27,7 @@ #include <linux/delay.h> #include <linux/bcd.h> #include <linux/mutex.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -53,7 +54,7 @@ static DEFINE_MUTEX(rtc_lock); /* Protect state etc */ static const unsigned char days_in_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +static long pcf8563_unlocked_ioctl(struct file *, unsigned int, unsigned long); /* Cache VL bit value read at driver init since writing the RTC_SECOND * register clears the VL status. @@ -62,7 +63,7 @@ static int voltage_low; static const struct file_operations pcf8563_fops = { .owner = THIS_MODULE, - .ioctl = pcf8563_ioctl, + .unlocked_ioctl = pcf8563_unlocked_ioctl, }; unsigned char @@ -212,8 +213,7 @@ pcf8563_exit(void) * ioctl calls for this driver. Why return -ENOTTY upon error? Because * POSIX says so! */ -int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int pcf8563_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { /* Some sanity checks. */ if (_IOC_TYPE(cmd) != RTC_MAGIC) @@ -339,6 +339,17 @@ int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } +static long pcf8563_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret; + + lock_kernel(); + return pcf8563_ioctl(filp, cmd, arg); + unlock_kernel(); + + return ret; +} + static int __init pcf8563_register(void) { if (pcf8563_init() < 0) { diff --git a/arch/cris/arch-v32/drivers/i2c.c b/arch/cris/arch-v32/drivers/i2c.c index 506826399ae7..2fd6a740d895 100644 --- a/arch/cris/arch-v32/drivers/i2c.c +++ b/arch/cris/arch-v32/drivers/i2c.c @@ -649,10 +649,10 @@ i2c_release(struct inode *inode, struct file *filp) /* Main device API. ioctl's to write or read to/from i2c registers. */ -static int -i2c_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long +i2c_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + int ret; if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) { return -ENOTTY; } @@ -665,9 +665,13 @@ i2c_ioctl(struct inode *inode, struct file *file, I2C_ARGREG(arg), I2C_ARGVALUE(arg))); - return i2c_writereg(I2C_ARGSLAVE(arg), + lock_kernel(); + ret = i2c_writereg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg), I2C_ARGVALUE(arg)); + unlock_kernel(); + return ret; + case I2C_READREG: { unsigned char val; @@ -675,7 +679,9 @@ i2c_ioctl(struct inode *inode, struct file *file, D(printk("i2cr %d %d ", I2C_ARGSLAVE(arg), I2C_ARGREG(arg))); + lock_kernel(); val = i2c_readreg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg)); + unlock_kernel(); D(printk("= %d\n", val)); return val; } @@ -688,10 +694,10 @@ i2c_ioctl(struct inode *inode, struct file *file, } static const struct file_operations i2c_fops = { - .owner = THIS_MODULE, - .ioctl = i2c_ioctl, - .open = i2c_open, - .release = i2c_release, + .owner = THIS_MODULE, + .unlocked_ioctl = i2c_ioctl, + .open = i2c_open, + .release = i2c_release, }; static int __init i2c_init(void) diff --git a/arch/cris/arch-v32/drivers/pcf8563.c b/arch/cris/arch-v32/drivers/pcf8563.c index f4478506e52c..bef6eb53b153 100644 --- a/arch/cris/arch-v32/drivers/pcf8563.c +++ b/arch/cris/arch-v32/drivers/pcf8563.c @@ -24,6 +24,7 @@ #include <linux/init.h> #include <linux/fs.h> #include <linux/ioctl.h> +#include <linux/smp_lock.h> #include <linux/delay.h> #include <linux/bcd.h> #include <linux/mutex.h> @@ -49,7 +50,7 @@ static DEFINE_MUTEX(rtc_lock); /* Protect state etc */ static const unsigned char days_in_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +static long pcf8563_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); /* Cache VL bit value read at driver init since writing the RTC_SECOND * register clears the VL status. @@ -57,8 +58,8 @@ int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); static int voltage_low; static const struct file_operations pcf8563_fops = { - .owner = THIS_MODULE, - .ioctl = pcf8563_ioctl + .owner = THIS_MODULE, + .unlocked_ioctl = pcf8563_unlocked_ioctl, }; unsigned char @@ -208,8 +209,7 @@ pcf8563_exit(void) * ioctl calls for this driver. Why return -ENOTTY upon error? Because * POSIX says so! */ -int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int pcf8563_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { /* Some sanity checks. */ if (_IOC_TYPE(cmd) != RTC_MAGIC) @@ -335,6 +335,17 @@ int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } +static long pcf8563_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret; + + lock_kernel(); + return pcf8563_ioctl(filp, cmd, arg); + unlock_kernel(); + + return ret; +} + static int __init pcf8563_register(void) { if (pcf8563_init() < 0) { -- GitLab From fb994ecc2b1c214951366c2ba5d8b121f0010d1f Mon Sep 17 00:00:00 2001 From: Greg Thelen <gthelen@google.com> Date: Wed, 5 May 2010 10:41:44 -0700 Subject: [PATCH 081/842] kbuild: Fix checking of scm-identifier variable I'm looking Makefile in the -mm branch (dated 2010-04-28-16-53) and seeing what looks like a bug in the checking of scm-identifier. The "ifneq ($scm-identifier)" seems to always execute "ifeq ($(LOCALVERSION,)) ...". This patch fixes the checking of scm-identifier. Signed-off-by: Greg Thelen <gthelen@google.com> Acked-by: David Rientjes <rientjes@google.com> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b98943a466c5..ea5f0bee1934 100644 --- a/Makefile +++ b/Makefile @@ -943,7 +943,7 @@ endif ifdef CONFIG_LOCALVERSION_AUTO localver-extra = $(scm-identifier) else - ifneq ($scm-identifier,) + ifneq ($(scm-identifier),) ifeq ($(LOCALVERSION),) localver-extra = + endif -- GitLab From e2efc09e52680cecb0ca624e379cb4b4c56157c3 Mon Sep 17 00:00:00 2001 From: Tirumala Marri <tmarri@amcc.com> Date: Mon, 21 Dec 2009 22:49:41 +0000 Subject: [PATCH 082/842] powerpc/44x: Adding PCI-E support for PowerPC 460SX based SOC. Add support for PCI-e on the AMCC 460SX boards Signed-off-by: Tirumala Marri <tmarri@amcc.com> Acked-by: Josh Boyer <jwboyer@linux.vnet.ibm.com Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com> --- arch/powerpc/boot/dts/redwood.dts | 122 ++++++++++++++++++++++++++++++ arch/powerpc/sysdev/ppc4xx_pci.c | 119 +++++++++++++++++++++++++++++ arch/powerpc/sysdev/ppc4xx_pci.h | 58 ++++++++++++++ 3 files changed, 299 insertions(+) diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts index d2af32e2bf7a..81636c01d906 100644 --- a/arch/powerpc/boot/dts/redwood.dts +++ b/arch/powerpc/boot/dts/redwood.dts @@ -234,10 +234,132 @@ has-inverted-stacr-oc; has-new-stacr-staopc; }; + }; + PCIE0: pciex@d00000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pciex-460sx", "ibm,plb-pciex"; + primary; + port = <0x0>; /* port number */ + reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */ + 0x0000000c 0x10000000 0x00001000>; /* Registers */ + dcr-reg = <0x100 0x020>; + sdr-base = <0x300>; + + /* Outbound ranges, one memory and one IO, + * later cannot be changed + */ + ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000 + 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>; + + /* Inbound 2GB range starting at 0 */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; + /* This drives busses 10 to 0x1f */ + bus-range = <0x10 0x1f>; + + /* Legacy interrupts (note the weird polarity, the bridge seems + * to invert PCIe legacy interrupts). + * We are de-swizzling here because the numbers are actually for + * port of the root complex virtual P2P bridge. But I want + * to avoid putting a node for it in the tree, so the numbers + * below are basically de-swizzled numbers. + * The real slot is on idsel 0, so the swizzling is 1:1 + */ + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = < + 0x0 0x0 0x0 0x1 &UIC3 0x0 0x4 /* swizzled int A */ + 0x0 0x0 0x0 0x2 &UIC3 0x1 0x4 /* swizzled int B */ + 0x0 0x0 0x0 0x3 &UIC3 0x2 0x4 /* swizzled int C */ + 0x0 0x0 0x0 0x4 &UIC3 0x3 0x4 /* swizzled int D */>; + }; + + PCIE1: pciex@d20000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pciex-460sx", "ibm,plb-pciex"; + primary; + port = <0x1>; /* port number */ + reg = <0x0000000d 0x20000000 0x20000000 /* Config space access */ + 0x0000000c 0x10001000 0x00001000>; /* Registers */ + dcr-reg = <0x120 0x020>; + sdr-base = <0x340>; + + /* Outbound ranges, one memory and one IO, + * later cannot be changed + */ + ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000 + 0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>; + + /* Inbound 2GB range starting at 0 */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; + + /* This drives busses 10 to 0x1f */ + bus-range = <0x20 0x2f>; + + /* Legacy interrupts (note the weird polarity, the bridge seems + * to invert PCIe legacy interrupts). + * We are de-swizzling here because the numbers are actually for + * port of the root complex virtual P2P bridge. But I want + * to avoid putting a node for it in the tree, so the numbers + * below are basically de-swizzled numbers. + * The real slot is on idsel 0, so the swizzling is 1:1 + */ + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = < + 0x0 0x0 0x0 0x1 &UIC3 0x4 0x4 /* swizzled int A */ + 0x0 0x0 0x0 0x2 &UIC3 0x5 0x4 /* swizzled int B */ + 0x0 0x0 0x0 0x3 &UIC3 0x6 0x4 /* swizzled int C */ + 0x0 0x0 0x0 0x4 &UIC3 0x7 0x4 /* swizzled int D */>; + }; + + PCIE2: pciex@d40000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pciex-460sx", "ibm,plb-pciex"; + primary; + port = <0x2>; /* port number */ + reg = <0x0000000d 0x40000000 0x20000000 /* Config space access */ + 0x0000000c 0x10002000 0x00001000>; /* Registers */ + dcr-reg = <0x140 0x020>; + sdr-base = <0x370>; + + /* Outbound ranges, one memory and one IO, + * later cannot be changed + */ + ranges = <0x02000000 0x00000000 0x80000000 0x0000000f 0x00000000 0x00000000 0x80000000 + 0x01000000 0x00000000 0x00000000 0x0000000f 0x80020000 0x00000000 0x00010000>; + + /* Inbound 2GB range starting at 0 */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; + + /* This drives busses 10 to 0x1f */ + bus-range = <0x30 0x3f>; + + /* Legacy interrupts (note the weird polarity, the bridge seems + * to invert PCIe legacy interrupts). + * We are de-swizzling here because the numbers are actually for + * port of the root complex virtual P2P bridge. But I want + * to avoid putting a node for it in the tree, so the numbers + * below are basically de-swizzled numbers. + * The real slot is on idsel 0, so the swizzling is 1:1 + */ + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = < + 0x0 0x0 0x0 0x1 &UIC3 0x8 0x4 /* swizzled int A */ + 0x0 0x0 0x0 0x2 &UIC3 0x9 0x4 /* swizzled int B */ + 0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /* swizzled int C */ + 0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>; }; }; + chosen { linux,stdout-path = "/plb/opb/serial@ef600200"; }; diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 106d767bf65b..156aa7d36258 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -974,6 +974,123 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata = .setup_utl = ppc460ex_pciex_init_utl, }; +static int __init ppc460sx_pciex_core_init(struct device_node *np) +{ + /* HSS drive amplitude */ + mtdcri(SDR0, PESDR0_460SX_HSSL0DAMP, 0xB9843211); + mtdcri(SDR0, PESDR0_460SX_HSSL1DAMP, 0xB9843211); + mtdcri(SDR0, PESDR0_460SX_HSSL2DAMP, 0xB9843211); + mtdcri(SDR0, PESDR0_460SX_HSSL3DAMP, 0xB9843211); + mtdcri(SDR0, PESDR0_460SX_HSSL4DAMP, 0xB9843211); + mtdcri(SDR0, PESDR0_460SX_HSSL5DAMP, 0xB9843211); + mtdcri(SDR0, PESDR0_460SX_HSSL6DAMP, 0xB9843211); + mtdcri(SDR0, PESDR0_460SX_HSSL7DAMP, 0xB9843211); + + mtdcri(SDR0, PESDR1_460SX_HSSL0DAMP, 0xB9843211); + mtdcri(SDR0, PESDR1_460SX_HSSL1DAMP, 0xB9843211); + mtdcri(SDR0, PESDR1_460SX_HSSL2DAMP, 0xB9843211); + mtdcri(SDR0, PESDR1_460SX_HSSL3DAMP, 0xB9843211); + + mtdcri(SDR0, PESDR2_460SX_HSSL0DAMP, 0xB9843211); + mtdcri(SDR0, PESDR2_460SX_HSSL1DAMP, 0xB9843211); + mtdcri(SDR0, PESDR2_460SX_HSSL2DAMP, 0xB9843211); + mtdcri(SDR0, PESDR2_460SX_HSSL3DAMP, 0xB9843211); + + /* HSS TX pre-emphasis */ + mtdcri(SDR0, PESDR0_460SX_HSSL0COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR0_460SX_HSSL1COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR0_460SX_HSSL2COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR0_460SX_HSSL3COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR0_460SX_HSSL4COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR0_460SX_HSSL5COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR0_460SX_HSSL6COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR0_460SX_HSSL7COEFA, 0xDCB98987); + + mtdcri(SDR0, PESDR1_460SX_HSSL0COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR1_460SX_HSSL1COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR1_460SX_HSSL2COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR1_460SX_HSSL3COEFA, 0xDCB98987); + + mtdcri(SDR0, PESDR2_460SX_HSSL0COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR2_460SX_HSSL1COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR2_460SX_HSSL2COEFA, 0xDCB98987); + mtdcri(SDR0, PESDR2_460SX_HSSL3COEFA, 0xDCB98987); + + /* HSS TX calibration control */ + mtdcri(SDR0, PESDR0_460SX_HSSL1CALDRV, 0x22222222); + mtdcri(SDR0, PESDR1_460SX_HSSL1CALDRV, 0x22220000); + mtdcri(SDR0, PESDR2_460SX_HSSL1CALDRV, 0x22220000); + + /* HSS TX slew control */ + mtdcri(SDR0, PESDR0_460SX_HSSSLEW, 0xFFFFFFFF); + mtdcri(SDR0, PESDR1_460SX_HSSSLEW, 0xFFFF0000); + mtdcri(SDR0, PESDR2_460SX_HSSSLEW, 0xFFFF0000); + + udelay(100); + + /* De-assert PLLRESET */ + dcri_clrset(SDR0, PESDR0_PLLLCT2, 0x00000100, 0); + + /* Reset DL, UTL, GPL before configuration */ + mtdcri(SDR0, PESDR0_460SX_RCSSET, + PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU); + mtdcri(SDR0, PESDR1_460SX_RCSSET, + PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU); + mtdcri(SDR0, PESDR2_460SX_RCSSET, + PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU); + + udelay(100); + + /* + * If bifurcation is not enabled, u-boot would have disabled the + * third PCIe port + */ + if (((mfdcri(SDR0, PESDR1_460SX_HSSCTLSET) & 0x00000001) == + 0x00000001)) { + printk(KERN_INFO "PCI: PCIE bifurcation setup successfully.\n"); + printk(KERN_INFO "PCI: Total 3 PCIE ports are present\n"); + return 3; + } + + printk(KERN_INFO "PCI: Total 2 PCIE ports are present\n"); + return 2; +} + +static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +{ + + if (port->endpoint) + dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2, + 0x01000000, 0); + else + dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2, + 0, 0x01000000); + + /*Gen-1*/ + mtdcri(SDR0, port->sdr_base + PESDRn_460SX_RCEI, 0x08000000); + + dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, + (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL), + PESDRx_RCSSET_RSTPYN); + + port->has_ibpre = 1; + + return 0; +} + +static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port) +{ + /* Max 128 Bytes */ + out_be32 (port->utl_base + PEUTL_PBBSZ, 0x00000000); + return 0; +} + +static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = { + .core_init = ppc460sx_pciex_core_init, + .port_init_hw = ppc460sx_pciex_init_port_hw, + .setup_utl = ppc460sx_pciex_init_utl, +}; + #endif /* CONFIG_44x */ #ifdef CONFIG_40x @@ -1089,6 +1206,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) } if (of_device_is_compatible(np, "ibm,plb-pciex-460ex")) ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops; + if (of_device_is_compatible(np, "ibm,plb-pciex-460sx")) + ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops; #endif /* CONFIG_44x */ #ifdef CONFIG_40x if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) diff --git a/arch/powerpc/sysdev/ppc4xx_pci.h b/arch/powerpc/sysdev/ppc4xx_pci.h index d04e40b306fb..56d9e5deccbf 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.h +++ b/arch/powerpc/sysdev/ppc4xx_pci.h @@ -323,6 +323,64 @@ #define PESDR0_460EX_IHS1 0x036C #define PESDR0_460EX_IHS2 0x036D +/* + * 460SX addtional DCRs + */ +#define PESDRn_460SX_RCEI 0x02 + +#define PESDR0_460SX_HSSL0DAMP 0x320 +#define PESDR0_460SX_HSSL1DAMP 0x321 +#define PESDR0_460SX_HSSL2DAMP 0x322 +#define PESDR0_460SX_HSSL3DAMP 0x323 +#define PESDR0_460SX_HSSL4DAMP 0x324 +#define PESDR0_460SX_HSSL5DAMP 0x325 +#define PESDR0_460SX_HSSL6DAMP 0x326 +#define PESDR0_460SX_HSSL7DAMP 0x327 + +#define PESDR1_460SX_HSSL0DAMP 0x354 +#define PESDR1_460SX_HSSL1DAMP 0x355 +#define PESDR1_460SX_HSSL2DAMP 0x356 +#define PESDR1_460SX_HSSL3DAMP 0x357 + +#define PESDR2_460SX_HSSL0DAMP 0x384 +#define PESDR2_460SX_HSSL1DAMP 0x385 +#define PESDR2_460SX_HSSL2DAMP 0x386 +#define PESDR2_460SX_HSSL3DAMP 0x387 + +#define PESDR0_460SX_HSSL0COEFA 0x328 +#define PESDR0_460SX_HSSL1COEFA 0x329 +#define PESDR0_460SX_HSSL2COEFA 0x32A +#define PESDR0_460SX_HSSL3COEFA 0x32B +#define PESDR0_460SX_HSSL4COEFA 0x32C +#define PESDR0_460SX_HSSL5COEFA 0x32D +#define PESDR0_460SX_HSSL6COEFA 0x32E +#define PESDR0_460SX_HSSL7COEFA 0x32F + +#define PESDR1_460SX_HSSL0COEFA 0x358 +#define PESDR1_460SX_HSSL1COEFA 0x359 +#define PESDR1_460SX_HSSL2COEFA 0x35A +#define PESDR1_460SX_HSSL3COEFA 0x35B + +#define PESDR2_460SX_HSSL0COEFA 0x388 +#define PESDR2_460SX_HSSL1COEFA 0x389 +#define PESDR2_460SX_HSSL2COEFA 0x38A +#define PESDR2_460SX_HSSL3COEFA 0x38B + +#define PESDR0_460SX_HSSL1CALDRV 0x339 +#define PESDR1_460SX_HSSL1CALDRV 0x361 +#define PESDR2_460SX_HSSL1CALDRV 0x391 + +#define PESDR0_460SX_HSSSLEW 0x338 +#define PESDR1_460SX_HSSSLEW 0x360 +#define PESDR2_460SX_HSSSLEW 0x390 + +#define PESDR0_460SX_HSSCTLSET 0x31E +#define PESDR1_460SX_HSSCTLSET 0x352 +#define PESDR2_460SX_HSSCTLSET 0x382 + +#define PESDR0_460SX_RCSSET 0x304 +#define PESDR1_460SX_RCSSET 0x344 +#define PESDR2_460SX_RCSSET 0x374 /* * Of the above, some are common offsets from the base */ -- GitLab From 499f49026e25e74dc617bb0d96ed6e85a67f4980 Mon Sep 17 00:00:00 2001 From: Stefan Roese <sr@denx.de> Date: Thu, 6 May 2010 21:43:43 +0000 Subject: [PATCH 083/842] powerpc/44x: Add reset-type to katmai.dts Katmai needs "reset-type" = "chip reset" (2) to correctly reboot the board. Signed-off-by: Stefan Roese <sr@denx.de> Cc: Josh Boyer <jwboyer@linux.vnet.ibm.com> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com> --- arch/powerpc/boot/dts/katmai.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/boot/dts/katmai.dts b/arch/powerpc/boot/dts/katmai.dts index 8cf2c0c88c05..7c3be5e45748 100644 --- a/arch/powerpc/boot/dts/katmai.dts +++ b/arch/powerpc/boot/dts/katmai.dts @@ -44,6 +44,7 @@ d-cache-size = <32768>; dcr-controller; dcr-access-method = "native"; + reset-type = <2>; /* Use chip-reset */ }; }; -- GitLab From a0c36a1f0fbab42590dab3c13c10fa7d20e6c2cd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:41:15 -0300 Subject: [PATCH 084/842] i7core_edac: Add an EDAC memory controller driver for Nehalem chipsets This driver is meant to support i7 core/i7core extreme desktop processors and Xeon 35xx/55xx series with integrated memory controller. It is likely that it can be expanded in the future to work with other processor series based at the same Memory Controller design. For now, it has just a few MCH status reads. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/Kconfig | 7 + drivers/edac/Makefile | 1 + drivers/edac/i7core_edac.c | 462 +++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 16 ++ 4 files changed, 486 insertions(+) create mode 100644 drivers/edac/i7core_edac.c diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 55c9c59b3f71..391ddbfb2a34 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -166,6 +166,13 @@ config EDAC_I5400 Support for error detection and correction the Intel i5400 MCH chipset (Seaburg). +config EDAC_I7CORE + tristate "Intel i7 Core (Nehalem) processors" + depends on EDAC_MM_EDAC && PCI && X86 + help + Support for error detection and correction the Intel + i7 Core (Nehalem) Integrated Memory Controller + config EDAC_I82860 tristate "Intel 82860" depends on EDAC_MM_EDAC && PCI && X86_32 diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index bc5dc232a0fb..b9996195b233 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o obj-$(CONFIG_EDAC_I5000) += i5000_edac.o obj-$(CONFIG_EDAC_I5100) += i5100_edac.o obj-$(CONFIG_EDAC_I5400) += i5400_edac.o +obj-$(CONFIG_EDAC_I7CORE) += i7core_edac.o obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o obj-$(CONFIG_EDAC_E752X) += e752x_edac.o obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c new file mode 100644 index 000000000000..7ecf15e66a3f --- /dev/null +++ b/drivers/edac/i7core_edac.c @@ -0,0 +1,462 @@ +/* Intel 7 core Memory Controller kernel module (Nehalem) + * + * This file may be distributed under the terms of the + * GNU General Public License version 2 only. + * + * Copyright (c) 2009 by: + * Mauro Carvalho Chehab <mchehab@redhat.com> + * + * Red Hat Inc. http://www.redhat.com + * + * Forked and adapted from the i5400_edac driver + * + * Based on the following public Intel datasheets: + * Intel Core i7 Processor Extreme Edition and Intel Core i7 Processor + * Datasheet, Volume 2: + * http://download.intel.com/design/processor/datashts/320835.pdf + * Intel Xeon Processor 5500 Series Datasheet Volume 2 + * http://www.intel.com/Assets/PDF/datasheet/321322.pdf + * also available at: + * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf + */ + + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/slab.h> +#include <linux/edac.h> +#include <linux/mmzone.h> + +#include "edac_core.h" + + +/* + * Alter this version for the module when modifications are made + */ +#define I7CORE_REVISION " Ver: 1.0.0 " __DATE__ +#define EDAC_MOD_STR "i7core_edac" + +/* HACK: temporary, just to enable all logs, for now */ +#undef debugf0 +#define debugf0(fmt, arg...) edac_printk(KERN_INFO, "i7core", fmt, ##arg) + +/* + * Debug macros + */ +#define i7core_printk(level, fmt, arg...) \ + edac_printk(level, "i7core", fmt, ##arg) + +#define i7core_mc_printk(mci, level, fmt, arg...) \ + edac_mc_chipset_printk(mci, level, "i7core", fmt, ##arg) + +/* + * i7core Memory Controller Registers + */ + + /* OFFSETS for Device 3 Function 0 */ + +#define MC_CONTROL 0x48 +#define MC_STATUS 0x4c +#define MC_MAX_DOD 0x64 + + /* OFFSETS for Devices 4,5 and 6 Function 0 */ + +#define MC_CHANNEL_ADDR_MATCH 0xf0 + +#define MC_MASK_DIMM (1 << 41) +#define MC_MASK_RANK (1 << 40) +#define MC_MASK_BANK (1 << 39) +#define MC_MASK_PAGE (1 << 38) +#define MC_MASK_COL (1 << 37) + +/* + * i7core structs + */ + +#define NUM_CHANS 3 +#define NUM_FUNCS 1 + +struct i7core_info { + u32 mc_control; + u32 mc_status; + u32 max_dod; +}; + +struct i7core_pvt { + struct pci_dev *pci_mcr; /* Dev 3:0 */ + struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS]; + struct i7core_info info; +}; + +/* Device name and register DID (Device ID) */ +struct i7core_dev_info { + const char *ctl_name; /* name for this device */ + u16 fsb_mapping_errors; /* DID for the branchmap,control */ +}; + +static int chan_pci_ids[NUM_CHANS] = { + PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL, /* Dev 4 */ + PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL, /* Dev 5 */ + PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL, /* Dev 6 */ +}; + +/* Table of devices attributes supported by this driver */ +static const struct i7core_dev_info i7core_devs[] = { + { + .ctl_name = "i7 Core", + .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR, + }, +}; + +static struct edac_pci_ctl_info *i7core_pci; + +/**************************************************************************** + Anciliary status routines + ****************************************************************************/ + + /* MC_CONTROL bits */ +#define CH2_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 10) +#define CH1_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 9) +#define CH0_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 8) +#define ECCx8(pvt) ((pvt)->info.mc_control & 1 << 1) + + /* MC_STATUS bits */ +#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & 1 << 3) +#define CH2_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 2) +#define CH1_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 1) +#define CH0_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 0) + + /* MC_MAX_DOD read functions */ +static inline int maxnumdimms(struct i7core_pvt *pvt) +{ + return (pvt->info.max_dod & 0x3) + 1; +} + +static inline int maxnumrank(struct i7core_pvt *pvt) +{ + static int ranks[4] = { 1, 2, 4, -EINVAL }; + + return ranks[(pvt->info.max_dod >> 2) & 0x3]; +} + +static inline int maxnumbank(struct i7core_pvt *pvt) +{ + static int banks[4] = { 4, 8, 16, -EINVAL }; + + return banks[(pvt->info.max_dod >> 4) & 0x3]; +} + +static inline int maxnumrow(struct i7core_pvt *pvt) +{ + static int rows[8] = { + 1 << 12, 1 << 13, 1 << 14, 1 << 15, + 1 << 16, -EINVAL, -EINVAL, -EINVAL, + }; + + return rows[((pvt->info.max_dod >> 6) & 0x7)]; +} + +static inline int maxnumcol(struct i7core_pvt *pvt) +{ + static int cols[8] = { + 1 << 10, 1 << 11, 1 << 12, -EINVAL, + }; + return cols[((pvt->info.max_dod >> 9) & 0x3) << 12]; +} + +/**************************************************************************** + Memory check routines + ****************************************************************************/ +static int get_dimm_config(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + + pci_read_config_dword(pvt->pci_mcr, MC_CONTROL, &pvt->info.mc_control); + pci_read_config_dword(pvt->pci_mcr, MC_STATUS, &pvt->info.mc_status); + pci_read_config_dword(pvt->pci_mcr, MC_MAX_DOD, &pvt->info.max_dod); + + debugf0("Channels active [%c][%c][%c] - enabled [%c][%c][%c]\n", + CH0_ACTIVE(pvt)?'0':'-', + CH1_ACTIVE(pvt)?'1':'-', + CH2_ACTIVE(pvt)?'2':'-', + CH0_DISABLED(pvt)?'-':'0', + CH1_DISABLED(pvt)?'-':'1', + CH2_DISABLED(pvt)?'-':'2'); + + if (ECC_ENABLED(pvt)) + debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); + else + debugf0("ECC disabled\n"); + + /* FIXME: need to handle the error codes */ + debugf0("DOD Maximum limits: DIMMS: %d, %d-ranked, %d-banked\n", + maxnumdimms(pvt), maxnumrank(pvt), maxnumbank(pvt)); + debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n", + maxnumrow(pvt), maxnumcol(pvt)); + + return 0; +} + +/**************************************************************************** + Device initialization routines: put/get, init/exit + ****************************************************************************/ + +/* + * i7core_put_devices 'put' all the devices that we have + * reserved via 'get' + */ +static void i7core_put_devices(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + int i, n; + + pci_dev_put(pvt->pci_mcr); + + /* Release all PCI device functions at MTR channel controllers */ + for (i = 0; i < NUM_CHANS; i++) + for (n = 0; n < NUM_FUNCS; n++) + pci_dev_put(pvt->pci_ch[i][n]); +} + +/* + * i7core_get_devices Find and perform 'get' operation on the MCH's + * device/functions we want to reference for this driver + * + * Need to 'get' device 16 func 1 and func 2 + */ +static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx) +{ + struct i7core_pvt *pvt; + struct pci_dev *pdev; + int i, n, func; + + pvt = mci->pvt_info; + memset(pvt, 0, sizeof(*pvt)); + + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR, + NULL); + if (!pdev) { + i7core_printk(KERN_ERR, + "Couldn't get PCI ID %04x:%04x function 0\n", + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR); + return -ENODEV; + } + pvt->pci_mcr=pdev; + + /* Get dimm basic config */ + get_dimm_config(mci); + + /* Retrieve all needed functions at MTR channel controllers */ + for (i = 0; i < NUM_CHANS; i++) { + pdev = NULL; + for (n = 0; n < NUM_FUNCS; n++) { + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + chan_pci_ids[i], pdev); + if (!pdev) { + /* End of list, leave */ + i7core_printk(KERN_ERR, + "Device not found: PCI ID %04x:%04x " + "found only %d functions " + "(broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, + chan_pci_ids[i], n); + i7core_put_devices(mci); + return -ENODEV; + } + func = PCI_FUNC(pdev->devfn); + pvt->pci_ch[i][func] = pdev; + } + } + i7core_printk(KERN_INFO, "Driver loaded.\n"); + + return 0; +} + +/* + * i7core_probe Probe for ONE instance of device to see if it is + * present. + * return: + * 0 for FOUND a device + * < 0 for error code + */ +static int __devinit i7core_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct mem_ctl_info *mci; + struct i7core_pvt *pvt; + int rc; + int num_channels; + int num_csrows; + int num_dimms_per_channel; + int dev_idx = id->driver_data; + + if (dev_idx >= ARRAY_SIZE(i7core_devs)) + return -EINVAL; + + /* wake up device */ + rc = pci_enable_device(pdev); + if (rc == -EIO) + return rc; + + debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", + __func__, + pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + + /* We only are looking for func 0 of the set */ + if (PCI_FUNC(pdev->devfn) != 0) + return -ENODEV; + + num_channels = NUM_CHANS; + + /* FIXME: FAKE data, since we currently don't now how to get this */ + num_dimms_per_channel = 4; + num_csrows = num_dimms_per_channel; + + /* allocate a new MC control structure */ + mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); + if (mci == NULL) + return -ENOMEM; + + debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); + + mci->dev = &pdev->dev; /* record ptr to the generic device */ + dev_set_drvdata(mci->dev, mci); + + pvt = mci->pvt_info; +// pvt->system_address = pdev; /* Record this device in our private */ +// pvt->maxch = num_channels; +// pvt->maxdimmperch = num_dimms_per_channel; + + /* 'get' the pci devices we want to reserve for our use */ + if (i7core_get_devices(mci, dev_idx)) + goto fail0; + + mci->mc_idx = 0; + mci->mtype_cap = MEM_FLAG_FB_DDR2; /* FIXME: it uses DDR3 */ + mci->edac_ctl_cap = EDAC_FLAG_NONE; + mci->edac_cap = EDAC_FLAG_NONE; + mci->mod_name = "i7core_edac.c"; + mci->mod_ver = I7CORE_REVISION; + mci->ctl_name = i7core_devs[dev_idx].ctl_name; + mci->dev_name = pci_name(pdev); + mci->ctl_page_to_phys = NULL; + + /* add this new MC control structure to EDAC's list of MCs */ + if (edac_mc_add_mc(mci)) { + debugf0("MC: " __FILE__ + ": %s(): failed edac_mc_add_mc()\n", __func__); + /* FIXME: perhaps some code should go here that disables error + * reporting if we just enabled it + */ + goto fail1; + } + + /* allocating generic PCI control info */ + i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); + if (!i7core_pci) { + printk(KERN_WARNING + "%s(): Unable to create PCI control\n", + __func__); + printk(KERN_WARNING + "%s(): PCI error report via EDAC not setup\n", + __func__); + } + + return 0; + +fail1: + i7core_put_devices(mci); + +fail0: + edac_mc_free(mci); + return -ENODEV; +} + +/* + * i7core_remove destructor for one instance of device + * + */ +static void __devexit i7core_remove(struct pci_dev *pdev) +{ + struct mem_ctl_info *mci; + + debugf0(__FILE__ ": %s()\n", __func__); + + if (i7core_pci) + edac_pci_release_generic_ctl(i7core_pci); + + mci = edac_mc_del_mc(&pdev->dev); + if (!mci) + return; + + /* retrieve references to resources, and free those resources */ + i7core_put_devices(mci); + + edac_mc_free(mci); +} + +/* + * pci_device_id table for which devices we are looking for + * + * The "E500P" device is the first device supported. + */ +static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)}, + {0,} /* 0 terminated list. */ +}; + +MODULE_DEVICE_TABLE(pci, i7core_pci_tbl); + +/* + * i7core_driver pci_driver structure for this module + * + */ +static struct pci_driver i7core_driver = { + .name = "i7core_edac", + .probe = i7core_probe, + .remove = __devexit_p(i7core_remove), + .id_table = i7core_pci_tbl, +}; + +/* + * i7core_init Module entry function + * Try to initialize this module for its devices + */ +static int __init i7core_init(void) +{ + int pci_rc; + + debugf2("MC: " __FILE__ ": %s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + + pci_rc = pci_register_driver(&i7core_driver); + + return (pci_rc < 0) ? pci_rc : 0; +} + +/* + * i7core_exit() Module exit function + * Unregister the driver + */ +static void __exit i7core_exit(void) +{ + debugf2("MC: " __FILE__ ": %s()\n", __func__); + pci_unregister_driver(&i7core_driver); +} + +module_init(i7core_init); +module_exit(i7core_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - " + I7CORE_REVISION); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 9f688d243b86..c5dd0994bd7c 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2532,6 +2532,22 @@ #define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 #define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 #define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 +#define PCI_DEVICE_ID_INTEL_I7_MCR 0x2c18 +#define PCI_DEVICE_ID_INTEL_I7_MC_TAD 0x2c19 +#define PCI_DEVICE_ID_INTEL_I7_MC_RAS 0x2c1a +#define PCI_DEVICE_ID_INTEL_I7_MC_TEST 0x2c1c +#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL 0x2c20 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR 0x2c21 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK 0x2c22 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC 0x2c23 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL 0x2c28 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR 0x2c29 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK 0x2c2a +#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC 0x2c2b +#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL 0x2c30 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR 0x2c31 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK 0x2c32 +#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 #define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a -- GitLab From 194a40feabb7cab38911a357c86e968e98024281 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:28 -0300 Subject: [PATCH 085/842] i7core_edac: Add error insertion code for Nehalem Implements set_inject_error() with the low-level code needed to inject memory errors at Nehalem, and adds some sysfs nodes to allow error injection The next patch will add an API for error injection. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 427 ++++++++++++++++++++++++++++++++++++- 1 file changed, 419 insertions(+), 8 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 7ecf15e66a3f..b590f8468693 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -20,7 +20,6 @@ * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf */ - #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> @@ -64,12 +63,16 @@ /* OFFSETS for Devices 4,5 and 6 Function 0 */ #define MC_CHANNEL_ADDR_MATCH 0xf0 - -#define MC_MASK_DIMM (1 << 41) -#define MC_MASK_RANK (1 << 40) -#define MC_MASK_BANK (1 << 39) -#define MC_MASK_PAGE (1 << 38) -#define MC_MASK_COL (1 << 37) +#define MC_CHANNEL_ERROR_MASK 0xf8 +#define MC_CHANNEL_ERROR_INJECT 0xfc + #define INJECT_ADDR_PARITY 0x10 + #define INJECT_ECC 0x08 + #define MASK_CACHELINE 0x06 + #define MASK_FULL_CACHELINE 0x06 + #define MASK_MSB32_CACHELINE 0x04 + #define MASK_LSB32_CACHELINE 0x02 + #define NO_MASK_CACHELINE 0x00 + #define REPEAT_EN 0x01 /* * i7core structs @@ -84,10 +87,23 @@ struct i7core_info { u32 max_dod; }; + +struct i7core_inject { + int enable; + + u32 section; + u32 type; + u32 eccmask; + + /* Error address mask */ + int channel, dimm, rank, bank, page, col; +}; + struct i7core_pvt { struct pci_dev *pci_mcr; /* Dev 3:0 */ struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS]; struct i7core_info info; + struct i7core_inject inject; }; /* Device name and register DID (Device ID) */ @@ -166,6 +182,7 @@ static inline int maxnumcol(struct i7core_pvt *pvt) return cols[((pvt->info.max_dod >> 9) & 0x3) << 12]; } + /**************************************************************************** Memory check routines ****************************************************************************/ @@ -199,6 +216,390 @@ static int get_dimm_config(struct mem_ctl_info *mci) return 0; } +/**************************************************************************** + Error insertion routines + ****************************************************************************/ + +/* The i7core has independent error injection features per channel. + However, to have a simpler code, we don't allow enabling error injection + on more than one channel. + Also, since a change at an inject parameter will be applied only at enable, + we're disabling error injection on all write calls to the sysfs nodes that + controls the error code injection. + */ +static void disable_inject(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + + pvt->inject.enable = 0; + + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ERROR_MASK, 0); +} + +/* + * i7core inject inject.section + * + * accept and store error injection inject.section value + * bit 0 - refers to the lower 32-byte half cacheline + * bit 1 - refers to the upper 32-byte half cacheline + */ +static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + unsigned long value; + int rc; + + if (pvt->inject.enable) + disable_inject(mci); + + rc = strict_strtoul(data, 10, &value); + if ((rc < 0) || (value > 3)) + return 0; + + pvt->inject.section = (u32) value; + return count; +} + +static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + return sprintf(data, "0x%08x\n", pvt->inject.section); +} + +/* + * i7core inject.type + * + * accept and store error injection inject.section value + * bit 0 - repeat enable - Enable error repetition + * bit 1 - inject ECC error + * bit 2 - inject parity error + */ +static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + unsigned long value; + int rc; + + if (pvt->inject.enable) + disable_inject(mci); + + rc = strict_strtoul(data, 10, &value); + if ((rc < 0) || (value > 7)) + return 0; + + pvt->inject.type = (u32) value; + return count; +} + +static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + return sprintf(data, "0x%08x\n", pvt->inject.type); +} + +/* + * i7core_inject_inject.eccmask_store + * + * The type of error (UE/CE) will depend on the inject.eccmask value: + * Any bits set to a 1 will flip the corresponding ECC bit + * Correctable errors can be injected by flipping 1 bit or the bits within + * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or + * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an + * uncorrectable error to be injected. + */ +static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + unsigned long value; + int rc; + + if (pvt->inject.enable) + disable_inject(mci); + + rc = strict_strtoul(data, 10, &value); + if (rc < 0) + return 0; + + pvt->inject.eccmask = (u32) value; + return count; +} + +static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + return sprintf(data, "0x%08x\n", pvt->inject.eccmask); +} + +/* + * i7core_addrmatch + * + * The type of error (UE/CE) will depend on the inject.eccmask value: + * Any bits set to a 1 will flip the corresponding ECC bit + * Correctable errors can be injected by flipping 1 bit or the bits within + * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or + * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an + * uncorrectable error to be injected. + */ +static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + char *cmd, *val; + long value; + int rc; + + if (pvt->inject.enable) + disable_inject(mci); + + do { + cmd = strsep((char **) &data, ":"); + if (!cmd) + break; + val = strsep((char **) &data, " \n\t"); + if (!val) + return cmd - data; + + if (!strcasecmp(val,"any")) + value = -1; + else { + rc = strict_strtol(val, 10, &value); + if ((rc < 0) || (value < 0)) + return cmd - data; + } + + if (!strcasecmp(cmd,"channel")) { + if (value < 3) + pvt->inject.channel = value; + else + return cmd - data; + } else if (!strcasecmp(cmd,"dimm")) { + if (value < 4) + pvt->inject.dimm = value; + else + return cmd - data; + } else if (!strcasecmp(cmd,"rank")) { + if (value < 4) + pvt->inject.rank = value; + else + return cmd - data; + } else if (!strcasecmp(cmd,"bank")) { + if (value < 4) + pvt->inject.bank = value; + else + return cmd - data; + } else if (!strcasecmp(cmd,"page")) { + if (value <= 0xffff) + pvt->inject.page = value; + else + return cmd - data; + } else if (!strcasecmp(cmd,"col") || + !strcasecmp(cmd,"column")) { + if (value <= 0x3fff) + pvt->inject.col = value; + else + return cmd - data; + } + } while (1); + + return count; +} + +static ssize_t i7core_inject_addrmatch_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + char channel[4], dimm[4], bank[4], rank[4], page[7], col[7]; + + if (pvt->inject.channel < 0) + sprintf(channel, "any"); + else + sprintf(channel, "%d", pvt->inject.channel); + if (pvt->inject.dimm < 0) + sprintf(dimm, "any"); + else + sprintf(dimm, "%d", pvt->inject.dimm); + if (pvt->inject.bank < 0) + sprintf(bank, "any"); + else + sprintf(bank, "%d", pvt->inject.bank); + if (pvt->inject.rank < 0) + sprintf(rank, "any"); + else + sprintf(rank, "%d", pvt->inject.rank); + if (pvt->inject.page < 0) + sprintf(page, "any"); + else + sprintf(page, "0x%04x", pvt->inject.page); + if (pvt->inject.col < 0) + sprintf(col, "any"); + else + sprintf(col, "0x%04x", pvt->inject.col); + + return sprintf(data, "channel: %s\ndimm: %s\nbank: %s\n" + "rank: %s\npage: %s\ncolumn: %s\n", + channel, dimm, bank, rank, page, col); +} + +/* + * This routine prepares the Memory Controller for error injection. + * The error will be injected when some process tries to write to the + * memory that matches the given criteria. + * The criteria can be set in terms of a mask where dimm, rank, bank, page + * and col can be specified. + * A -1 value for any of the mask items will make the MCU to ignore + * that matching criteria for error injection. + * + * It should be noticed that the error will only happen after a write operation + * on a memory that matches the condition. if REPEAT_EN is not enabled at + * inject mask, then it will produce just one error. Otherwise, it will repeat + * until the injectmask would be cleaned. + * + * FIXME: This routine assumes that MAXNUMDIMMS value of MC_MAX_DOD + * is reliable enough to check if the MC is using the + * three channels. However, this is not clear at the datasheet. + */ +static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + u32 injectmask; + u64 mask = 0; + int rc; + long enable; + + rc = strict_strtoul(data, 10, &enable); + if ((rc < 0)) + return 0; + + if (enable) { + pvt->inject.enable = 1; + } else { + disable_inject(mci); + return count; + } + + /* Sets pvt->inject.dimm mask */ + if (pvt->inject.dimm < 0) + mask |= 1l << 41; + else { + if (maxnumdimms(pvt) > 2) + mask |= (pvt->inject.dimm & 0x3l) << 35; + else + mask |= (pvt->inject.dimm & 0x1l) << 36; + } + + /* Sets pvt->inject.rank mask */ + if (pvt->inject.rank < 0) + mask |= 1l << 40; + else { + if (maxnumdimms(pvt) > 2) + mask |= (pvt->inject.rank & 0x1l) << 34; + else + mask |= (pvt->inject.rank & 0x3l) << 34; + } + + /* Sets pvt->inject.bank mask */ + if (pvt->inject.bank < 0) + mask |= 1l << 39; + else + mask |= (pvt->inject.bank & 0x15l) << 30; + + /* Sets pvt->inject.page mask */ + if (pvt->inject.page < 0) + mask |= 1l << 38; + else + mask |= (pvt->inject.page & 0xffffl) << 14; + + /* Sets pvt->inject.column mask */ + if (pvt->inject.col < 0) + mask |= 1l << 37; + else + mask |= (pvt->inject.col & 0x3fffl); + + pci_write_config_qword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH, mask); + + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); + + /* + * bit 0: REPEAT_EN + * bits 1-2: MASK_HALF_CACHELINE + * bit 3: INJECT_ECC + * bit 4: INJECT_ADDR_PARITY + */ + + injectmask = (pvt->inject.type & 1) && + (pvt->inject.section & 0x3) << 1 && + (pvt->inject.type & 0x6) << (3 - 1); + + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ERROR_MASK, injectmask); + + + debugf0("Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n", + mask, pvt->inject.eccmask, injectmask); + + return count; +} + +static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + return sprintf(data, "%d\n", pvt->inject.enable); +} + +/* + * Sysfs struct + */ +static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { + + { + .attr = { + .name = "inject_section", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_section_show, + .store = i7core_inject_section_store, + }, { + .attr = { + .name = "inject_type", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_type_show, + .store = i7core_inject_type_store, + }, { + .attr = { + .name = "inject_eccmask", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_eccmask_show, + .store = i7core_inject_eccmask_store, + }, { + .attr = { + .name = "inject_addrmatch", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_addrmatch_show, + .store = i7core_inject_addrmatch_store, + }, { + .attr = { + .name = "inject_enable", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_enable_show, + .store = i7core_inject_enable_store, + }, +}; + /**************************************************************************** Device initialization routines: put/get, init/exit ****************************************************************************/ @@ -322,10 +723,11 @@ static int __devinit i7core_probe(struct pci_dev *pdev, debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); - mci->dev = &pdev->dev; /* record ptr to the generic device */ + mci->dev = &pdev->dev; /* record ptr to the generic device */ dev_set_drvdata(mci->dev, mci); pvt = mci->pvt_info; + // pvt->system_address = pdev; /* Record this device in our private */ // pvt->maxch = num_channels; // pvt->maxdimmperch = num_dimms_per_channel; @@ -343,6 +745,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->ctl_name = i7core_devs[dev_idx].ctl_name; mci->dev_name = pci_name(pdev); mci->ctl_page_to_phys = NULL; + mci->mc_driver_sysfs_attributes = i7core_inj_attrs; /* add this new MC control structure to EDAC's list of MCs */ if (edac_mc_add_mc(mci)) { @@ -365,6 +768,14 @@ static int __devinit i7core_probe(struct pci_dev *pdev, __func__); } + /* Default error mask is any memory */ + pvt->inject.channel = -1; + pvt->inject.dimm = -1; + pvt->inject.rank = -1; + pvt->inject.bank = -1; + pvt->inject.page = -1; + pvt->inject.col = -1; + return 0; fail1: -- GitLab From 0b2b7b7ec06ce615acd11374bf9a512e166dabb0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: [PATCH 086/842] i7core_edac: Add more status functions to EDAC driver This patch were co-authored with Aristeu Rozanski. Signed-off-by: Aristeu Sergio <arozansk@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 114 ++++++++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 19 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index b590f8468693..da40730bf9c9 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -62,6 +62,15 @@ /* OFFSETS for Devices 4,5 and 6 Function 0 */ +#define MC_CHANNEL_DIMM_INIT_PARAMS 0x58 + #define THREE_DIMMS_PRESENT (1 << 24) + #define SINGLE_QUAD_RANK_PRESENT (1 << 23) + #define QUAD_RANK_PRESENT (1 << 22) + #define REGISTERED_DIMM (1 << 15) + +#define MC_CHANNEL_RANK_PRESENT 0x7c + #define RANK_PRESENT_MASK 0xffff + #define MC_CHANNEL_ADDR_MATCH 0xf0 #define MC_CHANNEL_ERROR_MASK 0xf8 #define MC_CHANNEL_ERROR_INJECT 0xfc @@ -74,6 +83,46 @@ #define NO_MASK_CACHELINE 0x00 #define REPEAT_EN 0x01 + /* OFFSETS for Devices 4,5 and 6 Function 1 */ +#define MC_DOD_CH_DIMM0 0x48 +#define MC_DOD_CH_DIMM1 0x4c +#define MC_DOD_CH_DIMM2 0x50 + #define RANKOFFSET_MASK ((1 << 12) | (1 << 11) | (1 << 10)) + #define RANKOFFSET(x) ((x & RANKOFFSET_MASK) >> 10) + #define DIMM_PRESENT_MASK (1 << 9) + #define DIMM_PRESENT(x) (((x) & DIMM_PRESENT_MASK) >> 9) + #define NUMBANK_MASK ((1 << 8) | (1 << 7)) + #define NUMBANK(x) (((x) & NUMBANK_MASK) >> 7) + #define NUMRANK_MASK ((1 << 6) | (1 << 5)) + #define NUMRANK(x) (((x) & NUMRANK_MASK) >> 5) + #define NUMROW_MASK ((1 << 4) | (1 << 3)) + #define NUMROW(x) (((x) & NUMROW_MASK) >> 3) + #define NUMCOL_MASK 3 + #define NUMCOL(x) ((x) & NUMCOL_MASK) + +#define MC_SAG_CH_0 0x80 +#define MC_SAG_CH_1 0x84 +#define MC_SAG_CH_2 0x88 +#define MC_SAG_CH_3 0x8c +#define MC_SAG_CH_4 0x90 +#define MC_SAG_CH_5 0x94 +#define MC_SAG_CH_6 0x98 +#define MC_SAG_CH_7 0x9c + +#define MC_RIR_LIMIT_CH_0 0x40 +#define MC_RIR_LIMIT_CH_1 0x44 +#define MC_RIR_LIMIT_CH_2 0x48 +#define MC_RIR_LIMIT_CH_3 0x4C +#define MC_RIR_LIMIT_CH_4 0x50 +#define MC_RIR_LIMIT_CH_5 0x54 +#define MC_RIR_LIMIT_CH_6 0x58 +#define MC_RIR_LIMIT_CH_7 0x5C +#define MC_RIR_LIMIT_MASK ((1 << 10) - 1) + +#define MC_RIR_WAY_CH 0x80 + #define MC_RIR_WAY_OFFSET_MASK (((1 << 14) - 1) & ~0x7) + #define MC_RIR_WAY_RANK_MASK 0x7 + /* * i7core structs */ @@ -99,11 +148,17 @@ struct i7core_inject { int channel, dimm, rank, bank, page, col; }; +struct i7core_channel { + u32 ranks; + u32 dimms; +}; + struct i7core_pvt { struct pci_dev *pci_mcr; /* Dev 3:0 */ struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS]; struct i7core_info info; struct i7core_inject inject; + struct i7core_channel channel[NUM_CHANS]; }; /* Device name and register DID (Device ID) */ @@ -133,16 +188,12 @@ static struct edac_pci_ctl_info *i7core_pci; ****************************************************************************/ /* MC_CONTROL bits */ -#define CH2_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 10) -#define CH1_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 9) -#define CH0_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 8) +#define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & 1 << (8 + ch)) #define ECCx8(pvt) ((pvt)->info.mc_control & 1 << 1) /* MC_STATUS bits */ #define ECC_ENABLED(pvt) ((pvt)->info.mc_status & 1 << 3) -#define CH2_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 2) -#define CH1_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 1) -#define CH0_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 0) +#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & 1 << ch) /* MC_MAX_DOD read functions */ static inline int maxnumdimms(struct i7core_pvt *pvt) @@ -189,19 +240,12 @@ static inline int maxnumcol(struct i7core_pvt *pvt) static int get_dimm_config(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; + int i; pci_read_config_dword(pvt->pci_mcr, MC_CONTROL, &pvt->info.mc_control); pci_read_config_dword(pvt->pci_mcr, MC_STATUS, &pvt->info.mc_status); pci_read_config_dword(pvt->pci_mcr, MC_MAX_DOD, &pvt->info.max_dod); - debugf0("Channels active [%c][%c][%c] - enabled [%c][%c][%c]\n", - CH0_ACTIVE(pvt)?'0':'-', - CH1_ACTIVE(pvt)?'1':'-', - CH2_ACTIVE(pvt)?'2':'-', - CH0_DISABLED(pvt)?'-':'0', - CH1_DISABLED(pvt)?'-':'1', - CH2_DISABLED(pvt)?'-':'2'); - if (ECC_ENABLED(pvt)) debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); else @@ -213,6 +257,38 @@ static int get_dimm_config(struct mem_ctl_info *mci) debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n", maxnumrow(pvt), maxnumcol(pvt)); + debugf0("Memory channel configuration:\n"); + + for (i = 0; i < NUM_CHANS; i++) { + u32 data; + + if (!CH_ACTIVE(pvt, i)) { + debugf0("Channel %i is not active\n", i); + continue; + } + if (CH_DISABLED(pvt, i)) { + debugf0("Channel %i is disabled\n", i); + continue; + } + + pci_read_config_dword(pvt->pci_ch[i][0], + MC_CHANNEL_DIMM_INIT_PARAMS, &data); + + pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT)? 4 : 2; + + if (data & THREE_DIMMS_PRESENT) + pvt->channel[i].dimms = 3; + else if (data & SINGLE_QUAD_RANK_PRESENT) + pvt->channel[i].dimms = 1; + else + pvt->channel[i].dimms = 2; + + debugf0("Channel %d (0x%08x): %d ranks, %d dimms " + "(%sregistered)\n", i, data, + pvt->channel[i].ranks, pvt->channel[i].dimms, + (data & REGISTERED_DIMM)? "" : "un" ); + } + return 0; } @@ -489,7 +565,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.dimm < 0) mask |= 1l << 41; else { - if (maxnumdimms(pvt) > 2) + if (pvt->channel[pvt->inject.channel].dimms > 2) mask |= (pvt->inject.dimm & 0x3l) << 35; else mask |= (pvt->inject.dimm & 0x1l) << 36; @@ -499,7 +575,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.rank < 0) mask |= 1l << 40; else { - if (maxnumdimms(pvt) > 2) + if (pvt->channel[pvt->inject.channel].dimms > 2) mask |= (pvt->inject.rank & 0x1l) << 34; else mask |= (pvt->inject.rank & 0x3l) << 34; @@ -646,9 +722,6 @@ static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx) } pvt->pci_mcr=pdev; - /* Get dimm basic config */ - get_dimm_config(mci); - /* Retrieve all needed functions at MTR channel controllers */ for (i = 0; i < NUM_CHANS; i++) { pdev = NULL; @@ -672,6 +745,9 @@ static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx) } i7core_printk(KERN_INFO, "Driver loaded.\n"); + /* Get dimm basic config */ + get_dimm_config(mci); + return 0; } -- GitLab From 8f331907578623f90a134261a559fa3249142caa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: [PATCH 087/842] i7core_edac: Registers all supported MC functions Now, it will try to register on all supported Memory Controller functions. It should be noticed that dev3, function 2 is present only on chips with Registered DIMM's, according to the datasheet. So, the driver doesn't return -ENODEV is all functions but this one were successfully registered and enabled: EDAC i7core: Registered device 8086:2c18 fn=3 0 EDAC i7core: Registered device 8086:2c19 fn=3 1 EDAC i7core: Device not found: PCI ID 8086:2c1a (dev 3, func 2) EDAC i7core: Registered device 8086:2c1c fn=3 4 EDAC i7core: Registered device 8086:2c20 fn=4 0 EDAC i7core: Registered device 8086:2c21 fn=4 1 EDAC i7core: Registered device 8086:2c22 fn=4 2 EDAC i7core: Registered device 8086:2c23 fn=4 3 EDAC i7core: Registered device 8086:2c28 fn=5 0 EDAC i7core: Registered device 8086:2c29 fn=5 1 EDAC i7core: Registered device 8086:2c2a fn=5 2 EDAC i7core: Registered device 8086:2c2b fn=5 3 EDAC i7core: Registered device 8086:2c30 fn=6 0 EDAC i7core: Registered device 8086:2c31 fn=6 1 EDAC i7core: Registered device 8086:2c32 fn=6 2 EDAC i7core: Registered device 8086:2c33 fn=6 3 EDAC i7core: Driver loaded. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 217 ++++++++++++++++++++++--------------- 1 file changed, 131 insertions(+), 86 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index da40730bf9c9..79aa84eaa12d 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -128,7 +128,8 @@ */ #define NUM_CHANS 3 -#define NUM_FUNCS 1 +#define NUM_MCR_FUNCS 4 +#define NUM_CHAN_FUNCS 3 struct i7core_info { u32 mc_control; @@ -153,9 +154,16 @@ struct i7core_channel { u32 dimms; }; +struct pci_id_descr { + int dev; + int func; + int dev_id; + struct pci_dev *pdev; +}; + struct i7core_pvt { - struct pci_dev *pci_mcr; /* Dev 3:0 */ - struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS]; + struct pci_dev *pci_mcr[NUM_MCR_FUNCS]; + struct pci_dev *pci_ch[NUM_CHANS][NUM_CHAN_FUNCS]; struct i7core_info info; struct i7core_inject inject; struct i7core_channel channel[NUM_CHANS]; @@ -167,11 +175,47 @@ struct i7core_dev_info { u16 fsb_mapping_errors; /* DID for the branchmap,control */ }; -static int chan_pci_ids[NUM_CHANS] = { - PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL, /* Dev 4 */ - PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL, /* Dev 5 */ - PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL, /* Dev 6 */ +#define PCI_DESCR(device, function, device_id) \ + .dev = (device), \ + .func = (function), \ + .dev_id = (device_id) + +struct pci_id_descr pci_devs[] = { + /* Memory controller */ + { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, + { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, + { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM is supported */ + { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, + + /* Channel 0 */ + { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) }, + { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) }, + { PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK) }, + { PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC) }, + + /* Channel 1 */ + { PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL) }, + { PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR) }, + { PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK) }, + { PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC) }, + + /* Channel 2 */ + { PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL) }, + { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) }, + { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) }, + { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) }, }; +#define N_DEVS ARRAY_SIZE(pci_devs) + +/* + * pci_device_id table for which devices we are looking for + * This should match the first device at pci_devs table + */ +static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)}, + {0,} /* 0 terminated list. */ +}; + /* Table of devices attributes supported by this driver */ static const struct i7core_dev_info i7core_devs[] = { @@ -242,9 +286,12 @@ static int get_dimm_config(struct mem_ctl_info *mci) struct i7core_pvt *pvt = mci->pvt_info; int i; - pci_read_config_dword(pvt->pci_mcr, MC_CONTROL, &pvt->info.mc_control); - pci_read_config_dword(pvt->pci_mcr, MC_STATUS, &pvt->info.mc_status); - pci_read_config_dword(pvt->pci_mcr, MC_MAX_DOD, &pvt->info.max_dod); + if (!pvt->pci_mcr[0]) + return -ENODEV; + + pci_read_config_dword(pvt->pci_mcr[0], MC_CONTROL, &pvt->info.mc_control); + pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, &pvt->info.mc_status); + pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, &pvt->info.max_dod); if (ECC_ENABLED(pvt)) debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); @@ -303,14 +350,19 @@ static int get_dimm_config(struct mem_ctl_info *mci) we're disabling error injection on all write calls to the sysfs nodes that controls the error code injection. */ -static void disable_inject(struct mem_ctl_info *mci) +static int disable_inject(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; pvt->inject.enable = 0; + if (!pvt->pci_ch[pvt->inject.channel][0]) + return -ENODEV; + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, 0); + + return 0; } /* @@ -550,6 +602,9 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, int rc; long enable; + if (!pvt->pci_ch[pvt->inject.channel][0]) + return 0; + rc = strict_strtoul(data, 10, &enable); if ((rc < 0)) return 0; @@ -684,17 +739,12 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { * i7core_put_devices 'put' all the devices that we have * reserved via 'get' */ -static void i7core_put_devices(struct mem_ctl_info *mci) +static void i7core_put_devices(void) { - struct i7core_pvt *pvt = mci->pvt_info; - int i, n; - - pci_dev_put(pvt->pci_mcr); + int i; - /* Release all PCI device functions at MTR channel controllers */ - for (i = 0; i < NUM_CHANS; i++) - for (n = 0; n < NUM_FUNCS; n++) - pci_dev_put(pvt->pci_ch[i][n]); + for (i = 0; i < N_DEVS; i++) + pci_dev_put(pci_devs[i].pdev); } /* @@ -703,50 +753,67 @@ static void i7core_put_devices(struct mem_ctl_info *mci) * * Need to 'get' device 16 func 1 and func 2 */ -static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx) +static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) { - struct i7core_pvt *pvt; - struct pci_dev *pdev; - int i, n, func; + struct i7core_pvt *pvt = mci->pvt_info; + int rc, i,func; + struct pci_dev *pdev = NULL; pvt = mci->pvt_info; memset(pvt, 0, sizeof(*pvt)); - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR, - NULL); - if (!pdev) { - i7core_printk(KERN_ERR, - "Couldn't get PCI ID %04x:%04x function 0\n", - PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR); - return -ENODEV; - } - pvt->pci_mcr=pdev; + for (i = 0; i < N_DEVS; i++) { + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + pci_devs[i].dev_id, NULL); + if (!pdev) { + /* End of list, leave */ + i7core_printk(KERN_ERR, + "Device not found: PCI ID %04x:%04x " + "(dev %d, func %d)\n", + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, + pci_devs[i].dev,pci_devs[i].func); + if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) + continue; /* Only on chips with RDIMMs */ + else + i7core_put_devices(); + } + pci_devs[i].pdev = pdev; + + rc = pci_enable_device(pdev); + if (rc < 0) { + i7core_printk(KERN_ERR, + "Couldn't enable PCI ID %04x:%04x " + "(dev %d, func %d)\n", + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, + pci_devs[i].dev, pci_devs[i].func); + i7core_put_devices(); + return rc; + } + /* Sanity check */ + if (PCI_FUNC(pdev->devfn) != pci_devs[i].func) { + i7core_printk(KERN_ERR, + "Device PCI ID %04x:%04x " + "has function %d instead of %d\n", + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, + PCI_FUNC(pdev->devfn), pci_devs[i].func); + i7core_put_devices(); + return -EINVAL; + } - /* Retrieve all needed functions at MTR channel controllers */ - for (i = 0; i < NUM_CHANS; i++) { - pdev = NULL; - for (n = 0; n < NUM_FUNCS; n++) { - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - chan_pci_ids[i], pdev); - if (!pdev) { - /* End of list, leave */ - i7core_printk(KERN_ERR, - "Device not found: PCI ID %04x:%04x " - "found only %d functions " - "(broken BIOS?)\n", - PCI_VENDOR_ID_INTEL, - chan_pci_ids[i], n); - i7core_put_devices(mci); - return -ENODEV; - } - func = PCI_FUNC(pdev->devfn); - pvt->pci_ch[i][func] = pdev; + i7core_printk(KERN_INFO, + "Registered device %0x:%0x fn=%0x %0x\n", + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + + func = PCI_FUNC(pdev->devfn); + if (pci_devs[i].dev < 4) { + pvt->pci_mcr[func] = pdev; + } else { + pvt->pci_ch[pci_devs[i].dev - 4][func] = pdev; } } - i7core_printk(KERN_INFO, "Driver loaded.\n"); - /* Get dimm basic config */ - get_dimm_config(mci); + i7core_printk(KERN_INFO, "Driver loaded.\n"); return 0; } @@ -763,7 +830,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int rc; int num_channels; int num_csrows; int num_dimms_per_channel; @@ -772,20 +838,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, if (dev_idx >= ARRAY_SIZE(i7core_devs)) return -EINVAL; - /* wake up device */ - rc = pci_enable_device(pdev); - if (rc == -EIO) - return rc; - - debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", - __func__, - pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - - /* We only are looking for func 0 of the set */ - if (PCI_FUNC(pdev->devfn) != 0) - return -ENODEV; - num_channels = NUM_CHANS; /* FIXME: FAKE data, since we currently don't now how to get this */ @@ -808,10 +860,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, // pvt->maxch = num_channels; // pvt->maxdimmperch = num_dimms_per_channel; - /* 'get' the pci devices we want to reserve for our use */ - if (i7core_get_devices(mci, dev_idx)) - goto fail0; - mci->mc_idx = 0; mci->mtype_cap = MEM_FLAG_FB_DDR2; /* FIXME: it uses DDR3 */ mci->edac_ctl_cap = EDAC_FLAG_NONE; @@ -823,6 +871,10 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->ctl_page_to_phys = NULL; mci->mc_driver_sysfs_attributes = i7core_inj_attrs; + /* 'get' the pci devices we want to reserve for our use */ + if (i7core_get_devices(mci, pdev)) + goto fail0; + /* add this new MC control structure to EDAC's list of MCs */ if (edac_mc_add_mc(mci)) { debugf0("MC: " __FILE__ @@ -852,10 +904,13 @@ static int __devinit i7core_probe(struct pci_dev *pdev, pvt->inject.page = -1; pvt->inject.col = -1; + /* Get dimm basic config */ + get_dimm_config(mci); + return 0; fail1: - i7core_put_devices(mci); + i7core_put_devices(); fail0: edac_mc_free(mci); @@ -880,21 +935,11 @@ static void __devexit i7core_remove(struct pci_dev *pdev) return; /* retrieve references to resources, and free those resources */ - i7core_put_devices(mci); + i7core_put_devices(); edac_mc_free(mci); } -/* - * pci_device_id table for which devices we are looking for - * - * The "E500P" device is the first device supported. - */ -static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)}, - {0,} /* 0 terminated list. */ -}; - MODULE_DEVICE_TABLE(pci, i7core_pci_tbl); /* -- GitLab From f122a89222510e8f57e8e0b9b5cdd3ec8863fe4c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: [PATCH 088/842] i7core_edac: Show read/write virtual/physical channel association Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 79aa84eaa12d..09a0998e1c3f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -68,6 +68,10 @@ #define QUAD_RANK_PRESENT (1 << 22) #define REGISTERED_DIMM (1 << 15) +#define MC_CHANNEL_MAPPER 0x60 + #define RDLCH(r, ch) ((((r) >> (3 + (ch * 6))) & 0x07) - 1) + #define WRLCH(r, ch) ((((r) >> (ch * 6)) & 0x07) - 1) + #define MC_CHANNEL_RANK_PRESENT 0x7c #define RANK_PRESENT_MASK 0xffff @@ -100,6 +104,8 @@ #define NUMCOL_MASK 3 #define NUMCOL(x) ((x) & NUMCOL_MASK) +#define MC_RANK_PRESENT 0x7c + #define MC_SAG_CH_0 0x80 #define MC_SAG_CH_1 0x84 #define MC_SAG_CH_2 0x88 @@ -135,6 +141,7 @@ struct i7core_info { u32 mc_control; u32 mc_status; u32 max_dod; + u32 ch_map; }; @@ -289,9 +296,19 @@ static int get_dimm_config(struct mem_ctl_info *mci) if (!pvt->pci_mcr[0]) return -ENODEV; - pci_read_config_dword(pvt->pci_mcr[0], MC_CONTROL, &pvt->info.mc_control); - pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, &pvt->info.mc_status); - pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, &pvt->info.max_dod); + /* Device 3 function 0 reads */ + pci_read_config_dword(pvt->pci_mcr[0], MC_CONTROL, + &pvt->info.mc_control); + pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, + &pvt->info.mc_status); + pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, + &pvt->info.max_dod); + pci_read_config_dword(pvt->pci_mcr[0], MC_CHANNEL_MAPPER, + &pvt->info.ch_map); + + debugf0("MC control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n", + pvt->info.mc_control, pvt->info.mc_status, + pvt->info.max_dod, pvt->info.ch_map); if (ECC_ENABLED(pvt)) debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); @@ -318,6 +335,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) continue; } + /* Devices 4-6 function 0 */ pci_read_config_dword(pvt->pci_ch[i][0], MC_CHANNEL_DIMM_INIT_PARAMS, &data); @@ -330,10 +348,13 @@ static int get_dimm_config(struct mem_ctl_info *mci) else pvt->channel[i].dimms = 2; - debugf0("Channel %d (0x%08x): %d ranks, %d dimms " - "(%sregistered)\n", i, data, + debugf0("Ch%d (0x%08x): rd ch %d, wr ch %d, " + "%d ranks, %d %cDIMMs\n", + i, data, + RDLCH(pvt->info.ch_map, i), + WRLCH(pvt->info.ch_map, i), pvt->channel[i].ranks, pvt->channel[i].dimms, - (data & REGISTERED_DIMM)? "" : "un" ); + (data & REGISTERED_DIMM)? 'R' : 'U' ); } return 0; -- GitLab From 7b029d03c36e5b06e067884aaefcee2c1c62efc7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: [PATCH 089/842] i7core_edac: A few fixes at error injection code Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 70 ++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 09a0998e1c3f..0c17db673065 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -30,6 +30,8 @@ #include "edac_core.h" +/* To use the new pci_[read/write]_config_qword instead of two dword */ +#define USE_QWORD 1 /* * Alter this version for the module when modifications are made @@ -639,44 +641,71 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, /* Sets pvt->inject.dimm mask */ if (pvt->inject.dimm < 0) - mask |= 1l << 41; + mask |= 1L << 41; else { if (pvt->channel[pvt->inject.channel].dimms > 2) - mask |= (pvt->inject.dimm & 0x3l) << 35; + mask |= (pvt->inject.dimm & 0x3L) << 35; else - mask |= (pvt->inject.dimm & 0x1l) << 36; + mask |= (pvt->inject.dimm & 0x1L) << 36; } /* Sets pvt->inject.rank mask */ if (pvt->inject.rank < 0) - mask |= 1l << 40; + mask |= 1L << 40; else { if (pvt->channel[pvt->inject.channel].dimms > 2) - mask |= (pvt->inject.rank & 0x1l) << 34; + mask |= (pvt->inject.rank & 0x1L) << 34; else - mask |= (pvt->inject.rank & 0x3l) << 34; + mask |= (pvt->inject.rank & 0x3L) << 34; } /* Sets pvt->inject.bank mask */ if (pvt->inject.bank < 0) - mask |= 1l << 39; + mask |= 1L << 39; else - mask |= (pvt->inject.bank & 0x15l) << 30; + mask |= (pvt->inject.bank & 0x15L) << 30; /* Sets pvt->inject.page mask */ if (pvt->inject.page < 0) - mask |= 1l << 38; + mask |= 1L << 38; else - mask |= (pvt->inject.page & 0xffffl) << 14; + mask |= (pvt->inject.page & 0xffffL) << 14; /* Sets pvt->inject.column mask */ if (pvt->inject.col < 0) - mask |= 1l << 37; + mask |= 1L << 37; else - mask |= (pvt->inject.col & 0x3fffl); + mask |= (pvt->inject.col & 0x3fffL); +#if USE_QWORD pci_write_config_qword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); +#else + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH, mask); + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L); +#endif + +#if 1 +#if USE_QWORD + u64 rdmask; + pci_read_config_qword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH, &rdmask); + debugf0("Inject addr match write 0x%016llx, read: 0x%016llx\n", + mask, rdmask); +#else + u32 rdmask1, rdmask2; + + pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH, &rdmask1); + pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ADDR_MATCH + 4, &rdmask2); + + debugf0("Inject addr match write 0x%016llx, read: 0x%08x%08x\n", + mask, rdmask1, rdmask2); +#endif +#endif pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); @@ -688,17 +717,18 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, * bit 4: INJECT_ADDR_PARITY */ - injectmask = (pvt->inject.type & 1) && - (pvt->inject.section & 0x3) << 1 && + injectmask = (pvt->inject.type & 1) | + (pvt->inject.section & 0x3) << 1 | (pvt->inject.type & 0x6) << (3 - 1); pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, injectmask); - debugf0("Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n", mask, pvt->inject.eccmask, injectmask); + + return count; } @@ -706,6 +736,16 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, char *data) { struct i7core_pvt *pvt = mci->pvt_info; + u32 injectmask; + + pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + MC_CHANNEL_ERROR_MASK, &injectmask); + + debugf0("Inject error read: 0x%018x\n", injectmask); + + if (injectmask & 0x0c) + pvt->inject.enable = 1; + return sprintf(data, "%d\n", pvt->inject.enable); } -- GitLab From 87d1d272ba25a1863e40ebb1df4bc0eed7a8fd11 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: [PATCH 090/842] i7core_edac: need mci->edac_check, otherwise module removal doesn't work There are some locking troubles with edac_core: if you don't declare an edac_check, module may suffer from soft lock. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 0c17db673065..190596af601a 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -879,6 +879,15 @@ static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) return 0; } +/* + * i7core_check_error Retrieve and process errors reported by the + * hardware. Called by the Core module. + */ +static void i7core_check_error(struct mem_ctl_info *mci) +{ + /* FIXME: need a real code here */ +} + /* * i7core_probe Probe for ONE instance of device to see if it is * present. @@ -912,8 +921,11 @@ static int __devinit i7core_probe(struct pci_dev *pdev, debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); + /* 'get' the pci devices we want to reserve for our use */ + if (i7core_get_devices(mci, pdev)) + goto fail0; + mci->dev = &pdev->dev; /* record ptr to the generic device */ - dev_set_drvdata(mci->dev, mci); pvt = mci->pvt_info; @@ -932,9 +944,8 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->ctl_page_to_phys = NULL; mci->mc_driver_sysfs_attributes = i7core_inj_attrs; - /* 'get' the pci devices we want to reserve for our use */ - if (i7core_get_devices(mci, pdev)) - goto fail0; + /* Set the function pointer to an actual operation function */ + mci->edac_check = i7core_check_error; /* add this new MC control structure to EDAC's list of MCs */ if (edac_mc_add_mc(mci)) { @@ -992,6 +1003,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) edac_pci_release_generic_ctl(i7core_pci); mci = edac_mc_del_mc(&pdev->dev); + if (!mci) return; -- GitLab From 442305b152778f07504e9fdf64815d4841279bbe Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:29 -0300 Subject: [PATCH 091/842] i7core_edac: Add a memory check routine, based on device 3 function 4 This function appears only on Xeon 5500 datasheet. Yet, testing with a Xeon 3503 showed that this is also implemented on other Nehalem processors. At the first read, MC_TEST_ERR_RCV1 and MC_TEST_ERR_RCV0 can contain any value. Modify CE error logic to update the error count only after the second read. An alternative approach would be to do a write at rcv0 and rcv1 registers, but it seemed better to keep they untouched, since BIOS might eventually assume that they are exclusive for their usage. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 115 ++++++++++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 7 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 190596af601a..b5dbc2b83961 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -62,6 +62,18 @@ #define MC_STATUS 0x4c #define MC_MAX_DOD 0x64 +/* + * OFFSETS for Device 3 Function 4, as inicated on Xeon 5500 datasheet: + * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf + */ + +#define MC_TEST_ERR_RCV1 0x60 + #define DIMM2_COR_ERR(r) ((r) & 0x7fff) + +#define MC_TEST_ERR_RCV0 0x64 + #define DIMM1_COR_ERR(r) (((r) >> 16) & 0x7fff) + #define DIMM0_COR_ERR(r) ((r) & 0x7fff) + /* OFFSETS for Devices 4,5 and 6 Function 0 */ #define MC_CHANNEL_DIMM_INIT_PARAMS 0x58 @@ -136,8 +148,9 @@ */ #define NUM_CHANS 3 -#define NUM_MCR_FUNCS 4 -#define NUM_CHAN_FUNCS 3 +#define MAX_DIMMS 3 /* Max DIMMS per channel */ +#define MAX_MCR_FUNC 4 +#define MAX_CHAN_FUNC 3 struct i7core_info { u32 mc_control; @@ -159,8 +172,8 @@ struct i7core_inject { }; struct i7core_channel { - u32 ranks; - u32 dimms; + u32 ranks; + u32 dimms; }; struct pci_id_descr { @@ -171,11 +184,16 @@ struct pci_id_descr { }; struct i7core_pvt { - struct pci_dev *pci_mcr[NUM_MCR_FUNCS]; - struct pci_dev *pci_ch[NUM_CHANS][NUM_CHAN_FUNCS]; + struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1]; + struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1]; struct i7core_info info; struct i7core_inject inject; struct i7core_channel channel[NUM_CHANS]; + + int ce_count_available; + unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */ + int last_ce_count[MAX_DIMMS]; + }; /* Device name and register DID (Device ID) */ @@ -749,6 +767,19 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, return sprintf(data, "%d\n", pvt->inject.enable); } +static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + + if (!pvt->ce_count_available) + return sprintf(data, "unavailable\n"); + + return sprintf(data, "dimm0: %lu\ndimm1: %lu\ndimm2: %lu\n", + pvt->ce_count[0], + pvt->ce_count[1], + pvt->ce_count[2]); +} + /* * Sysfs struct */ @@ -789,6 +820,13 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { }, .show = i7core_inject_enable_show, .store = i7core_inject_enable_store, + }, { + .attr = { + .name = "corrected_error_counts", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_ce_regs_show, + .store = NULL, }, }; @@ -879,13 +917,76 @@ static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) return 0; } +/**************************************************************************** + Error check routines + ****************************************************************************/ + +/* This function is based on the device 3 function 4 registers as described on: + * Intel Xeon Processor 5500 Series Datasheet Volume 2 + * http://www.intel.com/Assets/PDF/datasheet/321322.pdf + * also available at: + * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf + */ +static void check_mc_test_err(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + u32 rcv1, rcv0; + int new0, new1, new2; + + if (!pvt->pci_mcr[4]) { + debugf0("%s MCR registers not found\n",__func__); + return; + } + + /* Corrected error reads */ + pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1); + pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0); + + /* Store the new values */ + new2 = DIMM2_COR_ERR(rcv1); + new1 = DIMM1_COR_ERR(rcv0); + new0 = DIMM0_COR_ERR(rcv0); + + debugf2("%s CE rcv1=0x%08x rcv0=0x%08x, %d %d %d\n", + (pvt->ce_count_available ? "UPDATE" : "READ"), + rcv1, rcv0, new0, new1, new2); + + /* Updates CE counters if it is not the first time here */ + if (pvt->ce_count_available) { + /* Updates CE counters */ + int add0, add1, add2; + + add2 = new2 - pvt->last_ce_count[2]; + add1 = new1 - pvt->last_ce_count[1]; + add0 = new0 - pvt->last_ce_count[0]; + + if (add2 < 0) + add2 += 0x7fff; + pvt->ce_count[2] += add2; + + if (add1 < 0) + add1 += 0x7fff; + pvt->ce_count[1] += add1; + + if (add0 < 0) + add0 += 0x7fff; + pvt->ce_count[0] += add0; + } else + pvt->ce_count_available = 1; + + /* Store the new values */ + pvt->last_ce_count[2] = new2; + pvt->last_ce_count[1] = new1; + pvt->last_ce_count[0] = new0; +} + /* * i7core_check_error Retrieve and process errors reported by the * hardware. Called by the Core module. */ static void i7core_check_error(struct mem_ctl_info *mci) { - /* FIXME: need a real code here */ + check_mc_test_err(mci); } /* -- GitLab From ef708b53b98f2b53d9686a9f8f0b8d437952c295 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:30 -0300 Subject: [PATCH 092/842] i7core_edac: Add additional tests for error detection Properly check the number of channels and improve probing error detection Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 199 ++++++++++++++++++++++++++----------- 1 file changed, 139 insertions(+), 60 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index b5dbc2b83961..bfa462f6fa0e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -189,6 +189,7 @@ struct i7core_pvt { struct i7core_info info; struct i7core_inject inject; struct i7core_channel channel[NUM_CHANS]; + int channels; /* Number of active channels */ int ce_count_available; unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */ @@ -259,12 +260,12 @@ static struct edac_pci_ctl_info *i7core_pci; ****************************************************************************/ /* MC_CONTROL bits */ -#define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & 1 << (8 + ch)) -#define ECCx8(pvt) ((pvt)->info.mc_control & 1 << 1) +#define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & (1 << (8 + ch))) +#define ECCx8(pvt) ((pvt)->info.mc_control & (1 << 1)) /* MC_STATUS bits */ -#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & 1 << 3) -#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & 1 << ch) +#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & (1 << 3)) +#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch)) /* MC_MAX_DOD read functions */ static inline int maxnumdimms(struct i7core_pvt *pvt) @@ -308,6 +309,48 @@ static inline int maxnumcol(struct i7core_pvt *pvt) /**************************************************************************** Memory check routines ****************************************************************************/ +static int i7core_get_active_channels(int *channels) +{ + struct pci_dev *pdev = NULL; + int i; + u32 status, control; + + *channels = 0; + + for (i = 0; i < N_DEVS; i++) { + if (!pci_devs[i].pdev) + continue; + + if (PCI_SLOT(pci_devs[i].pdev->devfn) == 3 && + PCI_FUNC(pci_devs[i].pdev->devfn) == 0) { + pdev = pci_devs[i].pdev; + break; + } + } + + if (!pdev) + return -ENODEV; + + /* Device 3 function 0 reads */ + pci_read_config_dword(pdev, MC_STATUS, &status); + pci_read_config_dword(pdev, MC_CONTROL, &control); + + for (i = 0; i < NUM_CHANS; i++) { + /* Check if the channel is active */ + if (!(control & (1 << (8 + i)))) + continue; + + /* Check if the channel is disabled */ + if (status & (1 << i)) { + continue; + } + + (*channels)++; + } + + return 0; +} + static int get_dimm_config(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; @@ -852,69 +895,103 @@ static void i7core_put_devices(void) * * Need to 'get' device 16 func 1 and func 2 */ -static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) +static int i7core_get_devices(void) { - struct i7core_pvt *pvt = mci->pvt_info; - int rc, i,func; + int rc, i; struct pci_dev *pdev = NULL; - pvt = mci->pvt_info; - memset(pvt, 0, sizeof(*pvt)); - for (i = 0; i < N_DEVS; i++) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, NULL); - if (!pdev) { - /* End of list, leave */ + if (likely(pdev)) + pci_devs[i].pdev = pdev; + else { i7core_printk(KERN_ERR, "Device not found: PCI ID %04x:%04x " "(dev %d, func %d)\n", PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, pci_devs[i].dev,pci_devs[i].func); + + /* Dev 3 function 2 only exists on chips with RDIMMs */ if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) - continue; /* Only on chips with RDIMMs */ - else - i7core_put_devices(); + continue; + + /* End of list, leave */ + rc = -ENODEV; + goto error; } - pci_devs[i].pdev = pdev; - rc = pci_enable_device(pdev); - if (rc < 0) { + /* Sanity check */ + if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[i].dev || + PCI_FUNC(pdev->devfn) != pci_devs[i].func)) { i7core_printk(KERN_ERR, - "Couldn't enable PCI ID %04x:%04x " - "(dev %d, func %d)\n", + "Device PCI ID %04x:%04x " + "has fn %d.%d instead of fn %d.%d\n", PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pci_devs[i].dev, pci_devs[i].func); - i7core_put_devices(); - return rc; + rc = -EINVAL; + goto error; } - /* Sanity check */ - if (PCI_FUNC(pdev->devfn) != pci_devs[i].func) { + + /* Be sure that the device is enabled */ + rc = pci_enable_device(pdev); + if (unlikely(rc < 0)) { i7core_printk(KERN_ERR, - "Device PCI ID %04x:%04x " - "has function %d instead of %d\n", + "Couldn't enable PCI ID %04x:%04x " + "fn %d.%d\n", PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - PCI_FUNC(pdev->devfn), pci_devs[i].func); - i7core_put_devices(); - return -EINVAL; + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + goto error; } i7core_printk(KERN_INFO, - "Registered device %0x:%0x fn=%0x %0x\n", + "Registered device %0x:%0x fn %d.%d\n", PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + } + + return 0; + +error: + i7core_put_devices(); + return -EINVAL; +} + +static int mci_bind_devs(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + struct pci_dev *pdev; + int i, func, slot; + + for (i = 0; i < N_DEVS; i++) { + pdev = pci_devs[i].pdev; + if (!pdev) + continue; func = PCI_FUNC(pdev->devfn); - if (pci_devs[i].dev < 4) { + slot = PCI_SLOT(pdev->devfn); + if (slot == 3) { + if (unlikely(func > MAX_MCR_FUNC)) + goto error; pvt->pci_mcr[func] = pdev; - } else { - pvt->pci_ch[pci_devs[i].dev - 4][func] = pdev; - } + } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { + if (unlikely(func > MAX_CHAN_FUNC)) + goto error; + pvt->pci_ch[slot - 4][func] = pdev; + } else + goto error; + + debugf0("Associated fn %d.%d, dev = %p\n", + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev); } - - i7core_printk(KERN_INFO, "Driver loaded.\n"); - return 0; + +error: + i7core_printk(KERN_ERR, "Device %d, function %d " + "is out of the expected range\n", + slot, func); + return -EINVAL; } /**************************************************************************** @@ -1001,41 +1078,38 @@ static int __devinit i7core_probe(struct pci_dev *pdev, { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int num_channels; + int num_channels = 0; int num_csrows; - int num_dimms_per_channel; int dev_idx = id->driver_data; - if (dev_idx >= ARRAY_SIZE(i7core_devs)) + if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs))) return -EINVAL; - num_channels = NUM_CHANS; + /* get the pci devices we want to reserve for our use */ + if (unlikely(i7core_get_devices() < 0)) + return -ENODEV; + + /* Check the number of active and not disabled channels */ + if (unlikely (i7core_get_active_channels(&num_channels)) < 0) + goto fail0; - /* FIXME: FAKE data, since we currently don't now how to get this */ - num_dimms_per_channel = 4; - num_csrows = num_dimms_per_channel; + /* FIXME: we currently don't know the number of csrows */ + num_csrows = num_channels; /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); - if (mci == NULL) + if (unlikely (!mci)) return -ENOMEM; debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); - /* 'get' the pci devices we want to reserve for our use */ - if (i7core_get_devices(mci, pdev)) - goto fail0; - mci->dev = &pdev->dev; /* record ptr to the generic device */ pvt = mci->pvt_info; - -// pvt->system_address = pdev; /* Record this device in our private */ -// pvt->maxch = num_channels; -// pvt->maxdimmperch = num_dimms_per_channel; + memset(pvt, 0, sizeof(*pvt)); mci->mc_idx = 0; - mci->mtype_cap = MEM_FLAG_FB_DDR2; /* FIXME: it uses DDR3 */ + mci->mtype_cap = MEM_FLAG_DDR3; /* FIXME: how to handle RDDR3? */ mci->edac_ctl_cap = EDAC_FLAG_NONE; mci->edac_cap = EDAC_FLAG_NONE; mci->mod_name = "i7core_edac.c"; @@ -1044,12 +1118,18 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->dev_name = pci_name(pdev); mci->ctl_page_to_phys = NULL; mci->mc_driver_sysfs_attributes = i7core_inj_attrs; - /* Set the function pointer to an actual operation function */ mci->edac_check = i7core_check_error; + /* Store pci devices at mci for faster access */ + if (unlikely (mci_bind_devs(mci)) < 0) + goto fail1; + + /* Get dimm basic config */ + get_dimm_config(mci); + /* add this new MC control structure to EDAC's list of MCs */ - if (edac_mc_add_mc(mci)) { + if (unlikely(edac_mc_add_mc(mci)) < 0) { debugf0("MC: " __FILE__ ": %s(): failed edac_mc_add_mc()\n", __func__); /* FIXME: perhaps some code should go here that disables error @@ -1060,7 +1140,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* allocating generic PCI control info */ i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); - if (!i7core_pci) { + if (unlikely (!i7core_pci)) { printk(KERN_WARNING "%s(): Unable to create PCI control\n", __func__); @@ -1070,15 +1150,14 @@ static int __devinit i7core_probe(struct pci_dev *pdev, } /* Default error mask is any memory */ - pvt->inject.channel = -1; + pvt->inject.channel = 0; pvt->inject.dimm = -1; pvt->inject.rank = -1; pvt->inject.bank = -1; pvt->inject.page = -1; pvt->inject.col = -1; - /* Get dimm basic config */ - get_dimm_config(mci); + i7core_printk(KERN_INFO, "Driver loaded.\n"); return 0; -- GitLab From 1c6fed808f1ccd0804786e87f6b2c907dcd730fa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:30 -0300 Subject: [PATCH 093/842] i7core_edac: Properly fill struct csrow_info Thanks-to: Aristeu Rozanski <aris@redhat.com> for part of the code Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 48 ++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index bfa462f6fa0e..556a150e645b 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -348,13 +348,17 @@ static int i7core_get_active_channels(int *channels) (*channels)++; } + debugf0("Number of active channels: %d\n", *channels); + return 0; } static int get_dimm_config(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; - int i; + struct csrow_info *csr; + int i, csrow = 0; + enum edac_type mode; if (!pvt->pci_mcr[0]) return -ENODEV; @@ -365,7 +369,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, &pvt->info.mc_status); pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, - &pvt->info.max_dod); + &pvt->info.max_dod); pci_read_config_dword(pvt->pci_mcr[0], MC_CHANNEL_MAPPER, &pvt->info.ch_map); @@ -373,10 +377,16 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->info.mc_control, pvt->info.mc_status, pvt->info.max_dod, pvt->info.ch_map); - if (ECC_ENABLED(pvt)) + if (ECC_ENABLED(pvt)) { debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); - else + if (ECCx8(pvt)) + mode = EDAC_S8ECD8ED; + else + mode = EDAC_S4ECD4ED; + } else { debugf0("ECC disabled\n"); + mode = EDAC_NONE; + } /* FIXME: need to handle the error codes */ debugf0("DOD Maximum limits: DIMMS: %d, %d-ranked, %d-banked\n", @@ -411,13 +421,31 @@ static int get_dimm_config(struct mem_ctl_info *mci) else pvt->channel[i].dimms = 2; - debugf0("Ch%d (0x%08x): rd ch %d, wr ch %d, " - "%d ranks, %d %cDIMMs\n", - i, data, - RDLCH(pvt->info.ch_map, i), - WRLCH(pvt->info.ch_map, i), + debugf0("Ch%d phy rd%d, wr%d (0x%08x): " + "%d ranks, %d %cDIMMs, offset = %d\n", + i, + RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), + data, pvt->channel[i].ranks, pvt->channel[i].dimms, - (data & REGISTERED_DIMM)? 'R' : 'U' ); + (data & REGISTERED_DIMM)? 'R' : 'U', + RANKOFFSET(data)); + + csr = &mci->csrows[csrow]; + csr->first_page = 0; + csr->last_page = 0; + csr->page_mask = 0; + csr->nr_pages = 0; + csr->grain = 0; + csr->csrow_idx = csrow; + csr->dtype = DEV_X8; /* FIXME: check this */ + + if (data & REGISTERED_DIMM) + csr->mtype = MEM_RDDR3; + else + csr->mtype = MEM_DDR3; + csr->edac_mode = mode; + + csrow++; } return 0; -- GitLab From b7c761512c5412eb30be567a0640060cccfc372f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:30 -0300 Subject: [PATCH 094/842] i7core_edac: Improve error handling Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 556a150e645b..62ae472c4e27 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -328,8 +328,10 @@ static int i7core_get_active_channels(int *channels) } } - if (!pdev) + if (!pdev) { + i7core_printk(KERN_ERR, "Couldn't find fn 3.0!!!\n"); return -ENODEV; + } /* Device 3 function 0 reads */ pci_read_config_dword(pdev, MC_STATUS, &status); @@ -1109,16 +1111,19 @@ static int __devinit i7core_probe(struct pci_dev *pdev, int num_channels = 0; int num_csrows; int dev_idx = id->driver_data; + int rc; if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs))) return -EINVAL; /* get the pci devices we want to reserve for our use */ - if (unlikely(i7core_get_devices() < 0)) - return -ENODEV; + rc = i7core_get_devices(); + if (unlikely(rc < 0)) + return rc; /* Check the number of active and not disabled channels */ - if (unlikely (i7core_get_active_channels(&num_channels)) < 0) + rc = i7core_get_active_channels(&num_channels); + if (unlikely (rc < 0)) goto fail0; /* FIXME: we currently don't know the number of csrows */ @@ -1126,8 +1131,10 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); - if (unlikely (!mci)) - return -ENOMEM; + if (unlikely (!mci)) { + rc = -ENOMEM; + goto fail0; + } debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); @@ -1150,19 +1157,22 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->edac_check = i7core_check_error; /* Store pci devices at mci for faster access */ - if (unlikely (mci_bind_devs(mci)) < 0) + rc = mci_bind_devs(mci); + if (unlikely (rc < 0)) goto fail1; /* Get dimm basic config */ get_dimm_config(mci); /* add this new MC control structure to EDAC's list of MCs */ - if (unlikely(edac_mc_add_mc(mci)) < 0) { + if (unlikely(edac_mc_add_mc(mci))) { debugf0("MC: " __FILE__ ": %s(): failed edac_mc_add_mc()\n", __func__); /* FIXME: perhaps some code should go here that disables error * reporting if we just enabled it */ + + rc = -EINVAL; goto fail1; } @@ -1190,11 +1200,11 @@ static int __devinit i7core_probe(struct pci_dev *pdev, return 0; fail1: - i7core_put_devices(); + edac_mc_free(mci); fail0: - edac_mc_free(mci); - return -ENODEV; + i7core_put_devices(); + return rc; } /* -- GitLab From 7dd6953c5fecc44d264710e1fa158d0038215b63 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:30 -0300 Subject: [PATCH 095/842] i7core_edac: Add more information about each active dimm Thanks-to: Aristeu Rozanski <aris@redhat.com> for part of the code Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 43 ++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 62ae472c4e27..a6e798349e93 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -359,21 +359,18 @@ static int get_dimm_config(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; - int i, csrow = 0; + struct pci_dev *pdev = pvt->pci_mcr[0]; + int i, j, csrow = 0; enum edac_type mode; - if (!pvt->pci_mcr[0]) + if (!pdev) return -ENODEV; /* Device 3 function 0 reads */ - pci_read_config_dword(pvt->pci_mcr[0], MC_CONTROL, - &pvt->info.mc_control); - pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, - &pvt->info.mc_status); - pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, - &pvt->info.max_dod); - pci_read_config_dword(pvt->pci_mcr[0], MC_CHANNEL_MAPPER, - &pvt->info.ch_map); + pci_read_config_dword(pdev, MC_CONTROL, &pvt->info.mc_control); + pci_read_config_dword(pdev, MC_STATUS, &pvt->info.mc_status); + pci_read_config_dword(pdev, MC_MAX_DOD, &pvt->info.max_dod); + pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map); debugf0("MC control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n", pvt->info.mc_control, pvt->info.mc_status, @@ -399,7 +396,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) debugf0("Memory channel configuration:\n"); for (i = 0; i < NUM_CHANS; i++) { - u32 data; + u32 data, value[8]; if (!CH_ACTIVE(pvt, i)) { debugf0("Channel %i is not active\n", i); @@ -424,13 +421,33 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->channel[i].dimms = 2; debugf0("Ch%d phy rd%d, wr%d (0x%08x): " - "%d ranks, %d %cDIMMs, offset = %d\n", + "%d ranks, %d %cDIMMs, offset = %d\n\t" + "present: %i, numbank: %#x, numrank: %#x, " + "numrow: %#x, numcol: %#x\n", i, RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, pvt->channel[i].ranks, pvt->channel[i].dimms, (data & REGISTERED_DIMM)? 'R' : 'U', - RANKOFFSET(data)); + RANKOFFSET(data), + DIMM_PRESENT(data), + NUMBANK(data), NUMRANK(data), + NUMROW(data), NUMCOL(data)); + + pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); + pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]); + pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]); + pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]); + pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]); + pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]); + pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]); + pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]); + printk("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); + for (j = 0; j < 8; j++) + printk("\t\t%#x\t%#x\t%#x\n", + (value[j] >> 27) & 0x1, + (value[j] >> 24) & 0x7, + (value[j] && ((1 << 24) - 1))); csr = &mci->csrows[csrow]; csr->first_page = 0; -- GitLab From 854d3349973a7c47bd989794037f526b74af20c4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:30 -0300 Subject: [PATCH 096/842] i7core_edac: Get more info about the memory DIMMs Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 170 +++++++++++++++++++++++-------------- 1 file changed, 107 insertions(+), 63 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index a6e798349e93..483cca2e543b 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -109,14 +109,14 @@ #define RANKOFFSET(x) ((x & RANKOFFSET_MASK) >> 10) #define DIMM_PRESENT_MASK (1 << 9) #define DIMM_PRESENT(x) (((x) & DIMM_PRESENT_MASK) >> 9) - #define NUMBANK_MASK ((1 << 8) | (1 << 7)) - #define NUMBANK(x) (((x) & NUMBANK_MASK) >> 7) - #define NUMRANK_MASK ((1 << 6) | (1 << 5)) - #define NUMRANK(x) (((x) & NUMRANK_MASK) >> 5) - #define NUMROW_MASK ((1 << 4) | (1 << 3)) - #define NUMROW(x) (((x) & NUMROW_MASK) >> 3) - #define NUMCOL_MASK 3 - #define NUMCOL(x) ((x) & NUMCOL_MASK) + #define MC_DOD_NUMBANK_MASK ((1 << 8) | (1 << 7)) + #define MC_DOD_NUMBANK(x) (((x) & MC_DOD_NUMBANK_MASK) >> 7) + #define MC_DOD_NUMRANK_MASK ((1 << 6) | (1 << 5)) + #define MC_DOD_NUMRANK(x) (((x) & MC_DOD_NUMRANK_MASK) >> 5) + #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3)) + #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 3) + #define MC_DOD_NUMCOL_MASK 3 + #define MC_DOD_NUMCOL(x) ((x) & MC_DOD_NUMCOL_MASK) #define MC_RANK_PRESENT 0x7c @@ -268,41 +268,41 @@ static struct edac_pci_ctl_info *i7core_pci; #define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch)) /* MC_MAX_DOD read functions */ -static inline int maxnumdimms(struct i7core_pvt *pvt) +static inline int numdimms(u32 dimms) { - return (pvt->info.max_dod & 0x3) + 1; + return (dimms & 0x3) + 1; } -static inline int maxnumrank(struct i7core_pvt *pvt) +static inline int numrank(u32 rank) { static int ranks[4] = { 1, 2, 4, -EINVAL }; - return ranks[(pvt->info.max_dod >> 2) & 0x3]; + return ranks[rank & 0x3]; } -static inline int maxnumbank(struct i7core_pvt *pvt) +static inline int numbank(u32 bank) { static int banks[4] = { 4, 8, 16, -EINVAL }; - return banks[(pvt->info.max_dod >> 4) & 0x3]; + return banks[bank & 0x3]; } -static inline int maxnumrow(struct i7core_pvt *pvt) +static inline int numrow(u32 row) { static int rows[8] = { 1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16, -EINVAL, -EINVAL, -EINVAL, }; - return rows[((pvt->info.max_dod >> 6) & 0x7)]; + return rows[row & 0x7]; } -static inline int maxnumcol(struct i7core_pvt *pvt) +static inline int numcol(u32 col) { static int cols[8] = { 1 << 10, 1 << 11, 1 << 12, -EINVAL, }; - return cols[((pvt->info.max_dod >> 9) & 0x3) << 12]; + return cols[col & 0x3]; } @@ -359,10 +359,13 @@ static int get_dimm_config(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; - struct pci_dev *pdev = pvt->pci_mcr[0]; + struct pci_dev *pdev; int i, j, csrow = 0; enum edac_type mode; + enum mem_type mtype; + /* Get data from the MC register, function 0 */ + pdev = pvt->pci_mcr[0]; if (!pdev) return -ENODEV; @@ -388,15 +391,18 @@ static int get_dimm_config(struct mem_ctl_info *mci) } /* FIXME: need to handle the error codes */ - debugf0("DOD Maximum limits: DIMMS: %d, %d-ranked, %d-banked\n", - maxnumdimms(pvt), maxnumrank(pvt), maxnumbank(pvt)); - debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n", - maxnumrow(pvt), maxnumcol(pvt)); + debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked\n", + numdimms(pvt->info.max_dod), + numrank(pvt->info.max_dod >> 2), + numbank(pvt->info.max_dod >> 4)); + debugf0("DOD Max rows x colums = 0x%x x 0x%x\n", + numrow(pvt->info.max_dod >> 6), + numcol(pvt->info.max_dod >> 9)); debugf0("Memory channel configuration:\n"); for (i = 0; i < NUM_CHANS; i++) { - u32 data, value[8]; + u32 data, dimm_dod[3], value[8]; if (!CH_ACTIVE(pvt, i)) { debugf0("Channel %i is not active\n", i); @@ -413,58 +419,96 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT)? 4 : 2; + if (data & REGISTERED_DIMM) + mtype = MEM_RDDR3; + else + mtype = MEM_DDR3; +#if 0 if (data & THREE_DIMMS_PRESENT) pvt->channel[i].dimms = 3; else if (data & SINGLE_QUAD_RANK_PRESENT) pvt->channel[i].dimms = 1; else pvt->channel[i].dimms = 2; +#endif + + /* Devices 4-6 function 1 */ + pci_read_config_dword(pvt->pci_ch[i][1], + MC_DOD_CH_DIMM0, &dimm_dod[0]); + pci_read_config_dword(pvt->pci_ch[i][1], + MC_DOD_CH_DIMM1, &dimm_dod[1]); + pci_read_config_dword(pvt->pci_ch[i][1], + MC_DOD_CH_DIMM2, &dimm_dod[2]); debugf0("Ch%d phy rd%d, wr%d (0x%08x): " - "%d ranks, %d %cDIMMs, offset = %d\n\t" - "present: %i, numbank: %#x, numrank: %#x, " - "numrow: %#x, numcol: %#x\n", + "%d ranks, %cDIMMs\n", i, RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, - pvt->channel[i].ranks, pvt->channel[i].dimms, - (data & REGISTERED_DIMM)? 'R' : 'U', - RANKOFFSET(data), - DIMM_PRESENT(data), - NUMBANK(data), NUMRANK(data), - NUMROW(data), NUMCOL(data)); - - pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); - pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]); - pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]); - pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]); - pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]); - pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]); - pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]); - pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]); - printk("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); - for (j = 0; j < 8; j++) - printk("\t\t%#x\t%#x\t%#x\n", - (value[j] >> 27) & 0x1, - (value[j] >> 24) & 0x7, - (value[j] && ((1 << 24) - 1))); - - csr = &mci->csrows[csrow]; - csr->first_page = 0; - csr->last_page = 0; - csr->page_mask = 0; - csr->nr_pages = 0; - csr->grain = 0; - csr->csrow_idx = csrow; - csr->dtype = DEV_X8; /* FIXME: check this */ + pvt->channel[i].ranks, + (data & REGISTERED_DIMM)? 'R' : 'U'); - if (data & REGISTERED_DIMM) - csr->mtype = MEM_RDDR3; - else - csr->mtype = MEM_DDR3; - csr->edac_mode = mode; + for (j = 0; j < 3; j++) { + u32 banks, ranks, rows, cols; + + if (!DIMM_PRESENT(dimm_dod[j])) + continue; + + banks = numbank(MC_DOD_NUMBANK(dimm_dod[j])); + ranks = numrank(MC_DOD_NUMRANK(dimm_dod[j])); + rows = numrow(MC_DOD_NUMROW(dimm_dod[j])); + cols = numcol(MC_DOD_NUMCOL(dimm_dod[j])); + + pvt->channel[i].dimms++; + + debugf0("\tdimm %d offset: %x, numbank: %#x, " + "numrank: %#x, numrow: %#x, numcol: %#x\n", + j, + RANKOFFSET(dimm_dod[j]), + banks, ranks, rows, cols); + + csr = &mci->csrows[csrow]; + csr->first_page = 0; + csr->last_page = 0; + csr->page_mask = 0; + csr->nr_pages = 0; + csr->grain = 0; + csr->csrow_idx = csrow; + + switch (banks) { + case 4: + csr->dtype = DEV_X4; + break; + case 8: + csr->dtype = DEV_X8; + break; + case 16: + csr->dtype = DEV_X16; + break; + default: + csr->dtype = DEV_UNKNOWN; + } + + csr->edac_mode = mode; + csr->mtype = mtype; + + csrow++; + } - csrow++; + pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); + pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]); + pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]); + pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]); + pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]); + pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]); + pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]); + pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]); + printk("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); + for (j = 0; j < 8; j++) + printk("\t\t%#x\t%#x\t%#x\n", + (value[j] >> 27) & 0x1, + (value[j] >> 24) & 0x7, + (value[j] && ((1 << 24) - 1))); } return 0; -- GitLab From 5566cb7c91ba4ff4447278bb27896b4a2bb7d18a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:31 -0300 Subject: [PATCH 097/842] i7core_edac: Memory info fixes and preparation for properly filling cswrow data Now, memory size is properly displayed: EDAC i7core: DOD Max limits: DIMMS: 2, 1-ranked, 8-banked EDAC i7core: DOD Max rows x colums = 0x4000 x 0x400 EDAC i7core: Memory channel configuration: EDAC i7core: Ch0 phy rd0, wr0 (0x063f7c31): 2 ranks, UDIMMs EDAC i7core: dimm 0 (0x00000288) 1024 Mb offset: 0, numbank: 8, numrank: 1, numrow: 0x4000, numcol: 0x400 EDAC i7core: dimm 1 (0x00001288) 1024 Mb offset: 4, numbank: 8, numrank: 1, numrow: 0x4000, numcol: 0x400 EDAC i7core: Ch1 phy rd1, wr1 (0x063f7c31): 2 ranks, UDIMMs EDAC i7core: dimm 0 (0x00000288) 1024 Mb offset: 0, numbank: 8, numrank: 1, numrow: 0x4000, numcol: 0x400 EDAC i7core: Ch2 phy rd3, wr3 (0x063f7c31): 2 ranks, UDIMMs EDAC i7core: dimm 0 (0x00000288) 1024 Mb offset: 0, numbank: 8, numrank: 1, numrow: 0x4000, numcol: 0x400 Still, as the way to retrieve csrows info is not known, it does a mapping of what's available to csrows basic unit at edac core. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 483cca2e543b..772219fa10be 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -113,8 +113,8 @@ #define MC_DOD_NUMBANK(x) (((x) & MC_DOD_NUMBANK_MASK) >> 7) #define MC_DOD_NUMRANK_MASK ((1 << 6) | (1 << 5)) #define MC_DOD_NUMRANK(x) (((x) & MC_DOD_NUMRANK_MASK) >> 5) - #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3)) - #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 3) + #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3)| (1 << 2)) + #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 2) #define MC_DOD_NUMCOL_MASK 3 #define MC_DOD_NUMCOL(x) ((x) & MC_DOD_NUMCOL_MASK) @@ -361,6 +361,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) struct csrow_info *csr; struct pci_dev *pdev; int i, j, csrow = 0; + unsigned long last_page = 0; enum edac_type mode; enum mem_type mtype; @@ -380,7 +381,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->info.max_dod, pvt->info.ch_map); if (ECC_ENABLED(pvt)) { - debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); + debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ?8:4); if (ECCx8(pvt)) mode = EDAC_S8ECD8ED; else @@ -450,6 +451,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) for (j = 0; j < 3; j++) { u32 banks, ranks, rows, cols; + u32 size, npages; if (!DIMM_PRESENT(dimm_dod[j])) continue; @@ -459,19 +461,27 @@ static int get_dimm_config(struct mem_ctl_info *mci) rows = numrow(MC_DOD_NUMROW(dimm_dod[j])); cols = numcol(MC_DOD_NUMCOL(dimm_dod[j])); + /* DDR3 has 8 I/O banks */ + size = (rows * cols * banks * ranks) >> (20 - 3); + pvt->channel[i].dimms++; - debugf0("\tdimm %d offset: %x, numbank: %#x, " - "numrank: %#x, numrow: %#x, numcol: %#x\n", - j, + debugf0("\tdimm %d (0x%08x) %d Mb offset: %x, " + "numbank: %d,\n\t\t" + "numrank: %d, numrow: %#x, numcol: %#x\n", + j, dimm_dod[j], size, RANKOFFSET(dimm_dod[j]), banks, ranks, rows, cols); + npages = cols * rows; /* FIXME */ + csr = &mci->csrows[csrow]; - csr->first_page = 0; - csr->last_page = 0; + csr->first_page = last_page + 1; + last_page += npages; + csr->last_page = last_page; + csr->nr_pages = npages; + csr->page_mask = 0; - csr->nr_pages = 0; csr->grain = 0; csr->csrow_idx = csrow; -- GitLab From eb94fc402f1592dfe847b245d9109c11a99a2ea1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:31 -0300 Subject: [PATCH 098/842] i7core_edac: fill csrows edac sysfs info csrows is still fake, since we can't identify its representation with Nehalem registers. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 66 +++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 772219fa10be..e0a3b217c52b 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -309,25 +309,33 @@ static inline int numcol(u32 col) /**************************************************************************** Memory check routines ****************************************************************************/ -static int i7core_get_active_channels(int *channels) +static struct pci_dev *get_pdev_slot_func(int slot, int func) { - struct pci_dev *pdev = NULL; int i; - u32 status, control; - - *channels = 0; for (i = 0; i < N_DEVS; i++) { if (!pci_devs[i].pdev) continue; - if (PCI_SLOT(pci_devs[i].pdev->devfn) == 3 && - PCI_FUNC(pci_devs[i].pdev->devfn) == 0) { - pdev = pci_devs[i].pdev; - break; + if (PCI_SLOT(pci_devs[i].pdev->devfn) == slot && + PCI_FUNC(pci_devs[i].pdev->devfn) == func) { + return pci_devs[i].pdev; } } + return NULL; +} + +static int i7core_get_active_channels(int *channels, int *csrows) +{ + struct pci_dev *pdev = NULL; + int i, j; + u32 status, control; + + *channels = 0; + *csrows = 0; + + pdev = get_pdev_slot_func(3, 0); if (!pdev) { i7core_printk(KERN_ERR, "Couldn't find fn 3.0!!!\n"); return -ENODEV; @@ -338,6 +346,7 @@ static int i7core_get_active_channels(int *channels) pci_read_config_dword(pdev, MC_CONTROL, &control); for (i = 0; i < NUM_CHANS; i++) { + u32 dimm_dod[3]; /* Check if the channel is active */ if (!(control & (1 << (8 + i)))) continue; @@ -347,7 +356,27 @@ static int i7core_get_active_channels(int *channels) continue; } + pdev = get_pdev_slot_func(i + 4, 1); + if (!pdev) { + i7core_printk(KERN_ERR, "Couldn't find fn %d.%d!!!\n", + i + 4, 1); + return -ENODEV; + } + /* Devices 4-6 function 1 */ + pci_read_config_dword(pdev, + MC_DOD_CH_DIMM0, &dimm_dod[0]); + pci_read_config_dword(pdev, + MC_DOD_CH_DIMM1, &dimm_dod[1]); + pci_read_config_dword(pdev, + MC_DOD_CH_DIMM2, &dimm_dod[2]); + (*channels)++; + + for (j = 0; j < 3; j++) { + if (!DIMM_PRESENT(dimm_dod[j])) + continue; + (*csrows)++; + } } debugf0("Number of active channels: %d\n", *channels); @@ -473,7 +502,11 @@ static int get_dimm_config(struct mem_ctl_info *mci) RANKOFFSET(dimm_dod[j]), banks, ranks, rows, cols); - npages = cols * rows; /* FIXME */ +#if PAGE_SHIFT > 20 + npages = size >> (PAGE_SHIFT - 20); +#else + npages = size << (20 - PAGE_SHIFT); +#endif csr = &mci->csrows[csrow]; csr->first_page = last_page + 1; @@ -482,8 +515,12 @@ static int get_dimm_config(struct mem_ctl_info *mci) csr->nr_pages = npages; csr->page_mask = 0; - csr->grain = 0; + csr->grain = 8; csr->csrow_idx = csrow; + csr->nr_channels = 1; + + csr->channels[0].chan_idx = i; + csr->channels[0].ce_count = 0; switch (banks) { case 4: @@ -1179,7 +1216,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int num_channels = 0; + int num_channels; int num_csrows; int dev_idx = id->driver_data; int rc; @@ -1193,13 +1230,10 @@ static int __devinit i7core_probe(struct pci_dev *pdev, return rc; /* Check the number of active and not disabled channels */ - rc = i7core_get_active_channels(&num_channels); + rc = i7core_get_active_channels(&num_channels, &num_csrows); if (unlikely (rc < 0)) goto fail0; - /* FIXME: we currently don't know the number of csrows */ - num_csrows = num_channels; - /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); if (unlikely (!mci)) { -- GitLab From 41fcb7feed70d8076f1591664314ca172fcdff7b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 22 Jun 2009 22:48:31 -0300 Subject: [PATCH 099/842] i7core_edac: CodingStyle fixes Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 59 +++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e0a3b217c52b..914914759690 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -113,7 +113,7 @@ #define MC_DOD_NUMBANK(x) (((x) & MC_DOD_NUMBANK_MASK) >> 7) #define MC_DOD_NUMRANK_MASK ((1 << 6) | (1 << 5)) #define MC_DOD_NUMRANK(x) (((x) & MC_DOD_NUMRANK_MASK) >> 5) - #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3)| (1 << 2)) + #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3) | (1 << 2)) #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 2) #define MC_DOD_NUMCOL_MASK 3 #define MC_DOD_NUMCOL(x) ((x) & MC_DOD_NUMCOL_MASK) @@ -352,9 +352,8 @@ static int i7core_get_active_channels(int *channels, int *csrows) continue; /* Check if the channel is disabled */ - if (status & (1 << i)) { + if (status & (1 << i)) continue; - } pdev = get_pdev_slot_func(i + 4, 1); if (!pdev) { @@ -410,7 +409,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->info.max_dod, pvt->info.ch_map); if (ECC_ENABLED(pvt)) { - debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ?8:4); + debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ? 8 : 4); if (ECCx8(pvt)) mode = EDAC_S8ECD8ED; else @@ -447,7 +446,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) pci_read_config_dword(pvt->pci_ch[i][0], MC_CHANNEL_DIMM_INIT_PARAMS, &data); - pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT)? 4 : 2; + pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ? 4 : 2; if (data & REGISTERED_DIMM) mtype = MEM_RDDR3; @@ -476,7 +475,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, pvt->channel[i].ranks, - (data & REGISTERED_DIMM)? 'R' : 'U'); + (data & REGISTERED_DIMM) ? 'R' : 'U'); for (j = 0; j < 3; j++) { u32 banks, ranks, rows, cols; @@ -550,9 +549,9 @@ static int get_dimm_config(struct mem_ctl_info *mci) pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]); pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]); pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]); - printk("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); + debugf0("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); for (j = 0; j < 8; j++) - printk("\t\t%#x\t%#x\t%#x\n", + debugf0("\t\t%#x\t%#x\t%#x\n", (value[j] >> 27) & 0x1, (value[j] >> 24) & 0x7, (value[j] && ((1 << 24) - 1))); @@ -602,7 +601,7 @@ static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci, int rc; if (pvt->inject.enable) - disable_inject(mci); + disable_inject(mci); rc = strict_strtoul(data, 10, &value); if ((rc < 0) || (value > 3)) @@ -635,7 +634,7 @@ static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci, int rc; if (pvt->inject.enable) - disable_inject(mci); + disable_inject(mci); rc = strict_strtoul(data, 10, &value); if ((rc < 0) || (value > 7)) @@ -670,7 +669,7 @@ static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci, int rc; if (pvt->inject.enable) - disable_inject(mci); + disable_inject(mci); rc = strict_strtoul(data, 10, &value); if (rc < 0) @@ -706,7 +705,7 @@ static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, int rc; if (pvt->inject.enable) - disable_inject(mci); + disable_inject(mci); do { cmd = strsep((char **) &data, ":"); @@ -716,7 +715,7 @@ static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, if (!val) return cmd - data; - if (!strcasecmp(val,"any")) + if (!strcasecmp(val, "any")) value = -1; else { rc = strict_strtol(val, 10, &value); @@ -724,33 +723,33 @@ static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, return cmd - data; } - if (!strcasecmp(cmd,"channel")) { + if (!strcasecmp(cmd, "channel")) { if (value < 3) pvt->inject.channel = value; else return cmd - data; - } else if (!strcasecmp(cmd,"dimm")) { + } else if (!strcasecmp(cmd, "dimm")) { if (value < 4) pvt->inject.dimm = value; else return cmd - data; - } else if (!strcasecmp(cmd,"rank")) { + } else if (!strcasecmp(cmd, "rank")) { if (value < 4) pvt->inject.rank = value; else return cmd - data; - } else if (!strcasecmp(cmd,"bank")) { + } else if (!strcasecmp(cmd, "bank")) { if (value < 4) pvt->inject.bank = value; else return cmd - data; - } else if (!strcasecmp(cmd,"page")) { + } else if (!strcasecmp(cmd, "page")) { if (value <= 0xffff) pvt->inject.page = value; else return cmd - data; - } else if (!strcasecmp(cmd,"col") || - !strcasecmp(cmd,"column")) { + } else if (!strcasecmp(cmd, "col") || + !strcasecmp(cmd, "column")) { if (value <= 0x3fff) pvt->inject.col = value; else @@ -923,7 +922,8 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, injectmask); - debugf0("Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n", + debugf0("Error inject addr match 0x%016llx, ecc 0x%08x," + " inject 0x%08x\n", mask, pvt->inject.eccmask, injectmask); @@ -1048,7 +1048,7 @@ static int i7core_get_devices(void) "Device not found: PCI ID %04x:%04x " "(dev %d, func %d)\n", PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - pci_devs[i].dev,pci_devs[i].func); + pci_devs[i].dev, pci_devs[i].func); /* Dev 3 function 2 only exists on chips with RDIMMs */ if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) @@ -1231,12 +1231,12 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* Check the number of active and not disabled channels */ rc = i7core_get_active_channels(&num_channels, &num_csrows); - if (unlikely (rc < 0)) + if (unlikely(rc < 0)) goto fail0; /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); - if (unlikely (!mci)) { + if (unlikely(!mci)) { rc = -ENOMEM; goto fail0; } @@ -1249,7 +1249,12 @@ static int __devinit i7core_probe(struct pci_dev *pdev, memset(pvt, 0, sizeof(*pvt)); mci->mc_idx = 0; - mci->mtype_cap = MEM_FLAG_DDR3; /* FIXME: how to handle RDDR3? */ + /* + * FIXME: how to handle RDDR3 at MCI level? It is possible to have + * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different + * memory channels + */ + mci->mtype_cap = MEM_FLAG_DDR3; mci->edac_ctl_cap = EDAC_FLAG_NONE; mci->edac_cap = EDAC_FLAG_NONE; mci->mod_name = "i7core_edac.c"; @@ -1263,7 +1268,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* Store pci devices at mci for faster access */ rc = mci_bind_devs(mci); - if (unlikely (rc < 0)) + if (unlikely(rc < 0)) goto fail1; /* Get dimm basic config */ @@ -1283,7 +1288,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* allocating generic PCI control info */ i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); - if (unlikely (!i7core_pci)) { + if (unlikely(!i7core_pci)) { printk(KERN_WARNING "%s(): Unable to create PCI control\n", __func__); -- GitLab From 696e409dbd1ce325129c5030267365619364dfa0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 23 Jul 2009 06:57:45 -0300 Subject: [PATCH 100/842] edac_mce: Add an interface driver to report mce errors via edac edac_mce module is an interface module that gets mcelog data and forwards to any registered edac module that expects to receive data via mce. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- arch/x86/kernel/cpu/mcheck/mce.c | 10 ++++++ drivers/edac/Kconfig | 8 ++++- drivers/edac/Makefile | 1 + drivers/edac/edac_mce.c | 58 ++++++++++++++++++++++++++++++++ include/linux/edac_mce.h | 31 +++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 drivers/edac/edac_mce.c create mode 100644 include/linux/edac_mce.h diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 8a6f0afa767e..6585ff07ddf5 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -36,6 +36,7 @@ #include <linux/fs.h> #include <linux/mm.h> #include <linux/debugfs.h> +#include <linux/edac_mce.h> #include <asm/processor.h> #include <asm/hw_irq.h> @@ -168,6 +169,15 @@ void mce_log(struct mce *mce) for (;;) { entry = rcu_dereference_check_mce(mcelog.next); for (;;) { + /* + * If edac_mce is enabled, it will check the error type + * and will process it, if it is a known error. + * Otherwise, the error will be sent through mcelog + * interface + */ + if (edac_mce_parse(mce)) + return; + /* * When the buffer fills up discard new entries. * Assume that the earlier errors are the more diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 391ddbfb2a34..5b7fbc5aec87 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -69,6 +69,9 @@ config EDAC_MM_EDAC occurred so that a particular failing memory module can be replaced. If unsure, select 'Y'. +config EDAC_MCE + tristate + config EDAC_AMD64 tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h" depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE @@ -169,9 +172,12 @@ config EDAC_I5400 config EDAC_I7CORE tristate "Intel i7 Core (Nehalem) processors" depends on EDAC_MM_EDAC && PCI && X86 + select EDAC_MCE help Support for error detection and correction the Intel - i7 Core (Nehalem) Integrated Memory Controller + i7 Core (Nehalem) Integrated Memory Controller that exists on + newer processors like i7 Core, i7 Core Extreme, Xeon 35xx + and Xeon 55xx processors. config EDAC_I82860 tristate "Intel 82860" diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index b9996195b233..ca6b1bb24ccc 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_EDAC) := edac_stub.o obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o +obj-$(CONFIG_EDAC_MCE) += edac_mce.o edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o edac_core-objs += edac_module.o edac_device_sysfs.o diff --git a/drivers/edac/edac_mce.c b/drivers/edac/edac_mce.c new file mode 100644 index 000000000000..b1efa8e51921 --- /dev/null +++ b/drivers/edac/edac_mce.c @@ -0,0 +1,58 @@ +/* Provides edac interface to mcelog events + * + * This file may be distributed under the terms of the + * GNU General Public License version 2. + * + * Copyright (c) 2009 by: + * Mauro Carvalho Chehab <mchehab@redhat.com> + * + * Red Hat Inc. http://www.redhat.com + */ + +#include <linux/module.h> +#include <linux/edac_mce.h> +#include <asm/mce.h> + +int edac_mce_enabled; +EXPORT_SYMBOL_GPL(edac_mce_enabled); + + +/* + * Extension interface + */ + +static LIST_HEAD(edac_mce_list); +static DEFINE_MUTEX(edac_mce_lock); + +int edac_mce_register(struct edac_mce *edac_mce) +{ + mutex_lock(&edac_mce_lock); + list_add_tail(&edac_mce->list, &edac_mce_list); + mutex_unlock(&edac_mce_lock); + return 0; +} +EXPORT_SYMBOL(edac_mce_register); + +void edac_mce_unregister(struct edac_mce *edac_mce) +{ + mutex_lock(&edac_mce_lock); + list_del(&edac_mce->list); + mutex_unlock(&edac_mce_lock); +} +EXPORT_SYMBOL(edac_mce_unregister); + + + +int edac_mce_queue(struct mce *mce) +{ + struct edac_mce *edac_mce; + + list_for_each_entry(edac_mce, &edac_mce_list, list) { + if (edac_mce->check_error(edac_mce->priv, mce)) + return 1; + } + + /* Nobody queued the error */ + return 0; +} +EXPORT_SYMBOL_GPL(edac_mce_queue); diff --git a/include/linux/edac_mce.h b/include/linux/edac_mce.h new file mode 100644 index 000000000000..f974fc035363 --- /dev/null +++ b/include/linux/edac_mce.h @@ -0,0 +1,31 @@ +/* Provides edac interface to mcelog events + * + * This file may be distributed under the terms of the + * GNU General Public License version 2. + * + * Copyright (c) 2009 by: + * Mauro Carvalho Chehab <mchehab@redhat.com> + * + * Red Hat Inc. http://www.redhat.com + */ + +#if defined(CONFIG_EDAC_MCE) || \ + (defined(CONFIG_EDAC_MCE_MODULE) && defined(MODULE)) + +#include <asm/mce.h> +#include <linux/list.h> + +struct edac_mce { + struct list_head list; + + void *priv; + int (*check_error)(void *priv, struct mce *mce); +}; + +int edac_mce_register(struct edac_mce *edac_mce); +void edac_mce_unregister(struct edac_mce *edac_mce); +int edac_mce_parse(struct mce *mce); + +#else +#define edac_mce_parse(mce) (0) +#endif -- GitLab From 963c5ba35984c87963480031d1d7e2e556256ad7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 9 Jul 2009 22:04:30 -0300 Subject: [PATCH 101/842] edac/Kconfig: edac_mce can't be module Since mcelog is bool, edac_mce glue should also be bool, or otherwise will not work. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 5b7fbc5aec87..aedef7941b22 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -70,7 +70,7 @@ config EDAC_MM_EDAC replaced. If unsure, select 'Y'. config EDAC_MCE - tristate + bool config EDAC_AMD64 tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h" -- GitLab From d5381642ab01b084787925acdf26b5524d434476 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 9 Jul 2009 22:06:41 -0300 Subject: [PATCH 102/842] i7core_edac: Add edac_mce glue Adds a glue code to allow i7core to work with mcelog. With the glue, i7core registers itself on edac_mce. At mce, when an error is detected, it calls all registered drivers (in this case, i7core), for EDAC error handling. TODO: It currently just prints the MCE error log using about the same format as mce panic messages. The error message should be enhanced with mcelog userspace info and converted into the proper EDAC format, to feed the EDAC error counts. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/edac_mce.c | 11 ++-- drivers/edac/i7core_edac.c | 111 ++++++++++++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 6 deletions(-) diff --git a/drivers/edac/edac_mce.c b/drivers/edac/edac_mce.c index b1efa8e51921..9ccdc5b140e7 100644 --- a/drivers/edac/edac_mce.c +++ b/drivers/edac/edac_mce.c @@ -41,9 +41,7 @@ void edac_mce_unregister(struct edac_mce *edac_mce) } EXPORT_SYMBOL(edac_mce_unregister); - - -int edac_mce_queue(struct mce *mce) +int edac_mce_parse(struct mce *mce) { struct edac_mce *edac_mce; @@ -55,4 +53,9 @@ int edac_mce_queue(struct mce *mce) /* Nobody queued the error */ return 0; } -EXPORT_SYMBOL_GPL(edac_mce_queue); +EXPORT_SYMBOL_GPL(edac_mce_parse); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("EDAC Driver for mcelog captured errors"); diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 914914759690..3c7bb5f405f6 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -27,6 +27,8 @@ #include <linux/slab.h> #include <linux/edac.h> #include <linux/mmzone.h> +#include <linux/edac_mce.h> +#include <linux/spinlock.h> #include "edac_core.h" @@ -195,6 +197,11 @@ struct i7core_pvt { unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */ int last_ce_count[MAX_DIMMS]; + /* mcelog glue */ + struct edac_mce edac_mce; + struct mce mce_entry[MCE_LOG_LEN]; + unsigned mce_count; + spinlock_t mce_lock; }; /* Device name and register DID (Device ID) */ @@ -900,7 +907,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH + 4, &rdmask2); - debugf0("Inject addr match write 0x%016llx, read: 0x%08x%08x\n", + debugf0("Inject addr match write 0x%016llx, read: 0x%08x 0x%08x\n", mask, rdmask1, rdmask2); #endif #endif @@ -1162,9 +1169,11 @@ static void check_mc_test_err(struct mem_ctl_info *mci) new1 = DIMM1_COR_ERR(rcv0); new0 = DIMM0_COR_ERR(rcv0); +#if 0 debugf2("%s CE rcv1=0x%08x rcv0=0x%08x, %d %d %d\n", (pvt->ce_count_available ? "UPDATE" : "READ"), rcv1, rcv0, new0, new1, new2); +#endif /* Updates CE counters if it is not the first time here */ if (pvt->ce_count_available) { @@ -1195,15 +1204,96 @@ static void check_mc_test_err(struct mem_ctl_info *mci) pvt->last_ce_count[0] = new0; } +static void i7core_mce_output_error(struct mem_ctl_info *mci, + struct mce *m) +{ + debugf0("CPU %d: Machine Check Exception: %16Lx" + "Bank %d: %016Lx\n", + m->cpu, m->mcgstatus, m->bank, m->status); + if (m->ip) { + debugf0("RIP%s %02x:<%016Lx>\n", + !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "", + m->cs, m->ip); + } + printk(KERN_EMERG "TSC %llx ", m->tsc); + if (m->addr) + printk("ADDR %llx ", m->addr); + if (m->misc) + printk("MISC %llx ", m->misc); + +#if 0 + snprintf(msg, sizeof(msg), + "%s (Branch=%d DRAM-Bank=%d Buffer ID = %d RDWR=%s " + "RAS=%d CAS=%d %s Err=0x%lx (%s))", + type, branch >> 1, bank, buf_id, rdwr_str(rdwr), ras, cas, + type, allErrors, error_name[errnum]); + + /* Call the helper to output message */ + edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); +#endif +} + /* * i7core_check_error Retrieve and process errors reported by the * hardware. Called by the Core module. */ static void i7core_check_error(struct mem_ctl_info *mci) { + struct i7core_pvt *pvt = mci->pvt_info; + int i; + unsigned count = 0; + struct mce *m = NULL; + unsigned long flags; + + debugf0(__FILE__ ": %s()\n", __func__); + + /* Copy all mce errors into a temporary buffer */ + spin_lock_irqsave(&pvt->mce_lock, flags); + if (pvt->mce_count) { + m = kmalloc(sizeof(*m) * pvt->mce_count, GFP_ATOMIC); + if (m) { + count = pvt->mce_count; + memcpy(m, &pvt->mce_entry, sizeof(*m) * count); + } + pvt->mce_count = 0; + } + spin_unlock_irqrestore(&pvt->mce_lock, flags); + + /* proccess mcelog errors */ + for (i = 0; i < count; i++) + i7core_mce_output_error(mci, &m[i]); + + kfree(m); + + /* check memory count errors */ check_mc_test_err(mci); } +/* + * i7core_mce_check_error Replicates mcelog routine to get errors + * This routine simply queues mcelog errors, and + * return. The error itself should be handled later + * by i7core_check_error. + */ +static int i7core_mce_check_error(void *priv, struct mce *mce) +{ + struct i7core_pvt *pvt = priv; + unsigned long flags; + + debugf0(__FILE__ ": %s()\n", __func__); + + spin_lock_irqsave(&pvt->mce_lock, flags); + if (pvt->mce_count < MCE_LOG_LEN) { + memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); + pvt->mce_count++; + } + spin_unlock_irqrestore(&pvt->mce_lock, flags); + + /* Advice mcelog that the error were handled */ +// return 1; + return 0; // Let's duplicate the log +} + /* * i7core_probe Probe for ONE instance of device to see if it is * present. @@ -1305,6 +1395,18 @@ static int __devinit i7core_probe(struct pci_dev *pdev, pvt->inject.page = -1; pvt->inject.col = -1; + /* Registers on edac_mce in order to receive memory errors */ + pvt->edac_mce.priv = pvt; + pvt->edac_mce.check_error = i7core_mce_check_error; + spin_lock_init(&pvt->mce_lock); + + rc = edac_mce_register(&pvt->edac_mce); + if (unlikely (rc < 0)) { + debugf0("MC: " __FILE__ + ": %s(): failed edac_mce_register()\n", __func__); + goto fail1; + } + i7core_printk(KERN_INFO, "Driver loaded.\n"); return 0; @@ -1324,17 +1426,22 @@ fail0: static void __devexit i7core_remove(struct pci_dev *pdev) { struct mem_ctl_info *mci; + struct i7core_pvt *pvt; debugf0(__FILE__ ": %s()\n", __func__); if (i7core_pci) edac_pci_release_generic_ctl(i7core_pci); - mci = edac_mc_del_mc(&pdev->dev); + mci = edac_mc_del_mc(&pdev->dev); if (!mci) return; + /* Unregisters on edac_mce in order to receive memory errors */ + pvt = mci->pvt_info; + edac_mce_unregister(&pvt->edac_mce); + /* retrieve references to resources, and free those resources */ i7core_put_devices(); -- GitLab From e9bd2e73793bf0f7fcd8f94b532bb8f5c5b44171 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 9 Jul 2009 22:14:35 -0300 Subject: [PATCH 103/842] i7core_edac: Adds write unlock to MC registers The public Intel Xeon 5500 volume 2 datasheet describes, on page 53, session 2.6.7 a register that can lock/unlock Memory Controller the configuration register, called MC_CFG_CONTROL. Adds support for it in the hope that software error injection would work. With my tests with Xeon 35xx, there's still something missing. With a program that does sequencial bit writes at dev 0.0, sometimes, it produces error injection, after unblocking the MC_CFG_CONTROL (and, sometimes, it just locks my testing machine). I'll try later to discover by trial and error what's the register that solves this issue on Xeon 35xx. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 30 +++++++++++++++++++++++++++--- include/linux/pci_ids.h | 1 + 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 3c7bb5f405f6..26cd5c924d56 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -33,7 +33,7 @@ #include "edac_core.h" /* To use the new pci_[read/write]_config_qword instead of two dword */ -#define USE_QWORD 1 +#define USE_QWORD 0 /* * Alter this version for the module when modifications are made @@ -58,6 +58,10 @@ * i7core Memory Controller Registers */ + /* OFFSETS for Device 0 Function 0 */ + +#define MC_CFG_CONTROL 0x90 + /* OFFSETS for Device 3 Function 0 */ #define MC_CONTROL 0x48 @@ -186,6 +190,7 @@ struct pci_id_descr { }; struct i7core_pvt { + struct pci_dev *pci_noncore; struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1]; struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1]; struct i7core_info info; @@ -222,6 +227,9 @@ struct pci_id_descr pci_devs[] = { { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM is supported */ { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, + /* Generic Non-core registers */ + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, + /* Channel 0 */ { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) }, { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) }, @@ -882,6 +890,16 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, else mask |= (pvt->inject.col & 0x3fffL); + /* Unlock writes to registers */ + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 0x2); + msleep(100); + + /* Zeroes error count registers */ + pci_write_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, 0); + pci_write_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, 0); + pvt->ce_count_available = 0; + + #if USE_QWORD pci_write_config_qword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); @@ -929,12 +947,15 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, injectmask); +#if 0 + /* lock writes to registers */ + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 0); +#endif debugf0("Error inject addr match 0x%016llx, ecc 0x%08x," " inject 0x%08x\n", mask, pvt->inject.eccmask, injectmask); - return count; } @@ -1124,12 +1145,15 @@ static int mci_bind_devs(struct mem_ctl_info *mci) if (unlikely(func > MAX_CHAN_FUNC)) goto error; pvt->pci_ch[slot - 4][func] = pdev; - } else + } else if (!slot && !func) + pvt->pci_noncore = pdev; + else goto error; debugf0("Associated fn %d.%d, dev = %p\n", PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev); } + return 0; error: diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c5dd0994bd7c..9d5bfe86ba73 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2548,6 +2548,7 @@ #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR 0x2c31 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK 0x2c32 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33 +#define PCI_DEVICE_ID_INTEL_I7_NOCORE 0x2c41 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 #define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a -- GitLab From 5707b24a50b40582226618c56692af932db9fe02 Mon Sep 17 00:00:00 2001 From: Aristeu Rozanski <aris@redhat.com> Date: Thu, 9 Jul 2009 22:21:13 -0300 Subject: [PATCH 104/842] pci: Add a probing code that seeks for an specific bus This patch adds a probing code that seeks for an specific pci bus. It still needs testing, but it is hoped that this will help to identify the memory controller with Xeon 55xx series. Signed-off-by: Aristeu Sergio <arozansk@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- arch/x86/include/asm/pci_x86.h | 2 ++ arch/x86/pci/legacy.c | 42 ++++++++++++++++++++-------------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h index 1a0422348d6d..ff5404b82fdc 100644 --- a/arch/x86/include/asm/pci_x86.h +++ b/arch/x86/include/asm/pci_x86.h @@ -53,6 +53,8 @@ extern int pcibios_last_bus; extern struct pci_bus *pci_root_bus; extern struct pci_ops pci_root_ops; +void pcibios_scan_specific_bus(int busn); + /* pci-irq.c */ struct irq_info { diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c index 0db5eaf54560..c734c277b116 100644 --- a/arch/x86/pci/legacy.c +++ b/arch/x86/pci/legacy.c @@ -11,28 +11,14 @@ */ static void __devinit pcibios_fixup_peer_bridges(void) { - int n, devfn; - long node; + int n; if (pcibios_last_bus <= 0 || pcibios_last_bus > 0xff) return; DBG("PCI: Peer bridge fixup\n"); - for (n=0; n <= pcibios_last_bus; n++) { - u32 l; - if (pci_find_bus(0, n)) - continue; - node = get_mp_bus_to_node(n); - for (devfn = 0; devfn < 256; devfn += 8) { - if (!raw_pci_read(0, n, devfn, PCI_VENDOR_ID, 2, &l) && - l != 0x0000 && l != 0xffff) { - DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l); - printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); - pci_scan_bus_on_node(n, &pci_root_ops, node); - break; - } - } - } + for (n=0; n <= pcibios_last_bus; n++) + pcibios_scan_specific_bus(n); } int __init pci_legacy_init(void) @@ -49,6 +35,28 @@ int __init pci_legacy_init(void) return 0; } +EXPORT_SYMBOL_GPL(pci_legacy_init); + +void pcibios_scan_specific_bus(int busn) +{ + int devfn; + long node; + u32 l; + + if (pci_find_bus(0, busn)) + return; + + node = get_mp_bus_to_node(busn); + for (devfn = 0; devfn < 256; devfn += 8) { + if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) && + l != 0x0000 && l != 0xffff) { + DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l); + printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn); + pci_scan_bus_on_node(busn, &pci_root_ops, node); + return; + } + } +} int __init pci_subsys_init(void) { -- GitLab From d1fd4fb69eeeb7db0693df58b9116db498d5bfe1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Fri, 10 Jul 2009 18:39:53 -0300 Subject: [PATCH 105/842] i7core_edac: Add a code to probe Xeon 55xx bus This code changes the detection procedure of i7core_edac. Instead of directly probing for MC registers, it probes for another register found on Nehalem. If found, it tries to pick the first MC PCI BUS. This should work fine with Xeon 35xx, but, on Xeon 55xx, this is at bus 254 and 255 that are not properly detected by the non-legacy PCI methods. The new detection code scans specifically at buses 254 and 255 for the Xeon 55xx devices. This code has not tested yet. After working, a change at the code will be needed, since the i7core is not yet ready for working with 2 sets of MC. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- arch/x86/pci/legacy.c | 1 + drivers/edac/i7core_edac.c | 17 +++++++++++++---- include/linux/pci.h | 1 + include/linux/pci_ids.h | 1 + 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c index c734c277b116..d6cc2eddf339 100644 --- a/arch/x86/pci/legacy.c +++ b/arch/x86/pci/legacy.c @@ -57,6 +57,7 @@ void pcibios_scan_specific_bus(int busn) } } } +EXPORT_SYMBOL_GPL(pcibios_scan_specific_bus); int __init pci_subsys_init(void) { diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 26cd5c924d56..eec0c13c0205 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -221,15 +221,15 @@ struct i7core_dev_info { .dev_id = (device_id) struct pci_id_descr pci_devs[] = { + /* Generic Non-core registers */ + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, + /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM is supported */ { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, - /* Generic Non-core registers */ - { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, - /* Channel 0 */ { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) }, { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) }, @@ -255,7 +255,7 @@ struct pci_id_descr pci_devs[] = { * This should match the first device at pci_devs table */ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)}, {0,} /* 0 terminated list. */ }; @@ -1069,6 +1069,15 @@ static int i7core_get_devices(void) for (i = 0; i < N_DEVS; i++) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, NULL); + + if (!pdev && !i) { + pcibios_scan_specific_bus(254); + pcibios_scan_specific_bus(255); + + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + pci_devs[i].dev_id, NULL); + } + if (likely(pdev)) pci_devs[i].pdev = pdev; else { diff --git a/include/linux/pci.h b/include/linux/pci.h index a788fa12ff31..5e2c7e15187d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -621,6 +621,7 @@ void pci_fixup_cardbus(struct pci_bus *); /* Generic PCI functions used internally */ +void pcibios_scan_specific_bus(int busn); extern struct pci_bus *pci_find_bus(int domain, int busnr); void pci_bus_add_devices(const struct pci_bus *bus); struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 9d5bfe86ba73..12c3da6ef14d 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2554,6 +2554,7 @@ #define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a #define PCI_DEVICE_ID_INTEL_IOAT_TBG6 0x342b #define PCI_DEVICE_ID_INTEL_IOAT_TBG7 0x342c +#define PCI_DEVICE_ID_INTEL_X58_HUB_MGMT 0x342e #define PCI_DEVICE_ID_INTEL_IOAT_TBG0 0x3430 #define PCI_DEVICE_ID_INTEL_IOAT_TBG1 0x3431 #define PCI_DEVICE_ID_INTEL_IOAT_TBG2 0x3432 -- GitLab From 67166af4abc11d9c0deb497ebe0b562f69c71942 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 15 Jul 2009 06:56:23 -0300 Subject: [PATCH 106/842] i7core_edac: add support for more than one MC socket Some Nehalem architectures have more than one MC socket. Socket 0 is located at bus 255. Currently, it is using up to 2 sockets, but increasing it to a larger number is just a matter of increasing MAX_SOCKETS definition. This seems to be required for properly support of Xeon 55xx. Still needs testing with Xeon 55xx. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 326 ++++++++++++++++++++++++------------- 1 file changed, 213 insertions(+), 113 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index eec0c13c0205..69eacc1b50d7 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -155,6 +155,7 @@ #define NUM_CHANS 3 #define MAX_DIMMS 3 /* Max DIMMS per channel */ +#define NUM_SOCKETS 2 /* Max number of MC sockets */ #define MAX_MCR_FUNC 4 #define MAX_CHAN_FUNC 3 @@ -169,6 +170,7 @@ struct i7core_info { struct i7core_inject { int enable; + u8 socket; u32 section; u32 type; u32 eccmask; @@ -186,21 +188,25 @@ struct pci_id_descr { int dev; int func; int dev_id; - struct pci_dev *pdev; + struct pci_dev *pdev[NUM_SOCKETS]; }; struct i7core_pvt { - struct pci_dev *pci_noncore; - struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1]; - struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1]; + struct pci_dev *pci_noncore[NUM_SOCKETS]; + struct pci_dev *pci_mcr[NUM_SOCKETS][MAX_MCR_FUNC + 1]; + struct pci_dev *pci_ch[NUM_SOCKETS][NUM_CHANS][MAX_CHAN_FUNC + 1]; + struct i7core_info info; struct i7core_inject inject; - struct i7core_channel channel[NUM_CHANS]; + struct i7core_channel channel[NUM_SOCKETS][NUM_CHANS]; + + int sockets; /* Number of sockets */ int channels; /* Number of active channels */ - int ce_count_available; - unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */ - int last_ce_count[MAX_DIMMS]; + int ce_count_available[NUM_SOCKETS]; + /* ECC corrected errors counts per dimm */ + unsigned long ce_count[NUM_SOCKETS][MAX_DIMMS]; + int last_ce_count[NUM_SOCKETS][MAX_DIMMS]; /* mcelog glue */ struct edac_mce edac_mce; @@ -324,24 +330,26 @@ static inline int numcol(u32 col) /**************************************************************************** Memory check routines ****************************************************************************/ -static struct pci_dev *get_pdev_slot_func(int slot, int func) +static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, + unsigned func) { int i; for (i = 0; i < N_DEVS; i++) { - if (!pci_devs[i].pdev) + if (!pci_devs[i].pdev[socket]) continue; - if (PCI_SLOT(pci_devs[i].pdev->devfn) == slot && - PCI_FUNC(pci_devs[i].pdev->devfn) == func) { - return pci_devs[i].pdev; + if (PCI_SLOT(pci_devs[i].pdev[socket]->devfn) == slot && + PCI_FUNC(pci_devs[i].pdev[socket]->devfn) == func) { + return pci_devs[i].pdev[socket]; } } return NULL; } -static int i7core_get_active_channels(int *channels, int *csrows) +static int i7core_get_active_channels(u8 socket, unsigned *channels, + unsigned *csrows) { struct pci_dev *pdev = NULL; int i, j; @@ -350,9 +358,10 @@ static int i7core_get_active_channels(int *channels, int *csrows) *channels = 0; *csrows = 0; - pdev = get_pdev_slot_func(3, 0); + pdev = get_pdev_slot_func(socket, 3, 0); if (!pdev) { - i7core_printk(KERN_ERR, "Couldn't find fn 3.0!!!\n"); + i7core_printk(KERN_ERR, "Couldn't find socket %d fn 3.0!!!\n", + socket); return -ENODEV; } @@ -370,10 +379,11 @@ static int i7core_get_active_channels(int *channels, int *csrows) if (status & (1 << i)) continue; - pdev = get_pdev_slot_func(i + 4, 1); + pdev = get_pdev_slot_func(socket, i + 4, 1); if (!pdev) { - i7core_printk(KERN_ERR, "Couldn't find fn %d.%d!!!\n", - i + 4, 1); + i7core_printk(KERN_ERR, "Couldn't find socket %d " + "fn %d.%d!!!\n", + socket, i + 4, 1); return -ENODEV; } /* Devices 4-6 function 1 */ @@ -393,12 +403,13 @@ static int i7core_get_active_channels(int *channels, int *csrows) } } - debugf0("Number of active channels: %d\n", *channels); + debugf0("Number of active channels on socked %d: %d\n", + socket, *channels); return 0; } -static int get_dimm_config(struct mem_ctl_info *mci) +static int get_dimm_config(struct mem_ctl_info *mci, u8 socket) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; @@ -409,7 +420,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) enum mem_type mtype; /* Get data from the MC register, function 0 */ - pdev = pvt->pci_mcr[0]; + pdev = pvt->pci_mcr[socket][0]; if (!pdev) return -ENODEV; @@ -458,10 +469,11 @@ static int get_dimm_config(struct mem_ctl_info *mci) } /* Devices 4-6 function 0 */ - pci_read_config_dword(pvt->pci_ch[i][0], + pci_read_config_dword(pvt->pci_ch[socket][i][0], MC_CHANNEL_DIMM_INIT_PARAMS, &data); - pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ? 4 : 2; + pvt->channel[socket][i].ranks = (data & QUAD_RANK_PRESENT) ? + 4 : 2; if (data & REGISTERED_DIMM) mtype = MEM_RDDR3; @@ -477,11 +489,11 @@ static int get_dimm_config(struct mem_ctl_info *mci) #endif /* Devices 4-6 function 1 */ - pci_read_config_dword(pvt->pci_ch[i][1], + pci_read_config_dword(pvt->pci_ch[socket][i][1], MC_DOD_CH_DIMM0, &dimm_dod[0]); - pci_read_config_dword(pvt->pci_ch[i][1], + pci_read_config_dword(pvt->pci_ch[socket][i][1], MC_DOD_CH_DIMM1, &dimm_dod[1]); - pci_read_config_dword(pvt->pci_ch[i][1], + pci_read_config_dword(pvt->pci_ch[socket][i][1], MC_DOD_CH_DIMM2, &dimm_dod[2]); debugf0("Ch%d phy rd%d, wr%d (0x%08x): " @@ -489,7 +501,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) i, RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, - pvt->channel[i].ranks, + pvt->channel[socket][i].ranks, (data & REGISTERED_DIMM) ? 'R' : 'U'); for (j = 0; j < 3; j++) { @@ -507,7 +519,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) /* DDR3 has 8 I/O banks */ size = (rows * cols * banks * ranks) >> (20 - 3); - pvt->channel[i].dimms++; + pvt->channel[socket][i].dimms++; debugf0("\tdimm %d (0x%08x) %d Mb offset: %x, " "numbank: %d,\n\t\t" @@ -592,15 +604,42 @@ static int disable_inject(struct mem_ctl_info *mci) pvt->inject.enable = 0; - if (!pvt->pci_ch[pvt->inject.channel][0]) + if (!pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0]) return -ENODEV; - pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, 0); return 0; } +/* + * i7core inject inject.socket + * + * accept and store error injection inject.socket value + */ +static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, + const char *data, size_t count) +{ + struct i7core_pvt *pvt = mci->pvt_info; + unsigned long value; + int rc; + + rc = strict_strtoul(data, 10, &value); + if ((rc < 0) || (value > pvt->sockets)) + return 0; + + pvt->inject.section = (u32) value; + return count; +} + +static ssize_t i7core_inject_socket_show(struct mem_ctl_info *mci, + char *data) +{ + struct i7core_pvt *pvt = mci->pvt_info; + return sprintf(data, "%d\n", pvt->inject.socket); +} + /* * i7core inject inject.section * @@ -838,7 +877,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, int rc; long enable; - if (!pvt->pci_ch[pvt->inject.channel][0]) + if (!pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0]) return 0; rc = strict_strtoul(data, 10, &enable); @@ -856,7 +895,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.dimm < 0) mask |= 1L << 41; else { - if (pvt->channel[pvt->inject.channel].dimms > 2) + if (pvt->channel[pvt->inject.socket][pvt->inject.channel].dimms > 2) mask |= (pvt->inject.dimm & 0x3L) << 35; else mask |= (pvt->inject.dimm & 0x1L) << 36; @@ -866,7 +905,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.rank < 0) mask |= 1L << 40; else { - if (pvt->channel[pvt->inject.channel].dimms > 2) + if (pvt->channel[pvt->inject.socket][pvt->inject.channel].dimms > 2) mask |= (pvt->inject.rank & 0x1L) << 34; else mask |= (pvt->inject.rank & 0x3L) << 34; @@ -891,38 +930,41 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, mask |= (pvt->inject.col & 0x3fffL); /* Unlock writes to registers */ - pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 0x2); + pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], + MC_CFG_CONTROL, 0x2); msleep(100); /* Zeroes error count registers */ - pci_write_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, 0); - pci_write_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, 0); - pvt->ce_count_available = 0; + pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], + MC_TEST_ERR_RCV1, 0); + pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], + MC_TEST_ERR_RCV0, 0); + pvt->ce_count_available[pvt->inject.socket] = 0; #if USE_QWORD - pci_write_config_qword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_qword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); #else - pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); - pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L); #endif #if 1 #if USE_QWORD u64 rdmask; - pci_read_config_qword(pvt->pci_ch[pvt->inject.channel][0], + pci_read_config_qword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, &rdmask); debugf0("Inject addr match write 0x%016llx, read: 0x%016llx\n", mask, rdmask); #else u32 rdmask1, rdmask2; - pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, &rdmask1); - pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH + 4, &rdmask2); debugf0("Inject addr match write 0x%016llx, read: 0x%08x 0x%08x\n", @@ -930,7 +972,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, #endif #endif - pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); /* @@ -944,7 +986,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, (pvt->inject.section & 0x3) << 1 | (pvt->inject.type & 0x6) << (3 - 1); - pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, injectmask); #if 0 @@ -965,7 +1007,7 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, struct i7core_pvt *pvt = mci->pvt_info; u32 injectmask; - pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], + pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, &injectmask); debugf0("Inject error read: 0x%018x\n", injectmask); @@ -978,23 +1020,38 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) { + unsigned i, count, total = 0; struct i7core_pvt *pvt = mci->pvt_info; - if (!pvt->ce_count_available) - return sprintf(data, "unavailable\n"); + for (i = 0; i < pvt->sockets; i++) { + if (!pvt->ce_count_available[i]) + count = sprintf(data, "socket 0 data unavailable\n"); + else + count = sprintf(data, "socket %d, dimm0: %lu\n" + "dimm1: %lu\ndimm2: %lu\n", + i, + pvt->ce_count[i][0], + pvt->ce_count[i][1], + pvt->ce_count[i][2]); + data += count; + total += count; + } - return sprintf(data, "dimm0: %lu\ndimm1: %lu\ndimm2: %lu\n", - pvt->ce_count[0], - pvt->ce_count[1], - pvt->ce_count[2]); + return total; } /* * Sysfs struct */ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { - { + .attr = { + .name = "inject_socket", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_socket_show, + .store = i7core_inject_socket_store, + }, { .attr = { .name = "inject_section", .mode = (S_IRUGO | S_IWUSR) @@ -1049,10 +1106,11 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { */ static void i7core_put_devices(void) { - int i; + int i, j; - for (i = 0; i < N_DEVS; i++) - pci_dev_put(pci_devs[i].pdev); + for (i = 0; i < NUM_SOCKETS; i++) + for (j = 0; j < N_DEVS; j++) + pci_dev_put(pci_devs[j].pdev[i]); } /* @@ -1065,6 +1123,8 @@ static int i7core_get_devices(void) { int rc, i; struct pci_dev *pdev = NULL; + u8 bus = 0; + u8 socket = 0; for (i = 0; i < N_DEVS; i++) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, @@ -1078,14 +1138,32 @@ static int i7core_get_devices(void) pci_devs[i].dev_id, NULL); } - if (likely(pdev)) - pci_devs[i].pdev = pdev; - else { + if (likely(pdev)) { + bus = pdev->bus->number; + + if (bus == 0x3f) + socket = 0; + else + socket = 255 - bus; + + if (socket >= NUM_SOCKETS) { + i7core_printk(KERN_ERR, + "Found unexpected socket for " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + bus, pci_devs[i].dev, pci_devs[i].func, + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); + + rc = -ENODEV; + goto error; + } + + pci_devs[i].pdev[socket] = pdev; + } else { i7core_printk(KERN_ERR, - "Device not found: PCI ID %04x:%04x " - "(dev %d, func %d)\n", - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - pci_devs[i].dev, pci_devs[i].func); + "Device not found: " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + bus, pci_devs[i].dev, pci_devs[i].func, + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); /* Dev 3 function 2 only exists on chips with RDIMMs */ if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) @@ -1121,9 +1199,10 @@ static int i7core_get_devices(void) } i7core_printk(KERN_INFO, - "Registered device %0x:%0x fn %d.%d\n", - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + "Registered socket %d " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + socket, bus, pci_devs[i].dev, pci_devs[i].func, + PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); } return 0; @@ -1137,30 +1216,33 @@ static int mci_bind_devs(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; struct pci_dev *pdev; - int i, func, slot; + int i, j, func, slot; - for (i = 0; i < N_DEVS; i++) { - pdev = pci_devs[i].pdev; - if (!pdev) - continue; + for (i = 0; i < pvt->sockets; i++) { + for (j = 0; j < N_DEVS; j++) { + pdev = pci_devs[j].pdev[i]; + if (!pdev) + continue; - func = PCI_FUNC(pdev->devfn); - slot = PCI_SLOT(pdev->devfn); - if (slot == 3) { - if (unlikely(func > MAX_MCR_FUNC)) - goto error; - pvt->pci_mcr[func] = pdev; - } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { - if (unlikely(func > MAX_CHAN_FUNC)) + func = PCI_FUNC(pdev->devfn); + slot = PCI_SLOT(pdev->devfn); + if (slot == 3) { + if (unlikely(func > MAX_MCR_FUNC)) + goto error; + pvt->pci_mcr[i][func] = pdev; + } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { + if (unlikely(func > MAX_CHAN_FUNC)) + goto error; + pvt->pci_ch[i][slot - 4][func] = pdev; + } else if (!slot && !func) + pvt->pci_noncore[i] = pdev; + else goto error; - pvt->pci_ch[slot - 4][func] = pdev; - } else if (!slot && !func) - pvt->pci_noncore = pdev; - else - goto error; - debugf0("Associated fn %d.%d, dev = %p\n", - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev); + debugf0("Associated fn %d.%d, dev = %p, socket %d\n", + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + pdev, i); + } } return 0; @@ -1182,20 +1264,20 @@ error: * also available at: * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf */ -static void check_mc_test_err(struct mem_ctl_info *mci) +static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) { struct i7core_pvt *pvt = mci->pvt_info; u32 rcv1, rcv0; int new0, new1, new2; - if (!pvt->pci_mcr[4]) { + if (!pvt->pci_mcr[socket][4]) { debugf0("%s MCR registers not found\n",__func__); return; } /* Corrected error reads */ - pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1); - pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0); + pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV1, &rcv1); + pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV0, &rcv0); /* Store the new values */ new2 = DIMM2_COR_ERR(rcv1); @@ -1209,32 +1291,32 @@ static void check_mc_test_err(struct mem_ctl_info *mci) #endif /* Updates CE counters if it is not the first time here */ - if (pvt->ce_count_available) { + if (pvt->ce_count_available[socket]) { /* Updates CE counters */ int add0, add1, add2; - add2 = new2 - pvt->last_ce_count[2]; - add1 = new1 - pvt->last_ce_count[1]; - add0 = new0 - pvt->last_ce_count[0]; + add2 = new2 - pvt->last_ce_count[socket][2]; + add1 = new1 - pvt->last_ce_count[socket][1]; + add0 = new0 - pvt->last_ce_count[socket][0]; if (add2 < 0) add2 += 0x7fff; - pvt->ce_count[2] += add2; + pvt->ce_count[socket][2] += add2; if (add1 < 0) add1 += 0x7fff; - pvt->ce_count[1] += add1; + pvt->ce_count[socket][1] += add1; if (add0 < 0) add0 += 0x7fff; - pvt->ce_count[0] += add0; + pvt->ce_count[socket][0] += add0; } else - pvt->ce_count_available = 1; + pvt->ce_count_available[socket] = 1; /* Store the new values */ - pvt->last_ce_count[2] = new2; - pvt->last_ce_count[1] = new1; - pvt->last_ce_count[0] = new0; + pvt->last_ce_count[socket][2] = new2; + pvt->last_ce_count[socket][1] = new1; + pvt->last_ce_count[socket][0] = new0; } static void i7core_mce_output_error(struct mem_ctl_info *mci, @@ -1299,7 +1381,8 @@ static void i7core_check_error(struct mem_ctl_info *mci) kfree(m); /* check memory count errors */ - check_mc_test_err(mci); + for (i = 0; i < pvt->sockets; i++) + check_mc_test_err(mci, i); } /* @@ -1339,10 +1422,11 @@ static int __devinit i7core_probe(struct pci_dev *pdev, { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int num_channels; - int num_csrows; + int num_channels = 0; + int num_csrows = 0; int dev_idx = id->driver_data; - int rc; + int rc, i; + u8 sockets; if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs))) return -EINVAL; @@ -1352,10 +1436,25 @@ static int __devinit i7core_probe(struct pci_dev *pdev, if (unlikely(rc < 0)) return rc; - /* Check the number of active and not disabled channels */ - rc = i7core_get_active_channels(&num_channels, &num_csrows); - if (unlikely(rc < 0)) - goto fail0; + sockets = 1; + for (i = NUM_SOCKETS - 1; i > 0; i--) + if (pci_devs[0].pdev[i]) { + sockets = i + 1; + break; + } + + for (i = 0; i < sockets; i++) { + int channels; + int csrows; + + /* Check the number of active and not disabled channels */ + rc = i7core_get_active_channels(i, &channels, &csrows); + if (unlikely(rc < 0)) + goto fail0; + + num_channels += channels; + num_csrows += csrows; + } /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); @@ -1367,11 +1466,11 @@ static int __devinit i7core_probe(struct pci_dev *pdev, debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); mci->dev = &pdev->dev; /* record ptr to the generic device */ - pvt = mci->pvt_info; memset(pvt, 0, sizeof(*pvt)); - + pvt->sockets = sockets; mci->mc_idx = 0; + /* * FIXME: how to handle RDDR3 at MCI level? It is possible to have * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different @@ -1395,7 +1494,8 @@ static int __devinit i7core_probe(struct pci_dev *pdev, goto fail1; /* Get dimm basic config */ - get_dimm_config(mci); + for (i = 0; i < sockets; i++) + get_dimm_config(mci, i); /* add this new MC control structure to EDAC's list of MCs */ if (unlikely(edac_mc_add_mc(mci))) { -- GitLab From ba6c5c62eeb877da638e43f1282f778432142eec Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 15 Jul 2009 09:02:32 -0300 Subject: [PATCH 107/842] i7core_edac: maps all sockets as if ther are one MC controller Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 69eacc1b50d7..a93ebdf9c121 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -409,12 +409,12 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels, return 0; } -static int get_dimm_config(struct mem_ctl_info *mci, u8 socket) +static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; struct pci_dev *pdev; - int i, j, csrow = 0; + int i, j; unsigned long last_page = 0; enum edac_type mode; enum mem_type mtype; @@ -534,7 +534,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, u8 socket) npages = size << (20 - PAGE_SHIFT); #endif - csr = &mci->csrows[csrow]; + csr = &mci->csrows[*csrow]; csr->first_page = last_page + 1; last_page += npages; csr->last_page = last_page; @@ -542,7 +542,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, u8 socket) csr->page_mask = 0; csr->grain = 8; - csr->csrow_idx = csrow; + csr->csrow_idx = *csrow; csr->nr_channels = 1; csr->channels[0].chan_idx = i; @@ -565,7 +565,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, u8 socket) csr->edac_mode = mode; csr->mtype = mtype; - csrow++; + (*csrow)++; } pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); @@ -1424,6 +1424,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, struct i7core_pvt *pvt; int num_channels = 0; int num_csrows = 0; + int csrow = 0; int dev_idx = id->driver_data; int rc, i; u8 sockets; @@ -1495,7 +1496,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* Get dimm basic config */ for (i = 0; i < sockets; i++) - get_dimm_config(mci, i); + get_dimm_config(mci, &csrow, i); /* add this new MC control structure to EDAC's list of MCs */ if (unlikely(edac_mc_add_mc(mci))) { -- GitLab From 8a2f118e3a023a4e8cbe56a6e51f7b78fa8c76a0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 15 Jul 2009 19:01:08 -0300 Subject: [PATCH 108/842] i7core_edac: decode mcelog error and send it via edac interface Enriches mcelog error by using the encoded information at MCE status and misc registers (IA32_MCx_STATUS, IA32_MCx_MISC). Some fixes are still needed here, in order to properly fill the EDAC fields. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 92 +++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 22 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index a93ebdf9c121..4397a3171c62 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1319,33 +1319,75 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) pvt->last_ce_count[socket][0] = new0; } +/* + * According with tables E-11 and E-12 of chapter E.3.3 of Intel 64 and IA-32 + * Architectures Software Developer’s Manual Volume 3B. + * The MCA registers are the following ones: + * struct mce field MCA Register + * m->status MSR_IA32_MC0_STATUS + * m->addr MSR_IA32_MC0_ADDR + * m->misc MSR_IA32_MC0_MISC + * m->mcgstatus MSR_IA32_MCG_STATUS + * In the case of Nehalem, the error information is masked at .status and .misc + * fields + */ static void i7core_mce_output_error(struct mem_ctl_info *mci, struct mce *m) { - debugf0("CPU %d: Machine Check Exception: %16Lx" - "Bank %d: %016Lx\n", - m->cpu, m->mcgstatus, m->bank, m->status); - if (m->ip) { - debugf0("RIP%s %02x:<%016Lx>\n", - !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "", - m->cs, m->ip); + char *type="NON-FATAL"; + char *err, *msg; + unsigned long error = m->status & 0x1ff0000l; + u32 core_err_cnt = (m->status >> 38) && 0x7fff; + u32 dimm = (m->misc >> 16) & 0x3; + u32 channel = (m->misc >> 18) & 0x3; + u32 syndrome = m->misc >> 32; + u32 errnum = find_first_bit(&error, 32); + + switch (errnum) { + case 16: + err = "read ECC error"; + break; + case 17: + err = "RAS ECC error"; + break; + case 18: + err = "write parity error"; + break; + case 19: + err = "redundacy loss"; + break; + case 20: + err = "reserved"; + break; + case 21: + err = "memory range error"; + break; + case 22: + err = "RTID out of range"; + break; + case 23: + err = "address parity error"; + break; + case 24: + err = "byte enable parity error"; + break; + default: + err = "unknown"; } - printk(KERN_EMERG "TSC %llx ", m->tsc); - if (m->addr) - printk("ADDR %llx ", m->addr); - if (m->misc) - printk("MISC %llx ", m->misc); -#if 0 - snprintf(msg, sizeof(msg), - "%s (Branch=%d DRAM-Bank=%d Buffer ID = %d RDWR=%s " - "RAS=%d CAS=%d %s Err=0x%lx (%s))", - type, branch >> 1, bank, buf_id, rdwr_str(rdwr), ras, cas, - type, allErrors, error_name[errnum]); + msg = kasprintf(GFP_ATOMIC, + "%s (addr = 0x%08llx Bank=0x%08x, Dimm=%d, Channel=%d, " + "syndrome=0x%08x total error count=%d Err=%d (%s))\n", + type, (long long) m->addr, m->bank, dimm, channel, + syndrome, core_err_cnt,errnum, err); + + debugf0("%s", msg); /* Call the helper to output message */ - edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); -#endif + edac_mc_handle_fbd_ue(mci, 0 /* FIXME: should be rank here */, + 0, 0 /* FIXME: should be channel here */, msg); + + kfree(msg); } /* @@ -1398,6 +1440,13 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) debugf0(__FILE__ ": %s()\n", __func__); + /* + * Just let mcelog handle it if the error is + * outside the memory controller + */ + if (((mce->status & 0xffff) >> 7) != 1) + return 0; + spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count < MCE_LOG_LEN) { memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); @@ -1406,8 +1455,7 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) spin_unlock_irqrestore(&pvt->mce_lock, flags); /* Advice mcelog that the error were handled */ -// return 1; - return 0; // Let's duplicate the log + return 1; } /* -- GitLab From f237fcf2b7560be33386255042dc11167ca486d5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 15 Jul 2009 19:53:24 -0300 Subject: [PATCH 109/842] i7core_edac: some fixes at memory error parser m->bank is not related to the memory bank but, instead, to the MCA Error register bank. Fix it accordingly. While here, improves the comments for Nehalem bank. A later fix is needed, in order to get bank/rank information from MCA error log. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 4397a3171c62..67822976992e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1322,12 +1322,13 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) /* * According with tables E-11 and E-12 of chapter E.3.3 of Intel 64 and IA-32 * Architectures Software Developer’s Manual Volume 3B. - * The MCA registers are the following ones: + * Nehalem are defined as family 0x06, model 0x1a + * + * The MCA registers used here are the following ones: * struct mce field MCA Register - * m->status MSR_IA32_MC0_STATUS - * m->addr MSR_IA32_MC0_ADDR - * m->misc MSR_IA32_MC0_MISC - * m->mcgstatus MSR_IA32_MCG_STATUS + * m->status MSR_IA32_MC8_STATUS + * m->addr MSR_IA32_MC8_ADDR + * m->misc MSR_IA32_MC8_MISC * In the case of Nehalem, the error information is masked at .status and .misc * fields */ @@ -1375,10 +1376,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, err = "unknown"; } + /* FIXME: should convert addr into bank and rank information */ msg = kasprintf(GFP_ATOMIC, - "%s (addr = 0x%08llx Bank=0x%08x, Dimm=%d, Channel=%d, " - "syndrome=0x%08x total error count=%d Err=%d (%s))\n", - type, (long long) m->addr, m->bank, dimm, channel, + "%s (addr = 0x%08llx Dimm=%d, Channel=%d, " + "syndrome=0x%08x, count=%d Err=%d (%s))\n", + type, (long long) m->addr, dimm, channel, syndrome, core_err_cnt,errnum, err); debugf0("%s", msg); @@ -1447,6 +1449,10 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) if (((mce->status & 0xffff) >> 7) != 1) return 0; + /* Bank 8 registers are the only ones that we know how to handle */ + if (mce->bank != 8) + return 0; + spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count < MCE_LOG_LEN) { memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); -- GitLab From 310cbb7284fab9fc9cbb6bb893e51c414e15bba3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Fri, 17 Jul 2009 00:09:10 -0300 Subject: [PATCH 110/842] i7core: fix probing on Xeon55xx Xeon55xx fails to probe with this error message: EDAC DEBUG: in drivers/edac/i7core_edac.c, line at 1660: MC: drivers/edac/i7core_edac.c: i7core_init() EDAC i7core: Device not found: dev 00:00.0 PCI ID 8086:2c41 i7core_edac: probe of 0000:00:14.0 failed with error -22 This is due to the fact that, on Xeon35xx (and i7core), device 00.0 has PCI ID 8086:2c40. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 23 ++++++++++++++++++++--- include/linux/pci_ids.h | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 67822976992e..e2f6dfdca841 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -227,9 +227,6 @@ struct i7core_dev_info { .dev_id = (device_id) struct pci_id_descr pci_devs[] = { - /* Generic Non-core registers */ - { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, - /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, @@ -253,6 +250,16 @@ struct pci_id_descr pci_devs[] = { { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) }, { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) }, { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) }, + + /* Generic Non-core registers */ + /* + * This is the PCI device on i7core and on Xeon 35xx (8086:2c41) + * On Xeon 55xx, however, it has a different id (8086:2c40). So, + * the probing code needs to test for the other address in case of + * failure of this one + */ + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, + }; #define N_DEVS ARRAY_SIZE(pci_devs) @@ -1138,6 +1145,16 @@ static int i7core_get_devices(void) pci_devs[i].dev_id, NULL); } + /* + * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs + * is at addr 8086:2c40, instead of 8086:2c41. So, we need + * to probe for the alternate address in case of failure + */ + if (pci_devs[i].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE + && !pdev) + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, NULL); + if (likely(pdev)) { bus = pdev->bus->number; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 12c3da6ef14d..bf6db4814c27 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2549,6 +2549,7 @@ #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK 0x2c32 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33 #define PCI_DEVICE_ID_INTEL_I7_NOCORE 0x2c41 +#define PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT 0x2c40 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 #define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a -- GitLab From c5d34528696acadc40d2ba7601dbf35d65b74ad5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Fri, 17 Jul 2009 10:28:15 -0300 Subject: [PATCH 111/842] i7core: check if the memory error is fatal or non-fatal Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e2f6dfdca841..08149d5addff 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1352,7 +1352,7 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) static void i7core_mce_output_error(struct mem_ctl_info *mci, struct mce *m) { - char *type="NON-FATAL"; + char *type; char *err, *msg; unsigned long error = m->status & 0x1ff0000l; u32 core_err_cnt = (m->status >> 38) && 0x7fff; @@ -1361,6 +1361,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); + if (m->mcgstatus & 1) + type = "FATAL"; + else + type = "NON_FATAL"; + switch (errnum) { case 16: err = "read ECC error"; @@ -1454,7 +1459,8 @@ static void i7core_check_error(struct mem_ctl_info *mci) */ static int i7core_mce_check_error(void *priv, struct mce *mce) { - struct i7core_pvt *pvt = priv; + struct mem_ctl_info *mci = priv; + struct i7core_pvt *pvt = mci->pvt_info; unsigned long flags; debugf0(__FILE__ ": %s()\n", __func__); @@ -1477,6 +1483,10 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) } spin_unlock_irqrestore(&pvt->mce_lock, flags); + /* Handle fatal errors immediately */ + if (mce->mcgstatus & 1) + i7core_check_error(mci); + /* Advice mcelog that the error were handled */ return 1; } @@ -1601,7 +1611,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, pvt->inject.col = -1; /* Registers on edac_mce in order to receive memory errors */ - pvt->edac_mce.priv = pvt; + pvt->edac_mce.priv = mci; pvt->edac_mce.check_error = i7core_mce_check_error; spin_lock_init(&pvt->mce_lock); -- GitLab From a639539fa28531924c6b5e0f3963cc63d060947d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Fri, 17 Jul 2009 10:54:23 -0300 Subject: [PATCH 112/842] i7core: enrich error information based on memory transaction type Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 08149d5addff..9f39d3d5502e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1352,9 +1352,9 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) static void i7core_mce_output_error(struct mem_ctl_info *mci, struct mce *m) { - char *type; - char *err, *msg; + char *type, *optype, *err, *msg; unsigned long error = m->status & 0x1ff0000l; + u32 optypenum = (m->status >> 4) & 0x07; u32 core_err_cnt = (m->status >> 38) && 0x7fff; u32 dimm = (m->misc >> 16) & 0x3; u32 channel = (m->misc >> 18) & 0x3; @@ -1366,6 +1366,27 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, else type = "NON_FATAL"; + switch (optypenum) { + case 0: + optype = "generic undef request"; + break; + case 1: + optype = "read error"; + break; + case 2: + optype = "write error"; + break; + case 3: + optype = "addr/cmd error"; + break; + case 4: + optype = "scrubbing error"; + break; + default: + optype = "reserved"; + break; + } + switch (errnum) { case 16: err = "read ECC error"; @@ -1400,10 +1421,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, /* FIXME: should convert addr into bank and rank information */ msg = kasprintf(GFP_ATOMIC, - "%s (addr = 0x%08llx Dimm=%d, Channel=%d, " - "syndrome=0x%08x, count=%d Err=%d (%s))\n", + "%s (addr = 0x%08llx, Dimm=%d, Channel=%d, " + "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", type, (long long) m->addr, dimm, channel, - syndrome, core_err_cnt,errnum, err); + syndrome, core_err_cnt, (long long)m->status, + (long long)m->misc, optype, err); debugf0("%s", msg); -- GitLab From c77720b9544d8825ff5b9546d0ee038cfa4d4eb2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 18 Jul 2009 10:43:08 -0300 Subject: [PATCH 113/842] i7core: fix get_devices routine for Xeon55xx i7core_get_devices() were preparet to get just the first found device of each type. Due to that, on Xeon 55xx, only socket 1 were retrived. Rework i7core_get_devices() to clean it and to properly support Xeon 55xx. While here, fix a small typo. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 186 +++++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 78 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 9f39d3d5502e..79636b58ec52 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -410,7 +410,7 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels, } } - debugf0("Number of active channels on socked %d: %d\n", + debugf0("Number of active channels on socket %d: %d\n", socket, *channels); return 0; @@ -1126,107 +1126,137 @@ static void i7core_put_devices(void) * * Need to 'get' device 16 func 1 and func 2 */ -static int i7core_get_devices(void) +int i7core_get_onedevice(struct pci_dev **prev, int devno) { - int rc, i; struct pci_dev *pdev = NULL; u8 bus = 0; u8 socket = 0; - for (i = 0; i < N_DEVS; i++) { + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + pci_devs[devno].dev_id, *prev); + + /* + * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses + * aren't announced by acpi. So, we need to use a legacy scan probing + * to detect them + */ + if (unlikely(!pdev && !devno && !prev)) { + pcibios_scan_specific_bus(254); + pcibios_scan_specific_bus(255); + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_devs[i].dev_id, NULL); + pci_devs[devno].dev_id, *prev); + } - if (!pdev && !i) { - pcibios_scan_specific_bus(254); - pcibios_scan_specific_bus(255); + /* + * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs + * is at addr 8086:2c40, instead of 8086:2c41. So, we need + * to probe for the alternate address in case of failure + */ + if (pci_devs[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev) + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, *prev); - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_devs[i].dev_id, NULL); + if (!pdev) { + if (*prev) { + *prev = pdev; + return 0; } /* - * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs - * is at addr 8086:2c40, instead of 8086:2c41. So, we need - * to probe for the alternate address in case of failure + * Dev 3 function 2 only exists on chips with RDIMMs + * so, it is ok to not found it */ - if (pci_devs[i].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE - && !pdev) - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, NULL); + if ((pci_devs[devno].dev == 3) && (pci_devs[devno].func == 2)) { + *prev = pdev; + return 0; + } - if (likely(pdev)) { - bus = pdev->bus->number; + i7core_printk(KERN_ERR, + "Device not found: dev %02x.%d PCI ID %04x:%04x\n", + pci_devs[devno].dev, pci_devs[devno].func, + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); - if (bus == 0x3f) - socket = 0; - else - socket = 255 - bus; + /* End of list, leave */ + return -ENODEV; + } + bus = pdev->bus->number; - if (socket >= NUM_SOCKETS) { - i7core_printk(KERN_ERR, - "Found unexpected socket for " - "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_devs[i].dev, pci_devs[i].func, - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); + if (bus == 0x3f) + socket = 0; + else + socket = 255 - bus; + + if (socket >= NUM_SOCKETS) { + i7core_printk(KERN_ERR, + "Unexpected socket for " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + bus, pci_devs[devno].dev, pci_devs[devno].func, + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + pci_dev_put(pdev); + return -ENODEV; + } - rc = -ENODEV; - goto error; - } + if (pci_devs[devno].pdev[socket]) { + i7core_printk(KERN_ERR, + "Duplicated device for " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + bus, pci_devs[devno].dev, pci_devs[devno].func, + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + pci_dev_put(pdev); + return -ENODEV; + } - pci_devs[i].pdev[socket] = pdev; - } else { - i7core_printk(KERN_ERR, - "Device not found: " - "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_devs[i].dev, pci_devs[i].func, - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); + pci_devs[devno].pdev[socket] = pdev; + + /* Sanity check */ + if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[devno].dev || + PCI_FUNC(pdev->devfn) != pci_devs[devno].func)) { + i7core_printk(KERN_ERR, + "Device PCI ID %04x:%04x " + "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n", + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id, + bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + bus, pci_devs[devno].dev, pci_devs[devno].func); + return -ENODEV; + } - /* Dev 3 function 2 only exists on chips with RDIMMs */ - if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) - continue; + /* Be sure that the device is enabled */ + if (unlikely(pci_enable_device(pdev) < 0)) { + i7core_printk(KERN_ERR, + "Couldn't enable " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + bus, pci_devs[devno].dev, pci_devs[devno].func, + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + return -ENODEV; + } - /* End of list, leave */ - rc = -ENODEV; - goto error; - } + i7core_printk(KERN_INFO, + "Registered socket %d " + "dev %02x:%02x.%d PCI ID %04x:%04x\n", + socket, bus, pci_devs[devno].dev, pci_devs[devno].func, + PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); - /* Sanity check */ - if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[i].dev || - PCI_FUNC(pdev->devfn) != pci_devs[i].func)) { - i7core_printk(KERN_ERR, - "Device PCI ID %04x:%04x " - "has fn %d.%d instead of fn %d.%d\n", - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - pci_devs[i].dev, pci_devs[i].func); - rc = -EINVAL; - goto error; - } + *prev = pdev; - /* Be sure that the device is enabled */ - rc = pci_enable_device(pdev); - if (unlikely(rc < 0)) { - i7core_printk(KERN_ERR, - "Couldn't enable PCI ID %04x:%04x " - "fn %d.%d\n", - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - goto error; - } + return 0; +} - i7core_printk(KERN_INFO, - "Registered socket %d " - "dev %02x:%02x.%d PCI ID %04x:%04x\n", - socket, bus, pci_devs[i].dev, pci_devs[i].func, - PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id); - } +static int i7core_get_devices(void) +{ + int i; + struct pci_dev *pdev = NULL; + for (i = 0; i < N_DEVS; i++) { + pdev = NULL; + do { + if (i7core_get_onedevice(&pdev, i) < 0) { + i7core_put_devices(); + return -ENODEV; + } + } while (pdev); + } return 0; - -error: - i7core_put_devices(); - return -EINVAL; } static int mci_bind_devs(struct mem_ctl_info *mci) -- GitLab From ec6df24c15822e671801eeeb53758e14f3b28381 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 18 Jul 2009 10:44:30 -0300 Subject: [PATCH 114/842] i7core: better document i7core_get_active_channels() Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 79636b58ec52..bf0374062e3d 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -333,7 +333,6 @@ static inline int numcol(u32 col) return cols[col & 0x3]; } - /**************************************************************************** Memory check routines ****************************************************************************/ @@ -355,6 +354,23 @@ static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, return NULL; } +/** + * i7core_get_active_channels() - gets the number of channels and csrows + * @socket: Quick Path Interconnect socket + * @channels: Number of channels that will be returned + * @csrows: Number of csrows found + * + * Since EDAC core needs to know in advance the number of available channels + * and csrows, in order to allocate memory for csrows/channels, it is needed + * to run two similar steps. At the first step, implemented on this function, + * it checks the number of csrows/channels present at one socket. + * this is used in order to properly allocate the size of mci components. + * + * It should be noticed that none of the current available datasheets explain + * or even mention how csrows are seen by the memory controller. So, we need + * to add a fake description for csrows. + * So, this driver is attributing one DIMM memory for one csrow. + */ static int i7core_get_active_channels(u8 socket, unsigned *channels, unsigned *csrows) { -- GitLab From 3a7dde7fcd0dd50df33e0e7070d4947551d767fc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 18 Jul 2009 12:20:04 -0300 Subject: [PATCH 115/842] i7core: add socket info at the debug msg Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index bf0374062e3d..5695413c2879 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1467,9 +1467,9 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, /* FIXME: should convert addr into bank and rank information */ msg = kasprintf(GFP_ATOMIC, - "%s (addr = 0x%08llx, Dimm=%d, Channel=%d, " + "%s (addr = 0x%08llx, socket=%d, Dimm=%d, Channel=%d, " "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", - type, (long long) m->addr, dimm, channel, + type, (long long) m->addr, m->cpu, dimm, channel, syndrome, core_err_cnt, (long long)m->status, (long long)m->misc, optype, err); -- GitLab From 086271a0374bf0b9ce033aac9fb60530c421ad65 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 18 Jul 2009 12:22:28 -0300 Subject: [PATCH 116/842] i7core: remove some uneeded noisy debug messages Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 5695413c2879..fd00e0299ca1 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1494,8 +1494,6 @@ static void i7core_check_error(struct mem_ctl_info *mci) struct mce *m = NULL; unsigned long flags; - debugf0(__FILE__ ": %s()\n", __func__); - /* Copy all mce errors into a temporary buffer */ spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count) { @@ -1531,8 +1529,6 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) struct i7core_pvt *pvt = mci->pvt_info; unsigned long flags; - debugf0(__FILE__ ": %s()\n", __func__); - /* * Just let mcelog handle it if the error is * outside the memory controller -- GitLab From 17cb7b0cf78c14913c5410eff2ce03e1d9c8d958 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 20 Jul 2009 18:48:18 -0300 Subject: [PATCH 117/842] i7core_edac: Some cleanups at displayed info Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index fd00e0299ca1..86af14840b88 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -453,8 +453,8 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) pci_read_config_dword(pdev, MC_MAX_DOD, &pvt->info.max_dod); pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map); - debugf0("MC control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n", - pvt->info.mc_control, pvt->info.mc_status, + debugf0("QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n", + socket, pvt->info.mc_control, pvt->info.mc_status, pvt->info.max_dod, pvt->info.ch_map); if (ECC_ENABLED(pvt)) { @@ -469,16 +469,14 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) } /* FIXME: need to handle the error codes */ - debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked\n", + debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked " + "x%x x 0x%x\n", numdimms(pvt->info.max_dod), numrank(pvt->info.max_dod >> 2), numbank(pvt->info.max_dod >> 4)); - debugf0("DOD Max rows x colums = 0x%x x 0x%x\n", numrow(pvt->info.max_dod >> 6), numcol(pvt->info.max_dod >> 9)); - debugf0("Memory channel configuration:\n"); - for (i = 0; i < NUM_CHANS; i++) { u32 data, dimm_dod[3], value[8]; @@ -544,10 +542,9 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) pvt->channel[socket][i].dimms++; - debugf0("\tdimm %d (0x%08x) %d Mb offset: %x, " - "numbank: %d,\n\t\t" - "numrank: %d, numrow: %#x, numcol: %#x\n", - j, dimm_dod[j], size, + debugf0("\tdimm %d %d Mb offset: %x, " + "bank: %d, rank: %d, row: %#x, col: %#x\n", + j, size, RANKOFFSET(dimm_dod[j]), banks, ranks, rows, cols); @@ -599,9 +596,9 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]); pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]); pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]); - debugf0("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); + debugf1("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i); for (j = 0; j < 8; j++) - debugf0("\t\t%#x\t%#x\t%#x\n", + debugf1("\t\t%#x\t%#x\t%#x\n", (value[j] >> 27) & 0x1, (value[j] >> 24) & 0x7, (value[j] && ((1 << 24) - 1))); -- GitLab From 276b824c3095b09e8cb76f5709f56e9c6818ae85 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 22 Jul 2009 21:45:50 -0300 Subject: [PATCH 118/842] i7core_edac: some fixes at error injection code Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 104 ++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 86af14840b88..72859e87aeb2 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -32,9 +32,6 @@ #include "edac_core.h" -/* To use the new pci_[read/write]_config_qword instead of two dword */ -#define USE_QWORD 0 - /* * Alter this version for the module when modifications are made */ @@ -473,7 +470,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) "x%x x 0x%x\n", numdimms(pvt->info.max_dod), numrank(pvt->info.max_dod >> 2), - numbank(pvt->info.max_dod >> 4)); + numbank(pvt->info.max_dod >> 4), numrow(pvt->info.max_dod >> 6), numcol(pvt->info.max_dod >> 9)); @@ -646,7 +643,7 @@ static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, int rc; rc = strict_strtoul(data, 10, &value); - if ((rc < 0) || (value > pvt->sockets)) + if ((rc < 0) || (value >= pvt->sockets)) return 0; pvt->inject.section = (u32) value; @@ -803,7 +800,7 @@ static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, else return cmd - data; } else if (!strcasecmp(cmd, "dimm")) { - if (value < 4) + if (value < 3) pvt->inject.dimm = value; else return cmd - data; @@ -813,7 +810,7 @@ static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, else return cmd - data; } else if (!strcasecmp(cmd, "bank")) { - if (value < 4) + if (value < 32) pvt->inject.bank = value; else return cmd - data; @@ -870,6 +867,28 @@ static ssize_t i7core_inject_addrmatch_show(struct mem_ctl_info *mci, channel, dimm, bank, rank, page, col); } +static int write_and_test(struct pci_dev *dev, int where, u32 val) +{ + u32 read; + int count; + + for (count = 0; count < 10; count++) { + if (count) + msleep (100); + pci_write_config_dword(dev, where, val); + pci_read_config_dword(dev, where, &read); + + if (read == val) + return 0; + } + + debugf0("Error Injection Register 0x%02x: Tried to write 0x%08x, " + "but read: 0x%08x\n", where, val, read); + + return -EINVAL; +} + + /* * This routine prepares the Memory Controller for error injection. * The error will be injected when some process tries to write to the @@ -949,70 +968,49 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, else mask |= (pvt->inject.col & 0x3fffL); - /* Unlock writes to registers */ + /* + * bit 0: REPEAT_EN + * bits 1-2: MASK_HALF_CACHELINE + * bit 3: INJECT_ECC + * bit 4: INJECT_ADDR_PARITY + */ + + injectmask = (pvt->inject.type & 1) | + (pvt->inject.section & 0x3) << 1 | + (pvt->inject.type & 0x6) << (3 - 1); + + /* Unlock writes to registers - this register is write only */ pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], MC_CFG_CONTROL, 0x2); - msleep(100); +#if 0 /* Zeroes error count registers */ pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], MC_TEST_ERR_RCV1, 0); pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], MC_TEST_ERR_RCV0, 0); pvt->ce_count_available[pvt->inject.socket] = 0; +#endif - -#if USE_QWORD - pci_write_config_qword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); -#else - pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ADDR_MATCH, mask); - pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L); -#endif -#if 1 -#if USE_QWORD - u64 rdmask; - pci_read_config_qword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ADDR_MATCH, &rdmask); - debugf0("Inject addr match write 0x%016llx, read: 0x%016llx\n", - mask, rdmask); -#else - u32 rdmask1, rdmask2; - - pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ADDR_MATCH, &rdmask1); - pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ADDR_MATCH + 4, &rdmask2); - - debugf0("Inject addr match write 0x%016llx, read: 0x%08x 0x%08x\n", - mask, rdmask1, rdmask2); -#endif -#endif - - pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); + write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + MC_CHANNEL_ERROR_MASK, injectmask); + /* - * bit 0: REPEAT_EN - * bits 1-2: MASK_HALF_CACHELINE - * bit 3: INJECT_ECC - * bit 4: INJECT_ADDR_PARITY + * This is something undocumented, based on my tests + * Without writing 8 to this register, errors aren't injected. Not sure + * why. */ + pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], + MC_CFG_CONTROL, 8); - injectmask = (pvt->inject.type & 1) | - (pvt->inject.section & 0x3) << 1 | - (pvt->inject.type & 0x6) << (3 - 1); - - pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ERROR_MASK, injectmask); - -#if 0 - /* lock writes to registers */ - pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 0); -#endif debugf0("Error inject addr match 0x%016llx, ecc 0x%08x," " inject 0x%08x\n", mask, pvt->inject.eccmask, injectmask); -- GitLab From 2068def56c09f2b24e6de04a1b84757a0fb07947 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 5 Aug 2009 19:28:27 -0300 Subject: [PATCH 119/842] i7core_edac: fix error codes for sysfs error injection interface Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 72859e87aeb2..ab9d26ec19d7 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -644,7 +644,7 @@ static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, rc = strict_strtoul(data, 10, &value); if ((rc < 0) || (value >= pvt->sockets)) - return 0; + return -EIO; pvt->inject.section = (u32) value; return count; @@ -676,7 +676,7 @@ static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci, rc = strict_strtoul(data, 10, &value); if ((rc < 0) || (value > 3)) - return 0; + return -EIO; pvt->inject.section = (u32) value; return count; @@ -709,7 +709,7 @@ static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci, rc = strict_strtoul(data, 10, &value); if ((rc < 0) || (value > 7)) - return 0; + return -EIO; pvt->inject.type = (u32) value; return count; @@ -744,7 +744,7 @@ static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci, rc = strict_strtoul(data, 10, &value); if (rc < 0) - return 0; + return -EIO; pvt->inject.eccmask = (u32) value; return count; -- GitLab From 4157d9f55435331deef01ba8a9a47f248c042fb2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 5 Aug 2009 20:27:15 -0300 Subject: [PATCH 120/842] i7core_edac: fix error injection There were two stupid error injection bugs introduced by wrong cut-and-paste: one at socket store, and another at the error inject register. The last one were causing the code to not work at all. While here, adds debug messages to allow seeing what registers are being set while sending error injection. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index ab9d26ec19d7..f16aac253654 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -625,7 +625,7 @@ static int disable_inject(struct mem_ctl_info *mci) return -ENODEV; pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ERROR_MASK, 0); + MC_CHANNEL_ERROR_INJECT, 0); return 0; } @@ -646,7 +646,7 @@ static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, if ((rc < 0) || (value >= pvt->sockets)) return -EIO; - pvt->inject.section = (u32) value; + pvt->inject.socket = (u32) value; return count; } @@ -872,6 +872,10 @@ static int write_and_test(struct pci_dev *dev, int where, u32 val) u32 read; int count; + debugf0("setting pci %02x:%02x.%x reg=%02x value=%08x\n", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + where, val); + for (count = 0; count < 10; count++) { if (count) msleep (100); @@ -882,8 +886,10 @@ static int write_and_test(struct pci_dev *dev, int where, u32 val) return 0; } - debugf0("Error Injection Register 0x%02x: Tried to write 0x%08x, " - "but read: 0x%08x\n", where, val, read); + i7core_printk(KERN_ERR, "Error during set pci %02x:%02x.%x reg=%02x " + "write=%08x. Read=%08x\n", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + where, val, read); return -EINVAL; } @@ -983,15 +989,6 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], MC_CFG_CONTROL, 0x2); -#if 0 - /* Zeroes error count registers */ - pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], - MC_TEST_ERR_RCV1, 0); - pci_write_config_dword(pvt->pci_mcr[pvt->inject.socket][4], - MC_TEST_ERR_RCV0, 0); - pvt->ce_count_available[pvt->inject.socket] = 0; -#endif - write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], @@ -1001,7 +998,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ERROR_MASK, injectmask); + MC_CHANNEL_ERROR_INJECT, injectmask); /* * This is something undocumented, based on my tests @@ -1026,7 +1023,7 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, u32 injectmask; pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], - MC_CHANNEL_ERROR_MASK, &injectmask); + MC_CHANNEL_ERROR_INJECT, &injectmask); debugf0("Inject error read: 0x%018x\n", injectmask); -- GitLab From 31983a04d686f9f90b356072089d8d677e40e776 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 5 Aug 2009 21:16:56 -0300 Subject: [PATCH 121/842] Documentation/edac.txt: Add Nehalem specific EDAC characteristics As Nehalem has a different binding to EDAC API, and its own different error injection code, documents it. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- Documentation/edac.txt | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/Documentation/edac.txt b/Documentation/edac.txt index 79c533223762..8bc320467c64 100644 --- a/Documentation/edac.txt +++ b/Documentation/edac.txt @@ -6,6 +6,8 @@ Written by Doug Thompson <dougthompson@xmission.com> 7 Dec 2005 17 Jul 2007 Updated +(c) Mauro Carvalho Chehab <mchehab@redhat.com> +05 Aug 2009 Nehalem interface EDAC is maintained and written by: @@ -717,3 +719,111 @@ unique drivers for their hardware systems. The 'test_device_edac' sample driver is located at the bluesmoke.sourceforge.net project site for EDAC. +======================================================================= +NEHALEM USAGE OF EDAC APIs + +This chapter documents some EXPERIMENTAL mappings for EDAC API to handle +Nehalem EDAC driver. They will likely be changed on future versions +of the driver. + +Due to the way Nehalem exports Memory Controller data, some adjustments +were done at i7core_edac driver. This chapter will cover those differences + +1) On Nehalem, there are one Memory Controller per Quick Patch Interconnect + (QPI). At the driver, the term "socket" means one QPI. It should also be + associated with the CPU physical socket. + + Each MC have 3 physical read channels, 3 physical write channels and + 3 logic channels. The driver currenty sees it as just 3 channels. + Each channel can have up to 3 DIMMs. + + The minimum known unity is DIMMs. There are no information about csrows. + As EDAC API maps the minimum unity is csrows, the driver exports one + DIMM per csrow. + + Currently, it also exports the several memory controllers as just one. This + limit will be removed on future versions of the driver. + +2) Nehalem MC has the hability to generate errors. The driver implements this + functionality via some error injection nodes: + + For injecting a memory error, there are some sysfs nodes, under + /sys/devices/system/edac/mc/mc0/: + + inject_addrmatch: + Controls the error injection mask register. It is possible to specify + several characteristics of the address to match an error code: + dimm = the affected dimm. Numbers are relative to a channel; + rank = the memory rank; + channel = the channel that will generate an error; + bank = the affected bank; + page = the page address; + column (or col) = the address column. + each of the above values can be set to "any" to match any valid value. + + At driver init, all values are set to any. + + For example, to generate an error at rank 1 of dimm 2, for any channel, + any bank, any page, any column: + echo "dimm:2 rank:1" >/sys/devices/system/edac/mc/mc0/inject_addrmatch + + To return to the default behaviour of matching any, you can do: + echo "dimm:any rank:any" >/sys/devices/system/edac/mc/mc0/inject_addrmatch + + inject_eccmask: + specifies what bits will have troubles, + + inject_section: + specifies what ECC cache section will get the error: + 3 for both + 2 for the highest + 1 for the lowest + + inject_socket: + specifies what QPI (or processor socket) will generate the error. + on Xeon 35xx, it should be 0. + on Xeon 55xx, it should be 0 or 1. + + inject_type: + specifies the type of error, being a combination of the following bits: + bit 0 - repeat + bit 1 - ecc + bit 2 - parity + + inject_enable starts the error generation when something different + than 0 is written. + + All inject vars can be read. root permission is needed for write. + + Datasheet states that the error will only be generated after a write on an + address that matches inject_addrmatch. It seems, however, that reading will + also produce an error. + + For example, the following code will generate an error for any write access + at socket 0, on any DIMM/address on channel 2: + + echo "channel:2" > /sys/devices/system/edac/mc/mc0/inject_addrmatch + echo 2 >/sys/devices/system/edac/mc/mc0/inject_type + echo 64 >/sys/devices/system/edac/mc/mc0/inject_eccmask + echo 3 >/sys/devices/system/edac/mc/mc0/inject_section + echo 0 >/sys/devices/system/edac/mc/mc0/inject_socket + echo 1 >/sys/devices/system/edac/mc/mc0/inject_enable + dd if=/dev/mem of=/dev/null seek=16k bs=4k count=1 >& /dev/null + + The generated error message will look like: + + EDAC MC0: UE row 0, channel-a= 0 channel-b= 0 labels "-": NON_FATAL (addr = 0x0075b980, socket=0, Dimm=0, Channel=2, syndrome=0x00000040, count=1, Err=8c0000400001009f:4000080482 (read error: read ECC error)) + +3) Nehalem specific Corrected Error memory counters + + Nehalem have some registers to count memory errors, reporting it on a + way that it is different from what EDAC API allows. Due to that, a + separate sysfs note were created to handle such counters. + + They can be read by looking at the contents of "corrected_error_counts" + counter: + + $ cat /sys/devices/system/edac/mc/mc0/corrected_error_counts + dimm0: 15866 + dimm1: 0 + dimm2: 27285 -- GitLab From b990538a78ea84e89551ccaddf182beb5e16e6d2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 5 Aug 2009 21:36:35 -0300 Subject: [PATCH 122/842] i7core_edac: CodingSyle fixes/cleanups No functional changes. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 50 ++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index f16aac253654..86037a601b54 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -38,10 +38,6 @@ #define I7CORE_REVISION " Ver: 1.0.0 " __DATE__ #define EDAC_MOD_STR "i7core_edac" -/* HACK: temporary, just to enable all logs, for now */ -#undef debugf0 -#define debugf0(fmt, arg...) edac_printk(KERN_INFO, "i7core", fmt, ##arg) - /* * Debug macros */ @@ -105,6 +101,7 @@ #define REPEAT_EN 0x01 /* OFFSETS for Devices 4,5 and 6 Function 1 */ + #define MC_DOD_CH_DIMM0 0x48 #define MC_DOD_CH_DIMM1 0x4c #define MC_DOD_CH_DIMM2 0x50 @@ -227,7 +224,7 @@ struct pci_id_descr pci_devs[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, - { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM is supported */ + { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM */ { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, /* Channel 0 */ @@ -878,7 +875,7 @@ static int write_and_test(struct pci_dev *dev, int where, u32 val) for (count = 0; count < 10; count++) { if (count) - msleep (100); + msleep(100); pci_write_config_dword(dev, where, val); pci_read_config_dword(dev, where, &read); @@ -894,7 +891,6 @@ static int write_and_test(struct pci_dev *dev, int where, u32 val) return -EINVAL; } - /* * This routine prepares the Memory Controller for error injection. * The error will be injected when some process tries to write to the @@ -1326,7 +1322,7 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) int new0, new1, new2; if (!pvt->pci_mcr[socket][4]) { - debugf0("%s MCR registers not found\n",__func__); + debugf0("%s MCR registers not found\n", __func__); return; } @@ -1405,24 +1401,24 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, type = "NON_FATAL"; switch (optypenum) { - case 0: - optype = "generic undef request"; - break; - case 1: - optype = "read error"; - break; - case 2: - optype = "write error"; - break; - case 3: - optype = "addr/cmd error"; - break; - case 4: - optype = "scrubbing error"; - break; - default: - optype = "reserved"; - break; + case 0: + optype = "generic undef request"; + break; + case 1: + optype = "read error"; + break; + case 2: + optype = "write error"; + break; + case 3: + optype = "addr/cmd error"; + break; + case 4: + optype = "scrubbing error"; + break; + default: + optype = "reserved"; + break; } switch (errnum) { @@ -1672,7 +1668,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, spin_lock_init(&pvt->mce_lock); rc = edac_mce_register(&pvt->edac_mce); - if (unlikely (rc < 0)) { + if (unlikely(rc < 0)) { debugf0("MC: " __FILE__ ": %s(): failed edac_mce_register()\n", __func__); goto fail1; -- GitLab From 3ef288a98307adc9d3f83321b26281567f348ec6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 2 Sep 2009 23:43:33 -0300 Subject: [PATCH 123/842] i7core_edac: Print an error message if pci register fails Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 86037a601b54..26205e2efecf 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1743,7 +1743,13 @@ static int __init i7core_init(void) pci_rc = pci_register_driver(&i7core_driver); - return (pci_rc < 0) ? pci_rc : 0; + if (pci_rc >= 0) + return 0; + + i7core_printk(KERN_ERR, "Failed to register device with error %d.\n", + pci_rc); + + return pci_rc; } /* -- GitLab From 61053fdedb2080dadc18dc37abbba90d2e74bc03 Mon Sep 17 00:00:00 2001 From: Keith Mannthey <kmannth@us.ibm.com> Date: Wed, 2 Sep 2009 23:46:59 -0300 Subject: [PATCH 124/842] i7core_edac: Fix ecc enable shift From: Keith Mannthey <kmannth@us.ibm.com> Simple correction to a shift value. ECC_ENABLED is bit 4 of MC_STATUS, Dev 3 Fun 0 Offset 0x4c This correctly identifies the state of the ECC at the machine. Signed-off-by: Keith Mannthey <kmannth@us.ibm.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 26205e2efecf..87d5695f5fb0 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -286,7 +286,7 @@ static struct edac_pci_ctl_info *i7core_pci; #define ECCx8(pvt) ((pvt)->info.mc_control & (1 << 1)) /* MC_STATUS bits */ -#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & (1 << 3)) +#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & (1 << 4)) #define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch)) /* MC_MAX_DOD read functions */ -- GitLab From b4e8f0b6eaa1e99f1a64e539466a8ee2fb521d62 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 2 Sep 2009 23:49:59 -0300 Subject: [PATCH 125/842] i7core_edac: Use Device 3 function 2 to report errors with RDIMM's Nehalem and upper chipsets provide an special device that has corrected memory error counters detected with registered dimms. This device is only seen if there are registered memories plugged. After this patch, on a machine fully equiped with RDIMM's, it will use the Device 3 function 2 to count corrected errors instead on relying at mcelog. For unregistered DIMMs, it will keep the old behavior, counting errors via mcelog. This patch were developed together with Keith Mannthey <kmannth@us.ibm.com> Signed-off-by: Keith Mannthey <kmannth@us.ibm.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 208 +++++++++++++++++++++++++++++++------ 1 file changed, 178 insertions(+), 30 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 87d5695f5fb0..4758c208f39a 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -73,6 +73,18 @@ #define DIMM1_COR_ERR(r) (((r) >> 16) & 0x7fff) #define DIMM0_COR_ERR(r) ((r) & 0x7fff) +/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */ +#define MC_COR_ECC_CNT_0 0x80 +#define MC_COR_ECC_CNT_1 0x84 +#define MC_COR_ECC_CNT_2 0x88 +#define MC_COR_ECC_CNT_3 0x8c +#define MC_COR_ECC_CNT_4 0x90 +#define MC_COR_ECC_CNT_5 0x94 + +#define DIMM_TOP_COR_ERR(r) (((r) >> 16) & 0x7fff) +#define DIMM_BOT_COR_ERR(r) ((r) & 0x7fff) + + /* OFFSETS for Devices 4,5 and 6 Function 0 */ #define MC_CHANNEL_DIMM_INIT_PARAMS 0x58 @@ -194,13 +206,20 @@ struct i7core_pvt { struct i7core_inject inject; struct i7core_channel channel[NUM_SOCKETS][NUM_CHANS]; + unsigned int is_registered:1; /* true if all memories are RDIMMs */ + int sockets; /* Number of sockets */ int channels; /* Number of active channels */ int ce_count_available[NUM_SOCKETS]; - /* ECC corrected errors counts per dimm */ - unsigned long ce_count[NUM_SOCKETS][MAX_DIMMS]; - int last_ce_count[NUM_SOCKETS][MAX_DIMMS]; + int csrow_map[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; + + /* ECC corrected errors counts per udimm */ + unsigned long udimm_ce_count[NUM_SOCKETS][MAX_DIMMS]; + int udimm_last_ce_count[NUM_SOCKETS][MAX_DIMMS]; + /* ECC corrected errors counts per rdimm */ + unsigned long rdimm_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; + int rdimm_last_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; /* mcelog glue */ struct edac_mce edac_mce; @@ -471,6 +490,8 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) numrow(pvt->info.max_dod >> 6), numcol(pvt->info.max_dod >> 9)); + pvt->is_registered = 1; + for (i = 0; i < NUM_CHANS; i++) { u32 data, dimm_dod[3], value[8]; @@ -492,8 +513,14 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) if (data & REGISTERED_DIMM) mtype = MEM_RDDR3; - else + else { mtype = MEM_DDR3; + /* + * FIXME: Currently, the driver will use dev 3:2 + * counter registers only if all memories are registered + */ + pvt->is_registered = 0; + } #if 0 if (data & THREE_DIMMS_PRESENT) pvt->channel[i].dimms = 3; @@ -562,6 +589,8 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) csr->channels[0].chan_idx = i; csr->channels[0].ce_count = 0; + pvt->csrow_map[socket][i][j] = *csrow; + switch (banks) { case 4: csr->dtype = DEV_X4; @@ -1031,19 +1060,31 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) { - unsigned i, count, total = 0; + unsigned i, j, count, total = 0; struct i7core_pvt *pvt = mci->pvt_info; for (i = 0; i < pvt->sockets; i++) { - if (!pvt->ce_count_available[i]) + if (!pvt->ce_count_available[i]) { count = sprintf(data, "socket 0 data unavailable\n"); - else + continue; + } + if (!pvt->is_registered) count = sprintf(data, "socket %d, dimm0: %lu\n" "dimm1: %lu\ndimm2: %lu\n", i, - pvt->ce_count[i][0], - pvt->ce_count[i][1], - pvt->ce_count[i][2]); + pvt->udimm_ce_count[i][0], + pvt->udimm_ce_count[i][1], + pvt->udimm_ce_count[i][2]); + else + for (j = 0; j < NUM_CHANS; j++) { + count = sprintf(data, "socket %d, channel %d" + "dimm0: %lu\n" + "dimm1: %lu\ndimm2: %lu\n", + i, j, + pvt->rdimm_ce_count[i][j][0], + pvt->rdimm_ce_count[i][j][1], + pvt->rdimm_ce_count[i][j][2]); + } data += count; total += count; } @@ -1308,6 +1349,103 @@ error: /**************************************************************************** Error check routines ****************************************************************************/ +static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, int socket, + int chan, int dimm, int add) +{ + char *msg; + struct i7core_pvt *pvt = mci->pvt_info; + int row = pvt->csrow_map[socket][chan][dimm], i; + + for (i = 0; i < add; i++) { + msg = kasprintf(GFP_KERNEL, "Corrected error " + "(Socket=%d channel=%d dimm=%d", + socket, chan, dimm); + + edac_mc_handle_fbd_ce(mci, row, 0, msg); + kfree (msg); + } +} + +static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci, + int socket, int chan, int new0, int new1, int new2) +{ + struct i7core_pvt *pvt = mci->pvt_info; + int add0 = 0, add1 = 0, add2 = 0; + /* Updates CE counters if it is not the first time here */ + if (pvt->ce_count_available[socket]) { + /* Updates CE counters */ + + add2 = new2 - pvt->rdimm_last_ce_count[socket][chan][2]; + add1 = new1 - pvt->rdimm_last_ce_count[socket][chan][1]; + add0 = new0 - pvt->rdimm_last_ce_count[socket][chan][0]; + + if (add2 < 0) + add2 += 0x7fff; + pvt->rdimm_ce_count[socket][chan][2] += add2; + + if (add1 < 0) + add1 += 0x7fff; + pvt->rdimm_ce_count[socket][chan][1] += add1; + + if (add0 < 0) + add0 += 0x7fff; + pvt->rdimm_ce_count[socket][chan][0] += add0; + } else + pvt->ce_count_available[socket] = 1; + + /* Store the new values */ + pvt->rdimm_last_ce_count[socket][chan][2] = new2; + pvt->rdimm_last_ce_count[socket][chan][1] = new1; + pvt->rdimm_last_ce_count[socket][chan][0] = new0; + + /*updated the edac core */ + if (add0 != 0) + i7core_rdimm_update_csrow(mci, socket, chan, 0, add0); + if (add1 != 0) + i7core_rdimm_update_csrow(mci, socket, chan, 1, add1); + if (add2 != 0) + i7core_rdimm_update_csrow(mci, socket, chan, 2, add2); + +} + +static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) +{ + struct i7core_pvt *pvt = mci->pvt_info; + u32 rcv[3][2]; + int i, new0, new1, new2; + + /*Read DEV 3: FUN 2: MC_COR_ECC_CNT regs directly*/ + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_0, + &rcv[0][0]); + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_1, + &rcv[0][1]); + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_2, + &rcv[1][0]); + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_3, + &rcv[1][1]); + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_4, + &rcv[2][0]); + pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_5, + &rcv[2][1]); + for (i = 0 ; i < 3; i++) { + debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n", + (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]); + /*if the channel has 3 dimms*/ + if (pvt->channel[socket][i].dimms > 2) { + new0 = DIMM_BOT_COR_ERR(rcv[i][0]); + new1 = DIMM_TOP_COR_ERR(rcv[i][0]); + new2 = DIMM_BOT_COR_ERR(rcv[i][1]); + } else { + new0 = DIMM_TOP_COR_ERR(rcv[i][0]) + + DIMM_BOT_COR_ERR(rcv[i][0]); + new1 = DIMM_TOP_COR_ERR(rcv[i][1]) + + DIMM_BOT_COR_ERR(rcv[i][1]); + new2 = 0; + } + + i7core_rdimm_update_ce_count(mci, socket, i, new0, new1, new2); + } +} /* This function is based on the device 3 function 4 registers as described on: * Intel Xeon Processor 5500 Series Datasheet Volume 2 @@ -1315,7 +1453,7 @@ error: * also available at: * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf */ -static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) +static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) { struct i7core_pvt *pvt = mci->pvt_info; u32 rcv1, rcv0; @@ -1326,7 +1464,7 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) return; } - /* Corrected error reads */ + /* Corrected test errors */ pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV1, &rcv1); pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV0, &rcv0); @@ -1335,39 +1473,38 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) new1 = DIMM1_COR_ERR(rcv0); new0 = DIMM0_COR_ERR(rcv0); -#if 0 - debugf2("%s CE rcv1=0x%08x rcv0=0x%08x, %d %d %d\n", - (pvt->ce_count_available ? "UPDATE" : "READ"), - rcv1, rcv0, new0, new1, new2); -#endif - /* Updates CE counters if it is not the first time here */ if (pvt->ce_count_available[socket]) { /* Updates CE counters */ int add0, add1, add2; - add2 = new2 - pvt->last_ce_count[socket][2]; - add1 = new1 - pvt->last_ce_count[socket][1]; - add0 = new0 - pvt->last_ce_count[socket][0]; + add2 = new2 - pvt->udimm_last_ce_count[socket][2]; + add1 = new1 - pvt->udimm_last_ce_count[socket][1]; + add0 = new0 - pvt->udimm_last_ce_count[socket][0]; if (add2 < 0) add2 += 0x7fff; - pvt->ce_count[socket][2] += add2; + pvt->udimm_ce_count[socket][2] += add2; if (add1 < 0) add1 += 0x7fff; - pvt->ce_count[socket][1] += add1; + pvt->udimm_ce_count[socket][1] += add1; if (add0 < 0) add0 += 0x7fff; - pvt->ce_count[socket][0] += add0; + pvt->udimm_ce_count[socket][0] += add0; + + if (add0 | add1 | add2) + i7core_printk(KERN_ERR, "New Corrected error(s): " + "dimm0: +%d, dimm1: +%d, dimm2 +%d\n", + add0, add1, add2); } else pvt->ce_count_available[socket] = 1; /* Store the new values */ - pvt->last_ce_count[socket][2] = new2; - pvt->last_ce_count[socket][1] = new1; - pvt->last_ce_count[socket][0] = new0; + pvt->udimm_last_ce_count[socket][2] = new2; + pvt->udimm_last_ce_count[socket][1] = new1; + pvt->udimm_last_ce_count[socket][0] = new0; } /* @@ -1386,6 +1523,7 @@ static void check_mc_test_err(struct mem_ctl_info *mci, u8 socket) static void i7core_mce_output_error(struct mem_ctl_info *mci, struct mce *m) { + struct i7core_pvt *pvt = mci->pvt_info; char *type, *optype, *err, *msg; unsigned long error = m->status & 0x1ff0000l; u32 optypenum = (m->status >> 4) & 0x07; @@ -1394,6 +1532,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 channel = (m->misc >> 18) & 0x3; u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); + int csrow; if (m->mcgstatus & 1) type = "FATAL"; @@ -1463,9 +1602,15 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, debugf0("%s", msg); + csrow = pvt->csrow_map[m->cpu][channel][dimm]; + /* Call the helper to output message */ - edac_mc_handle_fbd_ue(mci, 0 /* FIXME: should be rank here */, - 0, 0 /* FIXME: should be channel here */, msg); + if (m->mcgstatus & 1) + edac_mc_handle_fbd_ue(mci, csrow, 0, + 0 /* FIXME: should be channel here */, msg); + else if (!pvt->is_registered) + edac_mc_handle_fbd_ce(mci, csrow, + 0 /* FIXME: should be channel here */, msg); kfree(msg); } @@ -1502,7 +1647,10 @@ static void i7core_check_error(struct mem_ctl_info *mci) /* check memory count errors */ for (i = 0; i < pvt->sockets; i++) - check_mc_test_err(mci, i); + if (!pvt->is_registered) + i7core_udimm_check_mc_ecc_err(mci, i); + else + i7core_rdimm_check_mc_ecc_err(mci, i); } /* -- GitLab From 14d2c08343eecd13f6c6ec232c98b16762b97924 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 2 Sep 2009 23:52:36 -0300 Subject: [PATCH 126/842] i7core: Use registered memories per processor Instead of assuming that the entire machine has either registered or unregistered memories, do it at CPU socket based. While here, fix a bug at i7core_mce_output_error(), where the we're using m->cpu directly as if it would represent a socket. Instead, the proper socket_id is given by cpu_data[m->cpu].phys_proc_id. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- --- drivers/edac/i7core_edac.c | 39 ++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 4758c208f39a..9f4e9d7d4dbf 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -29,6 +29,7 @@ #include <linux/mmzone.h> #include <linux/edac_mce.h> #include <linux/spinlock.h> +#include <asm/processor.h> #include "edac_core.h" @@ -206,8 +207,6 @@ struct i7core_pvt { struct i7core_inject inject; struct i7core_channel channel[NUM_SOCKETS][NUM_CHANS]; - unsigned int is_registered:1; /* true if all memories are RDIMMs */ - int sockets; /* Number of sockets */ int channels; /* Number of active channels */ @@ -221,6 +220,8 @@ struct i7core_pvt { unsigned long rdimm_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; int rdimm_last_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; + unsigned int is_registered[NUM_SOCKETS]; + /* mcelog glue */ struct edac_mce edac_mce; struct mce mce_entry[MCE_LOG_LEN]; @@ -490,8 +491,6 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) numrow(pvt->info.max_dod >> 6), numcol(pvt->info.max_dod >> 9)); - pvt->is_registered = 1; - for (i = 0; i < NUM_CHANS; i++) { u32 data, dimm_dod[3], value[8]; @@ -513,14 +512,8 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) if (data & REGISTERED_DIMM) mtype = MEM_RDDR3; - else { + else mtype = MEM_DDR3; - /* - * FIXME: Currently, the driver will use dev 3:2 - * counter registers only if all memories are registered - */ - pvt->is_registered = 0; - } #if 0 if (data & THREE_DIMMS_PRESENT) pvt->channel[i].dimms = 3; @@ -1068,7 +1061,7 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) count = sprintf(data, "socket 0 data unavailable\n"); continue; } - if (!pvt->is_registered) + if (!pvt->is_registered[i]) count = sprintf(data, "socket %d, dimm0: %lu\n" "dimm1: %lu\ndimm2: %lu\n", i, @@ -1310,7 +1303,9 @@ static int mci_bind_devs(struct mem_ctl_info *mci) struct pci_dev *pdev; int i, j, func, slot; + for (i = 0; i < pvt->sockets; i++) { + pvt->is_registered[i] = 0; for (j = 0; j < N_DEVS; j++) { pdev = pci_devs[j].pdev[i]; if (!pdev) @@ -1334,6 +1329,10 @@ static int mci_bind_devs(struct mem_ctl_info *mci) debugf0("Associated fn %d.%d, dev = %p, socket %d\n", PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev, i); + + if (PCI_SLOT(pdev->devfn) == 3 && + PCI_FUNC(pdev->devfn) == 2) + pvt->is_registered[i] = 1; } } @@ -1533,6 +1532,11 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); int csrow; +#ifdef CONFIG_SMP + u32 socket_id = cpu_data[m->cpu].phys_proc_id; +#else + u32 socket_id = 0; +#endif if (m->mcgstatus & 1) type = "FATAL"; @@ -1596,19 +1600,22 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, msg = kasprintf(GFP_ATOMIC, "%s (addr = 0x%08llx, socket=%d, Dimm=%d, Channel=%d, " "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", - type, (long long) m->addr, m->cpu, dimm, channel, + type, (long long) m->addr, socket_id, dimm, channel, syndrome, core_err_cnt, (long long)m->status, (long long)m->misc, optype, err); debugf0("%s", msg); - csrow = pvt->csrow_map[m->cpu][channel][dimm]; + if (socket_id < NUM_SOCKETS) + csrow = pvt->csrow_map[socket_id][channel][dimm]; + else + csrow = -1; /* Call the helper to output message */ if (m->mcgstatus & 1) edac_mc_handle_fbd_ue(mci, csrow, 0, 0 /* FIXME: should be channel here */, msg); - else if (!pvt->is_registered) + else if (!pvt->is_registered[socket_id]) edac_mc_handle_fbd_ce(mci, csrow, 0 /* FIXME: should be channel here */, msg); @@ -1647,7 +1654,7 @@ static void i7core_check_error(struct mem_ctl_info *mci) /* check memory count errors */ for (i = 0; i < pvt->sockets; i++) - if (!pvt->is_registered) + if (!pvt->is_registered[i]) i7core_udimm_check_mc_ecc_err(mci, i); else i7core_rdimm_check_mc_ecc_err(mci, i); -- GitLab From bc2d7245ff1c5466c877a0c32a7ec9563187a032 Mon Sep 17 00:00:00 2001 From: Keith Mannthey <kmannth@us.ibm.com> Date: Thu, 3 Sep 2009 00:05:05 -0300 Subject: [PATCH 127/842] i7core_edac: Probe on Xeons eariler On the Xeon 55XX series cpus the pci deives are not exposed via acpi so we much explicitly probe them to make the usable as a Linux PCI device. This moves the detection of this state to before pci_register_driver is called. Its present position was not working on my systems, the driver would complain about not finding a specific device. This patch allows the driver to load on my systems. Signed-off-by: Keith Mannthey <kmannth@us.ibm.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 9f4e9d7d4dbf..9fe7ec762e68 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1158,6 +1158,23 @@ static void i7core_put_devices(void) pci_dev_put(pci_devs[j].pdev[i]); } +static void i7core_xeon_pci_fixup(void) +{ + struct pci_dev *pdev = NULL; + int i; + /* + * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses + * aren't announced by acpi. So, we need to use a legacy scan probing + * to detect them + */ + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + pci_devs[0].dev_id, NULL); + if (unlikely(!pdev)) { + for (i = 0; i < NUM_SOCKETS; i ++) + pcibios_scan_specific_bus(255-i); + } +} + /* * i7core_get_devices Find and perform 'get' operation on the MCH's * device/functions we want to reference for this driver @@ -1173,19 +1190,6 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id, *prev); - /* - * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses - * aren't announced by acpi. So, we need to use a legacy scan probing - * to detect them - */ - if (unlikely(!pdev && !devno && !prev)) { - pcibios_scan_specific_bus(254); - pcibios_scan_specific_bus(255); - - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_devs[devno].dev_id, *prev); - } - /* * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs * is at addr 8086:2c40, instead of 8086:2c41. So, we need @@ -1896,6 +1900,8 @@ static int __init i7core_init(void) /* Ensure that the OPSTATE is set correctly for POLL or NMI */ opstate_init(); + i7core_xeon_pci_fixup(); + pci_rc = pci_register_driver(&i7core_driver); if (pci_rc >= 0) -- GitLab From 3a3bb4a647db4cb2468641df8da2ee9491784a9a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 3 Sep 2009 20:17:26 -0300 Subject: [PATCH 128/842] i7core_edac: Improve corrected_error_counts output for RDIMM Just cosmetics. instead of showing something like: socket 0, channel 2dimm0: 1 dimm1: 0 dimm2: 0 socket 1, channel 2dimm0: 0 dimm1: 0 dimm2: 0 Show: socket 0, channel 2 RDIMM0: 1 RDIMM1: 0 RDIMM2: 0 socket 0, channel 2 RDIMM0: 0 RDIMM1: 0 RDIMM2: 0 This is more synthetic and easier to parse. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 9fe7ec762e68..76f4e6d973af 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1070,9 +1070,9 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) pvt->udimm_ce_count[i][2]); else for (j = 0; j < NUM_CHANS; j++) { - count = sprintf(data, "socket %d, channel %d" - "dimm0: %lu\n" - "dimm1: %lu\ndimm2: %lu\n", + count = sprintf(data, "socket %d, channel %d " + "RDIMM0: %lu " + "RDIMM1: %lu RDIMM2: %lu\n", i, j, pvt->rdimm_ce_count[i][j][0], pvt->rdimm_ce_count[i][j][1], -- GitLab From a55456f3446d19853af54b64b3840312f46b6ea5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 5 Sep 2009 00:47:21 -0300 Subject: [PATCH 129/842] i7core: temporary workaround to allow it to compile against 2.6.30 Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 76f4e6d973af..af222ffcfdfc 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1536,8 +1536,10 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); int csrow; -#ifdef CONFIG_SMP - u32 socket_id = cpu_data[m->cpu].phys_proc_id; +/* FIXME */ +//#ifdef CONFIG_SMP +#if 0 + u32 socket_id = per_cpu(cpu_data, cpu).phys_proc_id; #else u32 socket_id = 0; #endif -- GitLab From 66607706cee7b6901aa0509198f075859c93ec6a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 5 Sep 2009 00:52:11 -0300 Subject: [PATCH 130/842] Dynamically allocate memory for PCI devices Instead of using a static table assuming always 2 CPU sockets, allocate space dynamically for Nehalem PCI devs. This patch is part of a series of patches that changes i7core_edac to allow more than 2 sockets and to properly report one memory controller per socket. --- drivers/edac/i7core_edac.c | 175 ++++++++++++++++++++++++------------- 1 file changed, 114 insertions(+), 61 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index af222ffcfdfc..7bcb5993b501 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -192,10 +192,9 @@ struct i7core_channel { }; struct pci_id_descr { - int dev; - int func; - int dev_id; - struct pci_dev *pdev[NUM_SOCKETS]; + int dev; + int func; + int dev_id; }; struct i7core_pvt { @@ -229,6 +228,17 @@ struct i7core_pvt { spinlock_t mce_lock; }; +struct i7core_dev { + struct list_head list; + + int socket; + struct pci_dev **pdev; +}; + +/* Static vars */ +static LIST_HEAD(i7core_edac_list); +static DEFINE_MUTEX(i7core_edac_lock); + /* Device name and register DID (Device ID) */ struct i7core_dev_info { const char *ctl_name; /* name for this device */ @@ -240,7 +250,7 @@ struct i7core_dev_info { .func = (function), \ .dev_id = (device_id) -struct pci_id_descr pci_devs[] = { +struct pci_id_descr pci_dev_descr[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, @@ -275,11 +285,10 @@ struct pci_id_descr pci_devs[] = { { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, }; -#define N_DEVS ARRAY_SIZE(pci_devs) +#define N_DEVS ARRAY_SIZE(pci_dev_descr) /* * pci_device_id table for which devices we are looking for - * This should match the first device at pci_devs table */ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)}, @@ -288,7 +297,7 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { /* Table of devices attributes supported by this driver */ -static const struct i7core_dev_info i7core_devs[] = { +static const struct i7core_dev_info i7core_probe_devs[] = { { .ctl_name = "i7 Core", .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR, @@ -347,21 +356,37 @@ static inline int numcol(u32 col) return cols[col & 0x3]; } +static struct i7core_dev *get_i7core_dev(int socket) +{ + struct i7core_dev *i7core_dev; + + list_for_each_entry(i7core_dev, &i7core_edac_list, list) { + if (i7core_dev->socket == socket) + return i7core_dev; + } + + return NULL; +} + /**************************************************************************** Memory check routines ****************************************************************************/ static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, unsigned func) { + struct i7core_dev *i7core_dev = get_i7core_dev(socket); int i; + if (!i7core_dev) + return NULL; + for (i = 0; i < N_DEVS; i++) { - if (!pci_devs[i].pdev[socket]) + if (!i7core_dev->pdev[i]) continue; - if (PCI_SLOT(pci_devs[i].pdev[socket]->devfn) == slot && - PCI_FUNC(pci_devs[i].pdev[socket]->devfn) == func) { - return pci_devs[i].pdev[socket]; + if (PCI_SLOT(i7core_dev->pdev[i]->devfn) == slot && + PCI_FUNC(i7core_dev->pdev[i]->devfn) == func) { + return i7core_dev->pdev[i]; } } @@ -1153,9 +1178,18 @@ static void i7core_put_devices(void) { int i, j; - for (i = 0; i < NUM_SOCKETS; i++) + for (i = 0; i < NUM_SOCKETS; i++) { + struct i7core_dev *i7core_dev = get_i7core_dev(i); + if (!i7core_dev) + continue; + for (j = 0; j < N_DEVS; j++) - pci_dev_put(pci_devs[j].pdev[i]); + pci_dev_put(i7core_dev->pdev[j]); + + list_del(&i7core_dev->list); + kfree(i7core_dev->pdev); + kfree(i7core_dev); + } } static void i7core_xeon_pci_fixup(void) @@ -1168,7 +1202,7 @@ static void i7core_xeon_pci_fixup(void) * to detect them */ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_devs[0].dev_id, NULL); + pci_dev_descr[0].dev_id, NULL); if (unlikely(!pdev)) { for (i = 0; i < NUM_SOCKETS; i ++) pcibios_scan_specific_bus(255-i); @@ -1183,19 +1217,21 @@ static void i7core_xeon_pci_fixup(void) */ int i7core_get_onedevice(struct pci_dev **prev, int devno) { + struct i7core_dev *i7core_dev; + struct pci_dev *pdev = NULL; u8 bus = 0; u8 socket = 0; pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_devs[devno].dev_id, *prev); + pci_dev_descr[devno].dev_id, *prev); /* * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs * is at addr 8086:2c40, instead of 8086:2c41. So, we need * to probe for the alternate address in case of failure */ - if (pci_devs[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev) + if (pci_dev_descr[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, *prev); @@ -1209,15 +1245,15 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) * Dev 3 function 2 only exists on chips with RDIMMs * so, it is ok to not found it */ - if ((pci_devs[devno].dev == 3) && (pci_devs[devno].func == 2)) { + if ((pci_dev_descr[devno].dev == 3) && (pci_dev_descr[devno].func == 2)) { *prev = pdev; return 0; } i7core_printk(KERN_ERR, "Device not found: dev %02x.%d PCI ID %04x:%04x\n", - pci_devs[devno].dev, pci_devs[devno].func, - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + pci_dev_descr[devno].dev, pci_dev_descr[devno].func, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); /* End of list, leave */ return -ENODEV; @@ -1229,37 +1265,40 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) else socket = 255 - bus; - if (socket >= NUM_SOCKETS) { - i7core_printk(KERN_ERR, - "Unexpected socket for " - "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_devs[devno].dev, pci_devs[devno].func, - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); - pci_dev_put(pdev); - return -ENODEV; + i7core_dev = get_i7core_dev(socket); + if (!i7core_dev) { + i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL); + if (!i7core_dev) + return -ENOMEM; + i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * N_DEVS, + GFP_KERNEL); + if (!i7core_dev->pdev) + return -ENOMEM; + i7core_dev->socket = socket; + list_add_tail(&i7core_dev->list, &i7core_edac_list); } - if (pci_devs[devno].pdev[socket]) { + if (i7core_dev->pdev[devno]) { i7core_printk(KERN_ERR, "Duplicated device for " "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_devs[devno].dev, pci_devs[devno].func, - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); pci_dev_put(pdev); return -ENODEV; } - pci_devs[devno].pdev[socket] = pdev; + i7core_dev->pdev[devno] = pdev; /* Sanity check */ - if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[devno].dev || - PCI_FUNC(pdev->devfn) != pci_devs[devno].func)) { + if (unlikely(PCI_SLOT(pdev->devfn) != pci_dev_descr[devno].dev || + PCI_FUNC(pdev->devfn) != pci_dev_descr[devno].func)) { i7core_printk(KERN_ERR, "Device PCI ID %04x:%04x " "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n", - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id, bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - bus, pci_devs[devno].dev, pci_devs[devno].func); + bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func); return -ENODEV; } @@ -1268,27 +1307,29 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) i7core_printk(KERN_ERR, "Couldn't enable " "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_devs[devno].dev, pci_devs[devno].func, - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); return -ENODEV; } i7core_printk(KERN_INFO, "Registered socket %d " "dev %02x:%02x.%d PCI ID %04x:%04x\n", - socket, bus, pci_devs[devno].dev, pci_devs[devno].func, - PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id); + socket, bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); *prev = pdev; return 0; } -static int i7core_get_devices(void) +static int i7core_get_devices(u8 *sockets) { int i; struct pci_dev *pdev = NULL; + struct i7core_dev *i7core_dev = NULL; + *sockets = 0; for (i = 0; i < N_DEVS; i++) { pdev = NULL; do { @@ -1298,6 +1339,12 @@ static int i7core_get_devices(void) } } while (pdev); } + + list_for_each_entry(i7core_dev, &i7core_edac_list, list) { + if (i7core_dev->socket + 1 > *sockets) + *sockets = i7core_dev->socket + 1; + } + return 0; } @@ -1307,11 +1354,15 @@ static int mci_bind_devs(struct mem_ctl_info *mci) struct pci_dev *pdev; int i, j, func, slot; - for (i = 0; i < pvt->sockets; i++) { + struct i7core_dev *i7core_dev = get_i7core_dev(i); + + if (!i7core_dev) + continue; + pvt->is_registered[i] = 0; for (j = 0; j < N_DEVS; j++) { - pdev = pci_devs[j].pdev[i]; + pdev = i7core_dev->pdev[j]; if (!pdev) continue; @@ -1723,20 +1774,17 @@ static int __devinit i7core_probe(struct pci_dev *pdev, int rc, i; u8 sockets; - if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs))) + /* + * FIXME: All memory controllers are allocated at the first pass. + */ + if (unlikely(dev_idx >= 1)) return -EINVAL; /* get the pci devices we want to reserve for our use */ - rc = i7core_get_devices(); + mutex_lock(&i7core_edac_lock); + rc = i7core_get_devices(&sockets); if (unlikely(rc < 0)) - return rc; - - sockets = 1; - for (i = NUM_SOCKETS - 1; i > 0; i--) - if (pci_devs[0].pdev[i]) { - sockets = i + 1; - break; - } + goto fail0; for (i = 0; i < sockets; i++) { int channels; @@ -1745,7 +1793,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* Check the number of active and not disabled channels */ rc = i7core_get_active_channels(i, &channels, &csrows); if (unlikely(rc < 0)) - goto fail0; + goto fail1; num_channels += channels; num_csrows += csrows; @@ -1755,7 +1803,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); if (unlikely(!mci)) { rc = -ENOMEM; - goto fail0; + goto fail1; } debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); @@ -1776,7 +1824,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->edac_cap = EDAC_FLAG_NONE; mci->mod_name = "i7core_edac.c"; mci->mod_ver = I7CORE_REVISION; - mci->ctl_name = i7core_devs[dev_idx].ctl_name; + mci->ctl_name = i7core_probe_devs[dev_idx].ctl_name; mci->dev_name = pci_name(pdev); mci->ctl_page_to_phys = NULL; mci->mc_driver_sysfs_attributes = i7core_inj_attrs; @@ -1786,7 +1834,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* Store pci devices at mci for faster access */ rc = mci_bind_devs(mci); if (unlikely(rc < 0)) - goto fail1; + goto fail2; /* Get dimm basic config */ for (i = 0; i < sockets; i++) @@ -1801,7 +1849,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, */ rc = -EINVAL; - goto fail1; + goto fail2; } /* allocating generic PCI control info */ @@ -1832,18 +1880,21 @@ static int __devinit i7core_probe(struct pci_dev *pdev, if (unlikely(rc < 0)) { debugf0("MC: " __FILE__ ": %s(): failed edac_mce_register()\n", __func__); - goto fail1; + goto fail2; } i7core_printk(KERN_INFO, "Driver loaded.\n"); + mutex_unlock(&i7core_edac_lock); return 0; -fail1: +fail2: edac_mc_free(mci); -fail0: +fail1: i7core_put_devices(); +fail0: + mutex_unlock(&i7core_edac_lock); return rc; } @@ -1871,7 +1922,9 @@ static void __devexit i7core_remove(struct pci_dev *pdev) edac_mce_unregister(&pvt->edac_mce); /* retrieve references to resources, and free those resources */ + mutex_lock(&i7core_edac_lock); i7core_put_devices(); + mutex_unlock(&i7core_edac_lock); edac_mc_free(mci); } -- GitLab From f47429494fd50c0b7396fe3f8a26ea638b47c5ba Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 5 Sep 2009 02:35:08 -0300 Subject: [PATCH 131/842] i7core_edac: create one mc per socket/QPI Instead of creating just one memory controller, create one per socket (e. g. per Quick Link Path Interconnect). This better reflects the Nehalem architecture. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 507 +++++++++++++++++-------------------- 1 file changed, 228 insertions(+), 279 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 7bcb5993b501..5bc316b8e805 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -29,10 +29,20 @@ #include <linux/mmzone.h> #include <linux/edac_mce.h> #include <linux/spinlock.h> +#include <linux/smp.h> #include <asm/processor.h> #include "edac_core.h" +/* + * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core + * registers start at bus 255, and are not reported by BIOS. + * We currently find devices with only 2 sockets. In order to support more QPI + * Quick Path Interconnect, just increment this number. + */ +#define MAX_SOCKET_BUSES 2 + + /* * Alter this version for the module when modifications are made */ @@ -162,7 +172,6 @@ #define NUM_CHANS 3 #define MAX_DIMMS 3 /* Max DIMMS per channel */ -#define NUM_SOCKETS 2 /* Max number of MC sockets */ #define MAX_MCR_FUNC 4 #define MAX_CHAN_FUNC 3 @@ -177,7 +186,6 @@ struct i7core_info { struct i7core_inject { int enable; - u8 socket; u32 section; u32 type; u32 eccmask; @@ -197,29 +205,37 @@ struct pci_id_descr { int dev_id; }; +struct i7core_dev { + struct list_head list; + u8 socket; + struct pci_dev **pdev; + struct mem_ctl_info *mci; +}; + struct i7core_pvt { - struct pci_dev *pci_noncore[NUM_SOCKETS]; - struct pci_dev *pci_mcr[NUM_SOCKETS][MAX_MCR_FUNC + 1]; - struct pci_dev *pci_ch[NUM_SOCKETS][NUM_CHANS][MAX_CHAN_FUNC + 1]; + struct pci_dev *pci_noncore; + struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1]; + struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1]; + + struct i7core_dev *i7core_dev; struct i7core_info info; struct i7core_inject inject; - struct i7core_channel channel[NUM_SOCKETS][NUM_CHANS]; + struct i7core_channel channel[NUM_CHANS]; - int sockets; /* Number of sockets */ - int channels; /* Number of active channels */ + int channels; /* Number of active channels */ - int ce_count_available[NUM_SOCKETS]; - int csrow_map[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; + int ce_count_available; + int csrow_map[NUM_CHANS][MAX_DIMMS]; /* ECC corrected errors counts per udimm */ - unsigned long udimm_ce_count[NUM_SOCKETS][MAX_DIMMS]; - int udimm_last_ce_count[NUM_SOCKETS][MAX_DIMMS]; + unsigned long udimm_ce_count[MAX_DIMMS]; + int udimm_last_ce_count[MAX_DIMMS]; /* ECC corrected errors counts per rdimm */ - unsigned long rdimm_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; - int rdimm_last_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; + unsigned long rdimm_ce_count[NUM_CHANS][MAX_DIMMS]; + int rdimm_last_ce_count[NUM_CHANS][MAX_DIMMS]; - unsigned int is_registered[NUM_SOCKETS]; + unsigned int is_registered; /* mcelog glue */ struct edac_mce edac_mce; @@ -228,22 +244,10 @@ struct i7core_pvt { spinlock_t mce_lock; }; -struct i7core_dev { - struct list_head list; - - int socket; - struct pci_dev **pdev; -}; - /* Static vars */ static LIST_HEAD(i7core_edac_list); static DEFINE_MUTEX(i7core_edac_lock); - -/* Device name and register DID (Device ID) */ -struct i7core_dev_info { - const char *ctl_name; /* name for this device */ - u16 fsb_mapping_errors; /* DID for the branchmap,control */ -}; +static u8 max_num_sockets; #define PCI_DESCR(device, function, device_id) \ .dev = (device), \ @@ -295,15 +299,6 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { {0,} /* 0 terminated list. */ }; - -/* Table of devices attributes supported by this driver */ -static const struct i7core_dev_info i7core_probe_devs[] = { - { - .ctl_name = "i7 Core", - .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR, - }, -}; - static struct edac_pci_ctl_info *i7core_pci; /**************************************************************************** @@ -356,7 +351,7 @@ static inline int numcol(u32 col) return cols[col & 0x3]; } -static struct i7core_dev *get_i7core_dev(int socket) +static struct i7core_dev *get_i7core_dev(u8 socket) { struct i7core_dev *i7core_dev; @@ -471,18 +466,19 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels, return 0; } -static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) +static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; struct pci_dev *pdev; int i, j; + u8 socket = pvt->i7core_dev->socket; unsigned long last_page = 0; enum edac_type mode; enum mem_type mtype; /* Get data from the MC register, function 0 */ - pdev = pvt->pci_mcr[socket][0]; + pdev = pvt->pci_mcr[0]; if (!pdev) return -ENODEV; @@ -529,10 +525,10 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) } /* Devices 4-6 function 0 */ - pci_read_config_dword(pvt->pci_ch[socket][i][0], + pci_read_config_dword(pvt->pci_ch[i][0], MC_CHANNEL_DIMM_INIT_PARAMS, &data); - pvt->channel[socket][i].ranks = (data & QUAD_RANK_PRESENT) ? + pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ? 4 : 2; if (data & REGISTERED_DIMM) @@ -549,11 +545,11 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) #endif /* Devices 4-6 function 1 */ - pci_read_config_dword(pvt->pci_ch[socket][i][1], + pci_read_config_dword(pvt->pci_ch[i][1], MC_DOD_CH_DIMM0, &dimm_dod[0]); - pci_read_config_dword(pvt->pci_ch[socket][i][1], + pci_read_config_dword(pvt->pci_ch[i][1], MC_DOD_CH_DIMM1, &dimm_dod[1]); - pci_read_config_dword(pvt->pci_ch[socket][i][1], + pci_read_config_dword(pvt->pci_ch[i][1], MC_DOD_CH_DIMM2, &dimm_dod[2]); debugf0("Ch%d phy rd%d, wr%d (0x%08x): " @@ -561,7 +557,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) i, RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, - pvt->channel[socket][i].ranks, + pvt->channel[i].ranks, (data & REGISTERED_DIMM) ? 'R' : 'U'); for (j = 0; j < 3; j++) { @@ -579,7 +575,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) /* DDR3 has 8 I/O banks */ size = (rows * cols * banks * ranks) >> (20 - 3); - pvt->channel[socket][i].dimms++; + pvt->channel[i].dimms++; debugf0("\tdimm %d %d Mb offset: %x, " "bank: %d, rank: %d, row: %#x, col: %#x\n", @@ -607,7 +603,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) csr->channels[0].chan_idx = i; csr->channels[0].ce_count = 0; - pvt->csrow_map[socket][i][j] = *csrow; + pvt->csrow_map[i][j] = *csrow; switch (banks) { case 4: @@ -665,42 +661,15 @@ static int disable_inject(struct mem_ctl_info *mci) pvt->inject.enable = 0; - if (!pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0]) + if (!pvt->pci_ch[pvt->inject.channel][0]) return -ENODEV; - pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_INJECT, 0); return 0; } -/* - * i7core inject inject.socket - * - * accept and store error injection inject.socket value - */ -static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, - const char *data, size_t count) -{ - struct i7core_pvt *pvt = mci->pvt_info; - unsigned long value; - int rc; - - rc = strict_strtoul(data, 10, &value); - if ((rc < 0) || (value >= pvt->sockets)) - return -EIO; - - pvt->inject.socket = (u32) value; - return count; -} - -static ssize_t i7core_inject_socket_show(struct mem_ctl_info *mci, - char *data) -{ - struct i7core_pvt *pvt = mci->pvt_info; - return sprintf(data, "%d\n", pvt->inject.socket); -} - /* * i7core inject inject.section * @@ -965,7 +934,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, int rc; long enable; - if (!pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0]) + if (!pvt->pci_ch[pvt->inject.channel][0]) return 0; rc = strict_strtoul(data, 10, &enable); @@ -983,7 +952,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.dimm < 0) mask |= 1L << 41; else { - if (pvt->channel[pvt->inject.socket][pvt->inject.channel].dimms > 2) + if (pvt->channel[pvt->inject.channel].dimms > 2) mask |= (pvt->inject.dimm & 0x3L) << 35; else mask |= (pvt->inject.dimm & 0x1L) << 36; @@ -993,7 +962,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, if (pvt->inject.rank < 0) mask |= 1L << 40; else { - if (pvt->channel[pvt->inject.socket][pvt->inject.channel].dimms > 2) + if (pvt->channel[pvt->inject.channel].dimms > 2) mask |= (pvt->inject.rank & 0x1L) << 34; else mask |= (pvt->inject.rank & 0x3L) << 34; @@ -1029,18 +998,18 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, (pvt->inject.type & 0x6) << (3 - 1); /* Unlock writes to registers - this register is write only */ - pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 0x2); - write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH, mask); - write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L); - write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); - write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + write_and_test(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_INJECT, injectmask); /* @@ -1048,7 +1017,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, * Without writing 8 to this register, errors aren't injected. Not sure * why. */ - pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, 8); debugf0("Error inject addr match 0x%016llx, ecc 0x%08x," @@ -1065,7 +1034,7 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, struct i7core_pvt *pvt = mci->pvt_info; u32 injectmask; - pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], + pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_INJECT, &injectmask); debugf0("Inject error read: 0x%018x\n", injectmask); @@ -1078,34 +1047,30 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) { - unsigned i, j, count, total = 0; + unsigned i, count, total = 0; struct i7core_pvt *pvt = mci->pvt_info; - for (i = 0; i < pvt->sockets; i++) { - if (!pvt->ce_count_available[i]) { - count = sprintf(data, "socket 0 data unavailable\n"); - continue; - } - if (!pvt->is_registered[i]) - count = sprintf(data, "socket %d, dimm0: %lu\n" - "dimm1: %lu\ndimm2: %lu\n", - i, - pvt->udimm_ce_count[i][0], - pvt->udimm_ce_count[i][1], - pvt->udimm_ce_count[i][2]); - else - for (j = 0; j < NUM_CHANS; j++) { - count = sprintf(data, "socket %d, channel %d " - "RDIMM0: %lu " - "RDIMM1: %lu RDIMM2: %lu\n", - i, j, - pvt->rdimm_ce_count[i][j][0], - pvt->rdimm_ce_count[i][j][1], - pvt->rdimm_ce_count[i][j][2]); - } - data += count; - total += count; + if (!pvt->ce_count_available) { + count = sprintf(data, "data unavailable\n"); + return 0; } + if (!pvt->is_registered) + count = sprintf(data, "all channels " + "UDIMM0: %lu UDIMM1: %lu UDIMM2: %lu\n", + pvt->udimm_ce_count[0], + pvt->udimm_ce_count[1], + pvt->udimm_ce_count[2]); + else + for (i = 0; i < NUM_CHANS; i++) { + count = sprintf(data, "channel %d RDIMM0: %lu " + "RDIMM1: %lu RDIMM2: %lu\n", + i, + pvt->rdimm_ce_count[i][0], + pvt->rdimm_ce_count[i][1], + pvt->rdimm_ce_count[i][2]); + } + data += count; + total += count; return total; } @@ -1115,13 +1080,6 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) */ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { { - .attr = { - .name = "inject_socket", - .mode = (S_IRUGO | S_IWUSR) - }, - .show = i7core_inject_socket_show, - .store = i7core_inject_socket_store, - }, { .attr = { .name = "inject_section", .mode = (S_IRUGO | S_IWUSR) @@ -1178,7 +1136,7 @@ static void i7core_put_devices(void) { int i, j; - for (i = 0; i < NUM_SOCKETS; i++) { + for (i = 0; i < max_num_sockets; i++) { struct i7core_dev *i7core_dev = get_i7core_dev(i); if (!i7core_dev) continue; @@ -1204,7 +1162,7 @@ static void i7core_xeon_pci_fixup(void) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, pci_dev_descr[0].dev_id, NULL); if (unlikely(!pdev)) { - for (i = 0; i < NUM_SOCKETS; i ++) + for (i = 0; i < MAX_SOCKET_BUSES; i++) pcibios_scan_specific_bus(255-i); } } @@ -1323,13 +1281,11 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) return 0; } -static int i7core_get_devices(u8 *sockets) +static int i7core_get_devices(void) { int i; struct pci_dev *pdev = NULL; - struct i7core_dev *i7core_dev = NULL; - *sockets = 0; for (i = 0; i < N_DEVS; i++) { pdev = NULL; do { @@ -1340,55 +1296,48 @@ static int i7core_get_devices(u8 *sockets) } while (pdev); } - list_for_each_entry(i7core_dev, &i7core_edac_list, list) { - if (i7core_dev->socket + 1 > *sockets) - *sockets = i7core_dev->socket + 1; - } - return 0; } -static int mci_bind_devs(struct mem_ctl_info *mci) +static int mci_bind_devs(struct mem_ctl_info *mci, + struct i7core_dev *i7core_dev) { struct i7core_pvt *pvt = mci->pvt_info; struct pci_dev *pdev; - int i, j, func, slot; + int i, func, slot; - for (i = 0; i < pvt->sockets; i++) { - struct i7core_dev *i7core_dev = get_i7core_dev(i); + /* Associates i7core_dev and mci for future usage */ + pvt->i7core_dev = i7core_dev; + i7core_dev->mci = mci; - if (!i7core_dev) + pvt->is_registered = 0; + for (i = 0; i < N_DEVS; i++) { + pdev = i7core_dev->pdev[i]; + if (!pdev) continue; - pvt->is_registered[i] = 0; - for (j = 0; j < N_DEVS; j++) { - pdev = i7core_dev->pdev[j]; - if (!pdev) - continue; - - func = PCI_FUNC(pdev->devfn); - slot = PCI_SLOT(pdev->devfn); - if (slot == 3) { - if (unlikely(func > MAX_MCR_FUNC)) - goto error; - pvt->pci_mcr[i][func] = pdev; - } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { - if (unlikely(func > MAX_CHAN_FUNC)) - goto error; - pvt->pci_ch[i][slot - 4][func] = pdev; - } else if (!slot && !func) - pvt->pci_noncore[i] = pdev; - else + func = PCI_FUNC(pdev->devfn); + slot = PCI_SLOT(pdev->devfn); + if (slot == 3) { + if (unlikely(func > MAX_MCR_FUNC)) + goto error; + pvt->pci_mcr[func] = pdev; + } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { + if (unlikely(func > MAX_CHAN_FUNC)) goto error; + pvt->pci_ch[slot - 4][func] = pdev; + } else if (!slot && !func) + pvt->pci_noncore = pdev; + else + goto error; - debugf0("Associated fn %d.%d, dev = %p, socket %d\n", - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - pdev, i); + debugf0("Associated fn %d.%d, dev = %p, socket %d\n", + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + pdev, i7core_dev->socket); - if (PCI_SLOT(pdev->devfn) == 3 && - PCI_FUNC(pdev->devfn) == 2) - pvt->is_registered[i] = 1; - } + if (PCI_SLOT(pdev->devfn) == 3 && + PCI_FUNC(pdev->devfn) == 2) + pvt->is_registered = 1; } return 0; @@ -1403,17 +1352,17 @@ error: /**************************************************************************** Error check routines ****************************************************************************/ -static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, int socket, +static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, int chan, int dimm, int add) { char *msg; struct i7core_pvt *pvt = mci->pvt_info; - int row = pvt->csrow_map[socket][chan][dimm], i; + int row = pvt->csrow_map[chan][dimm], i; for (i = 0; i < add; i++) { msg = kasprintf(GFP_KERNEL, "Corrected error " - "(Socket=%d channel=%d dimm=%d", - socket, chan, dimm); + "(Socket=%d channel=%d dimm=%d)", + pvt->i7core_dev->socket, chan, dimm); edac_mc_handle_fbd_ce(mci, row, 0, msg); kfree (msg); @@ -1421,71 +1370,71 @@ static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, int socket, } static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci, - int socket, int chan, int new0, int new1, int new2) + int chan, int new0, int new1, int new2) { struct i7core_pvt *pvt = mci->pvt_info; int add0 = 0, add1 = 0, add2 = 0; /* Updates CE counters if it is not the first time here */ - if (pvt->ce_count_available[socket]) { + if (pvt->ce_count_available) { /* Updates CE counters */ - add2 = new2 - pvt->rdimm_last_ce_count[socket][chan][2]; - add1 = new1 - pvt->rdimm_last_ce_count[socket][chan][1]; - add0 = new0 - pvt->rdimm_last_ce_count[socket][chan][0]; + add2 = new2 - pvt->rdimm_last_ce_count[chan][2]; + add1 = new1 - pvt->rdimm_last_ce_count[chan][1]; + add0 = new0 - pvt->rdimm_last_ce_count[chan][0]; if (add2 < 0) add2 += 0x7fff; - pvt->rdimm_ce_count[socket][chan][2] += add2; + pvt->rdimm_ce_count[chan][2] += add2; if (add1 < 0) add1 += 0x7fff; - pvt->rdimm_ce_count[socket][chan][1] += add1; + pvt->rdimm_ce_count[chan][1] += add1; if (add0 < 0) add0 += 0x7fff; - pvt->rdimm_ce_count[socket][chan][0] += add0; + pvt->rdimm_ce_count[chan][0] += add0; } else - pvt->ce_count_available[socket] = 1; + pvt->ce_count_available = 1; /* Store the new values */ - pvt->rdimm_last_ce_count[socket][chan][2] = new2; - pvt->rdimm_last_ce_count[socket][chan][1] = new1; - pvt->rdimm_last_ce_count[socket][chan][0] = new0; + pvt->rdimm_last_ce_count[chan][2] = new2; + pvt->rdimm_last_ce_count[chan][1] = new1; + pvt->rdimm_last_ce_count[chan][0] = new0; /*updated the edac core */ if (add0 != 0) - i7core_rdimm_update_csrow(mci, socket, chan, 0, add0); + i7core_rdimm_update_csrow(mci, chan, 0, add0); if (add1 != 0) - i7core_rdimm_update_csrow(mci, socket, chan, 1, add1); + i7core_rdimm_update_csrow(mci, chan, 1, add1); if (add2 != 0) - i7core_rdimm_update_csrow(mci, socket, chan, 2, add2); + i7core_rdimm_update_csrow(mci, chan, 2, add2); } -static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) +static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; u32 rcv[3][2]; int i, new0, new1, new2; /*Read DEV 3: FUN 2: MC_COR_ECC_CNT regs directly*/ - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_0, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_0, &rcv[0][0]); - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_1, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_1, &rcv[0][1]); - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_2, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_2, &rcv[1][0]); - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_3, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_3, &rcv[1][1]); - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_4, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_4, &rcv[2][0]); - pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_5, + pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_5, &rcv[2][1]); for (i = 0 ; i < 3; i++) { debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n", (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]); /*if the channel has 3 dimms*/ - if (pvt->channel[socket][i].dimms > 2) { + if (pvt->channel[i].dimms > 2) { new0 = DIMM_BOT_COR_ERR(rcv[i][0]); new1 = DIMM_TOP_COR_ERR(rcv[i][0]); new2 = DIMM_BOT_COR_ERR(rcv[i][1]); @@ -1497,7 +1446,7 @@ static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) new2 = 0; } - i7core_rdimm_update_ce_count(mci, socket, i, new0, new1, new2); + i7core_rdimm_update_ce_count(mci, i, new0, new1, new2); } } @@ -1507,20 +1456,20 @@ static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) * also available at: * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf */ -static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) +static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; u32 rcv1, rcv0; int new0, new1, new2; - if (!pvt->pci_mcr[socket][4]) { + if (!pvt->pci_mcr[4]) { debugf0("%s MCR registers not found\n", __func__); return; } /* Corrected test errors */ - pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV1, &rcv1); - pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV0, &rcv0); + pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1); + pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0); /* Store the new values */ new2 = DIMM2_COR_ERR(rcv1); @@ -1528,37 +1477,37 @@ static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) new0 = DIMM0_COR_ERR(rcv0); /* Updates CE counters if it is not the first time here */ - if (pvt->ce_count_available[socket]) { + if (pvt->ce_count_available) { /* Updates CE counters */ int add0, add1, add2; - add2 = new2 - pvt->udimm_last_ce_count[socket][2]; - add1 = new1 - pvt->udimm_last_ce_count[socket][1]; - add0 = new0 - pvt->udimm_last_ce_count[socket][0]; + add2 = new2 - pvt->udimm_last_ce_count[2]; + add1 = new1 - pvt->udimm_last_ce_count[1]; + add0 = new0 - pvt->udimm_last_ce_count[0]; if (add2 < 0) add2 += 0x7fff; - pvt->udimm_ce_count[socket][2] += add2; + pvt->udimm_ce_count[2] += add2; if (add1 < 0) add1 += 0x7fff; - pvt->udimm_ce_count[socket][1] += add1; + pvt->udimm_ce_count[1] += add1; if (add0 < 0) add0 += 0x7fff; - pvt->udimm_ce_count[socket][0] += add0; + pvt->udimm_ce_count[0] += add0; if (add0 | add1 | add2) i7core_printk(KERN_ERR, "New Corrected error(s): " "dimm0: +%d, dimm1: +%d, dimm2 +%d\n", add0, add1, add2); } else - pvt->ce_count_available[socket] = 1; + pvt->ce_count_available = 1; /* Store the new values */ - pvt->udimm_last_ce_count[socket][2] = new2; - pvt->udimm_last_ce_count[socket][1] = new1; - pvt->udimm_last_ce_count[socket][0] = new0; + pvt->udimm_last_ce_count[2] = new2; + pvt->udimm_last_ce_count[1] = new1; + pvt->udimm_last_ce_count[0] = new0; } /* @@ -1587,13 +1536,6 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); int csrow; -/* FIXME */ -//#ifdef CONFIG_SMP -#if 0 - u32 socket_id = per_cpu(cpu_data, cpu).phys_proc_id; -#else - u32 socket_id = 0; -#endif if (m->mcgstatus & 1) type = "FATAL"; @@ -1655,24 +1597,21 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, /* FIXME: should convert addr into bank and rank information */ msg = kasprintf(GFP_ATOMIC, - "%s (addr = 0x%08llx, socket=%d, Dimm=%d, Channel=%d, " + "%s (addr = 0x%08llx, cpu=%d, Dimm=%d, Channel=%d, " "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", - type, (long long) m->addr, socket_id, dimm, channel, + type, (long long) m->addr, m->cpu, dimm, channel, syndrome, core_err_cnt, (long long)m->status, (long long)m->misc, optype, err); debugf0("%s", msg); - if (socket_id < NUM_SOCKETS) - csrow = pvt->csrow_map[socket_id][channel][dimm]; - else - csrow = -1; + csrow = pvt->csrow_map[channel][dimm]; /* Call the helper to output message */ if (m->mcgstatus & 1) edac_mc_handle_fbd_ue(mci, csrow, 0, 0 /* FIXME: should be channel here */, msg); - else if (!pvt->is_registered[socket_id]) + else if (!pvt->is_registered) edac_mc_handle_fbd_ce(mci, csrow, 0 /* FIXME: should be channel here */, msg); @@ -1695,12 +1634,14 @@ static void i7core_check_error(struct mem_ctl_info *mci) spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count) { m = kmalloc(sizeof(*m) * pvt->mce_count, GFP_ATOMIC); + if (m) { count = pvt->mce_count; memcpy(m, &pvt->mce_entry, sizeof(*m) * count); } pvt->mce_count = 0; } + spin_unlock_irqrestore(&pvt->mce_lock, flags); /* proccess mcelog errors */ @@ -1710,11 +1651,10 @@ static void i7core_check_error(struct mem_ctl_info *mci) kfree(m); /* check memory count errors */ - for (i = 0; i < pvt->sockets; i++) - if (!pvt->is_registered[i]) - i7core_udimm_check_mc_ecc_err(mci, i); - else - i7core_rdimm_check_mc_ecc_err(mci, i); + if (!pvt->is_registered) + i7core_udimm_check_mc_ecc_err(mci); + else + i7core_rdimm_check_mc_ecc_err(mci); } /* @@ -1740,6 +1680,10 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) if (mce->bank != 8) return 0; + /* Only handle if it is the right mc controller */ + if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) + return 0; + spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count < MCE_LOG_LEN) { memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); @@ -1755,63 +1699,26 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 1; } -/* - * i7core_probe Probe for ONE instance of device to see if it is - * present. - * return: - * 0 for FOUND a device - * < 0 for error code - */ -static int __devinit i7core_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +static int i7core_register_mci(struct i7core_dev *i7core_dev, + int num_channels, int num_csrows) { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int num_channels = 0; - int num_csrows = 0; int csrow = 0; - int dev_idx = id->driver_data; - int rc, i; - u8 sockets; - - /* - * FIXME: All memory controllers are allocated at the first pass. - */ - if (unlikely(dev_idx >= 1)) - return -EINVAL; - - /* get the pci devices we want to reserve for our use */ - mutex_lock(&i7core_edac_lock); - rc = i7core_get_devices(&sockets); - if (unlikely(rc < 0)) - goto fail0; - - for (i = 0; i < sockets; i++) { - int channels; - int csrows; - - /* Check the number of active and not disabled channels */ - rc = i7core_get_active_channels(i, &channels, &csrows); - if (unlikely(rc < 0)) - goto fail1; - - num_channels += channels; - num_csrows += csrows; - } + int rc; /* allocate a new MC control structure */ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); - if (unlikely(!mci)) { - rc = -ENOMEM; - goto fail1; - } + if (unlikely(!mci)) + return -ENOMEM; debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); - mci->dev = &pdev->dev; /* record ptr to the generic device */ + /* record ptr to the generic device */ + mci->dev = &i7core_dev->pdev[0]->dev; + pvt = mci->pvt_info; memset(pvt, 0, sizeof(*pvt)); - pvt->sockets = sockets; mci->mc_idx = 0; /* @@ -1824,21 +1731,21 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mci->edac_cap = EDAC_FLAG_NONE; mci->mod_name = "i7core_edac.c"; mci->mod_ver = I7CORE_REVISION; - mci->ctl_name = i7core_probe_devs[dev_idx].ctl_name; - mci->dev_name = pci_name(pdev); + mci->ctl_name = kasprintf(GFP_KERNEL, "i7 core #%d", + i7core_dev->socket); + mci->dev_name = pci_name(i7core_dev->pdev[0]); mci->ctl_page_to_phys = NULL; mci->mc_driver_sysfs_attributes = i7core_inj_attrs; /* Set the function pointer to an actual operation function */ mci->edac_check = i7core_check_error; /* Store pci devices at mci for faster access */ - rc = mci_bind_devs(mci); + rc = mci_bind_devs(mci, i7core_dev); if (unlikely(rc < 0)) - goto fail2; + goto fail; /* Get dimm basic config */ - for (i = 0; i < sockets; i++) - get_dimm_config(mci, &csrow, i); + get_dimm_config(mci, &csrow); /* add this new MC control structure to EDAC's list of MCs */ if (unlikely(edac_mc_add_mc(mci))) { @@ -1849,11 +1756,12 @@ static int __devinit i7core_probe(struct pci_dev *pdev, */ rc = -EINVAL; - goto fail2; + goto fail; } /* allocating generic PCI control info */ - i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); + i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev, + EDAC_MOD_STR); if (unlikely(!i7core_pci)) { printk(KERN_WARNING "%s(): Unable to create PCI control\n", @@ -1880,7 +1788,50 @@ static int __devinit i7core_probe(struct pci_dev *pdev, if (unlikely(rc < 0)) { debugf0("MC: " __FILE__ ": %s(): failed edac_mce_register()\n", __func__); - goto fail2; + } + +fail: + edac_mc_free(mci); + return rc; +} + +/* + * i7core_probe Probe for ONE instance of device to see if it is + * present. + * return: + * 0 for FOUND a device + * < 0 for error code + */ +static int __devinit i7core_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int dev_idx = id->driver_data; + int rc; + struct i7core_dev *i7core_dev; + + /* + * FIXME: All memory controllers are allocated at the first pass. + */ + if (unlikely(dev_idx >= 1)) + return -EINVAL; + + /* get the pci devices we want to reserve for our use */ + mutex_lock(&i7core_edac_lock); + rc = i7core_get_devices(); + if (unlikely(rc < 0)) + goto fail0; + + list_for_each_entry(i7core_dev, &i7core_edac_list, list) { + int channels; + int csrows; + + /* Check the number of active and not disabled channels */ + rc = i7core_get_active_channels(i7core_dev->socket, + &channels, &csrows); + if (unlikely(rc < 0)) + goto fail1; + + i7core_register_mci(i7core_dev, channels, csrows); } i7core_printk(KERN_INFO, "Driver loaded.\n"); @@ -1888,9 +1839,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, mutex_unlock(&i7core_edac_lock); return 0; -fail2: - edac_mc_free(mci); - fail1: i7core_put_devices(); fail0: @@ -1926,6 +1874,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) i7core_put_devices(); mutex_unlock(&i7core_edac_lock); + kfree(mci->ctl_name); edac_mc_free(mci); } -- GitLab From 6c6aa3afdba2460cb668d4cb65c74dfa8eb43449 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 5 Sep 2009 03:27:04 -0300 Subject: [PATCH 132/842] i7core_edac: sanity check: print a warning if a mcelog is ignored In thesis, the other mc controller should handle it. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 5bc316b8e805..335d9ed02c45 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1681,8 +1681,13 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 0; /* Only handle if it is the right mc controller */ - if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) + if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) { + debugf0("mc%d: ignoring mce log for socket %d. " + "Another mc should get it.\n", + pvt->i7core_dev->socket, + cpu_data(mce->cpu).phys_proc_id); return 0; + } spin_lock_irqsave(&pvt->mce_lock, flags); if (pvt->mce_count < MCE_LOG_LEN) { -- GitLab From d4c277957f4e8e6f2b626e2661cbbf9c76782e36 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 5 Sep 2009 04:12:02 -0300 Subject: [PATCH 133/842] i7core_edac: a few fixes for multiple mc's Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 335d9ed02c45..2c30493eae0f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1270,11 +1270,10 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) return -ENODEV; } - i7core_printk(KERN_INFO, - "Registered socket %d " - "dev %02x:%02x.%d PCI ID %04x:%04x\n", - socket, bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); + debugf0("Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n", + socket, bus, pci_dev_descr[devno].dev, + pci_dev_descr[devno].func, + PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); *prev = pdev; @@ -1713,7 +1712,8 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, int rc; /* allocate a new MC control structure */ - mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); + mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, + i7core_dev->socket); if (unlikely(!mci)) return -ENOMEM; @@ -1724,7 +1724,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, pvt = mci->pvt_info; memset(pvt, 0, sizeof(*pvt)); - mci->mc_idx = 0; /* * FIXME: how to handle RDDR3 at MCI level? It is possible to have @@ -1815,7 +1814,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, struct i7core_dev *i7core_dev; /* - * FIXME: All memory controllers are allocated at the first pass. + * All memory controllers are allocated at the first pass. */ if (unlikely(dev_idx >= 1)) return -EINVAL; @@ -1836,7 +1835,9 @@ static int __devinit i7core_probe(struct pci_dev *pdev, if (unlikely(rc < 0)) goto fail1; - i7core_register_mci(i7core_dev, channels, csrows); + rc = i7core_register_mci(i7core_dev, channels, csrows); + if (unlikely(rc < 0)) + goto fail1; } i7core_printk(KERN_INFO, "Driver loaded.\n"); @@ -1876,6 +1877,8 @@ static void __devexit i7core_remove(struct pci_dev *pdev) /* retrieve references to resources, and free those resources */ mutex_lock(&i7core_edac_lock); + + /* FIXME: This should put the devices only for this mci!!! */ i7core_put_devices(); mutex_unlock(&i7core_edac_lock); -- GitLab From c344436319e898784febbeeea71d1b0f65ef53ae Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 5 Sep 2009 05:10:15 -0300 Subject: [PATCH 134/842] Documentation/edac.txt: Improve it to reflect the latest changes at the driver Signed-off-by: Mauro Carvalho Chehab <mcheahb@redhat.com> --- Documentation/edac.txt | 72 ++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/Documentation/edac.txt b/Documentation/edac.txt index 8bc320467c64..bd3f8a3905af 100644 --- a/Documentation/edac.txt +++ b/Documentation/edac.txt @@ -730,25 +730,41 @@ Due to the way Nehalem exports Memory Controller data, some adjustments were done at i7core_edac driver. This chapter will cover those differences 1) On Nehalem, there are one Memory Controller per Quick Patch Interconnect - (QPI). At the driver, the term "socket" means one QPI. It should also be - associated with the CPU physical socket. + (QPI). At the driver, the term "socket" means one QPI. This is + associated with a physical CPU socket. Each MC have 3 physical read channels, 3 physical write channels and 3 logic channels. The driver currenty sees it as just 3 channels. Each channel can have up to 3 DIMMs. The minimum known unity is DIMMs. There are no information about csrows. - As EDAC API maps the minimum unity is csrows, the driver exports one + As EDAC API maps the minimum unity is csrows, the driver sequencially + maps channel/dimm into different csrows. + + For example, suposing the following layout: + Ch0 phy rd0, wr0 (0x063f4031): 2 ranks, UDIMMs + dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400 + dimm 1 1024 Mb offset: 4, bank: 8, rank: 1, row: 0x4000, col: 0x400 + Ch1 phy rd1, wr1 (0x063f4031): 2 ranks, UDIMMs + dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400 + Ch2 phy rd3, wr3 (0x063f4031): 2 ranks, UDIMMs + dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400 + The driver will map it as: + csrow0: channel 0, dimm0 + csrow1: channel 0, dimm1 + csrow2: channel 1, dimm0 + csrow3: channel 2, dimm0 + +exports one DIMM per csrow. - Currently, it also exports the several memory controllers as just one. This - limit will be removed on future versions of the driver. + Each QPI is exported as a different memory controller. 2) Nehalem MC has the hability to generate errors. The driver implements this functionality via some error injection nodes: For injecting a memory error, there are some sysfs nodes, under - /sys/devices/system/edac/mc/mc0/: + /sys/devices/system/edac/mc/mc?/: inject_addrmatch: Controls the error injection mask register. It is possible to specify @@ -779,11 +795,6 @@ were done at i7core_edac driver. This chapter will cover those differences 2 for the highest 1 for the lowest - inject_socket: - specifies what QPI (or processor socket) will generate the error. - on Xeon 35xx, it should be 0. - on Xeon 55xx, it should be 0 or 1. - inject_type: specifies the type of error, being a combination of the following bits: bit 0 - repeat @@ -806,10 +817,12 @@ were done at i7core_edac driver. This chapter will cover those differences echo 2 >/sys/devices/system/edac/mc/mc0/inject_type echo 64 >/sys/devices/system/edac/mc/mc0/inject_eccmask echo 3 >/sys/devices/system/edac/mc/mc0/inject_section - echo 0 >/sys/devices/system/edac/mc/mc0/inject_socket echo 1 >/sys/devices/system/edac/mc/mc0/inject_enable dd if=/dev/mem of=/dev/null seek=16k bs=4k count=1 >& /dev/null + For socket 1, it is needed to replace "mc0" by "mc1" at the above + commands. + The generated error message will look like: EDAC MC0: UE row 0, channel-a= 0 channel-b= 0 labels "-": NON_FATAL (addr = 0x0075b980, socket=0, Dimm=0, Channel=2, syndrome=0x00000040, count=1, Err=8c0000400001009f:4000080482 (read error: read ECC error)) @@ -821,9 +834,36 @@ were done at i7core_edac driver. This chapter will cover those differences separate sysfs note were created to handle such counters. They can be read by looking at the contents of "corrected_error_counts" - counter: + counter. Due to hardware limits, the output is different on machines + with unregistered memories and machines with registered ones. + + With unregistered memories, it outputs: $ cat /sys/devices/system/edac/mc/mc0/corrected_error_counts - dimm0: 15866 - dimm1: 0 - dimm2: 27285 + all channels UDIMM0: 0 UDIMM1: 0 UDIMM2: 0 + + What happens here is that errors on different csrows, but at the same + dimm number will increment the same counter. + So, in this memory mapping: + csrow0: channel 0, dimm0 + csrow1: channel 0, dimm1 + csrow2: channel 1, dimm0 + csrow3: channel 2, dimm0 + The hardware will increment UDIMM0 for an error at either csrow0, csrow2 + or csrow3. + + With registered memories, it outputs: + + $cat /sys/devices/system/edac/mc/mc0/corrected_error_counts + channel 0 RDIMM0: 0 RDIMM1: 0 RDIMM2: 0 + channel 1 RDIMM0: 0 RDIMM1: 0 RDIMM2: 0 + channel 2 RDIMM0: 0 RDIMM1: 0 RDIMM2: 0 + + So, with registered memories, there's a direct map between a csrow and a + counter. + +4) Standard error counters + + The standard error counters are generated when an mcelog error is received + by the driver. Since it is counted by software, it is possible that some + errors could be lost. -- GitLab From d88b85072fa7d406f54c30ceeabcd37e5a2ec21a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 5 Sep 2009 05:10:31 -0300 Subject: [PATCH 135/842] i7core_edac: Fix a bug when printing error counts with RDIMMs Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 2c30493eae0f..821e8a1a09cf 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1054,13 +1054,15 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) count = sprintf(data, "data unavailable\n"); return 0; } - if (!pvt->is_registered) + if (!pvt->is_registered) { count = sprintf(data, "all channels " "UDIMM0: %lu UDIMM1: %lu UDIMM2: %lu\n", pvt->udimm_ce_count[0], pvt->udimm_ce_count[1], pvt->udimm_ce_count[2]); - else + data += count; + total += count; + } else { for (i = 0; i < NUM_CHANS; i++) { count = sprintf(data, "channel %d RDIMM0: %lu " "RDIMM1: %lu RDIMM2: %lu\n", @@ -1068,9 +1070,10 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) pvt->rdimm_ce_count[i][0], pvt->rdimm_ce_count[i][1], pvt->rdimm_ce_count[i][2]); - } - data += count; - total += count; + data += count; + total += count; + } + } return total; } -- GitLab From 13d6e9b653e6f714024c67287c7d7eac54d8417b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 5 Sep 2009 12:15:20 -0300 Subject: [PATCH 136/842] i7core_edac: at remove, don't remove all pci devices at once Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 821e8a1a09cf..c2266f820b0f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1135,22 +1135,24 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { * i7core_put_devices 'put' all the devices that we have * reserved via 'get' */ -static void i7core_put_devices(void) +static void i7core_put_devices(struct i7core_dev *i7core_dev) { - int i, j; + int i; - for (i = 0; i < max_num_sockets; i++) { - struct i7core_dev *i7core_dev = get_i7core_dev(i); - if (!i7core_dev) - continue; + for (i = 0; i < N_DEVS; i++) + pci_dev_put(i7core_dev->pdev[i]); - for (j = 0; j < N_DEVS; j++) - pci_dev_put(i7core_dev->pdev[j]); + list_del(&i7core_dev->list); + kfree(i7core_dev->pdev); + kfree(i7core_dev); +} - list_del(&i7core_dev->list); - kfree(i7core_dev->pdev); - kfree(i7core_dev); - } +static void i7core_put_all_devices(void) +{ + struct i7core_dev *i7core_dev; + + list_for_each_entry(i7core_dev, &i7core_edac_list, list) + i7core_put_devices(i7core_dev); } static void i7core_xeon_pci_fixup(void) @@ -1292,7 +1294,7 @@ static int i7core_get_devices(void) pdev = NULL; do { if (i7core_get_onedevice(&pdev, i) < 0) { - i7core_put_devices(); + i7core_put_all_devices(); return -ENODEV; } } while (pdev); @@ -1849,7 +1851,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, return 0; fail1: - i7core_put_devices(); + i7core_put_all_devices(); fail0: mutex_unlock(&i7core_edac_lock); return rc; @@ -1863,6 +1865,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) { struct mem_ctl_info *mci; struct i7core_pvt *pvt; + struct i7core_dev *i7core_dev; debugf0(__FILE__ ": %s()\n", __func__); @@ -1876,13 +1879,12 @@ static void __devexit i7core_remove(struct pci_dev *pdev) /* Unregisters on edac_mce in order to receive memory errors */ pvt = mci->pvt_info; + i7core_dev = pvt->i7core_dev; edac_mce_unregister(&pvt->edac_mce); /* retrieve references to resources, and free those resources */ mutex_lock(&i7core_edac_lock); - - /* FIXME: This should put the devices only for this mci!!! */ - i7core_put_devices(); + i7core_put_devices(i7core_dev); mutex_unlock(&i7core_edac_lock); kfree(mci->ctl_name); -- GitLab From 0f062792b48dc8389fb18cbfb9318625886644c7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 5 Sep 2009 12:16:19 -0300 Subject: [PATCH 137/842] i7core_edac: remove static counter for max sockets The number of sockets is now fully dynamic. Get rid of this obsolete var. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index c2266f820b0f..391348bf93d2 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -247,7 +247,6 @@ struct i7core_pvt { /* Static vars */ static LIST_HEAD(i7core_edac_list); static DEFINE_MUTEX(i7core_edac_lock); -static u8 max_num_sockets; #define PCI_DESCR(device, function, device_id) \ .dev = (device), \ -- GitLab From 22e6bcbdcf9279321dbe646c5a234b816db12881 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sat, 5 Sep 2009 23:06:50 -0300 Subject: [PATCH 138/842] i7core_edac: change remove module strategy The old remove module stragegy didn't work on devices with multiple cores, since only one PCI device is used to open all mc's, due to Nehalem nature. Also, it were based at pdev value. However, this doesn't point to the pci device used at mci->dev. So, instead, it unregisters all devices at once, deleting them from the device list. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 55 ++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 391348bf93d2..c3fec5de3e51 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1138,11 +1138,18 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev) { int i; - for (i = 0; i < N_DEVS; i++) - pci_dev_put(i7core_dev->pdev[i]); - - list_del(&i7core_dev->list); + debugf0(__FILE__ ": %s()\n", __func__); + for (i = 0; i < N_DEVS; i++) { + struct pci_dev *pdev = i7core_dev->pdev[i]; + if (!pdev) + continue; + debugf0("Removing dev %02x:%02x.%d\n", + pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + pci_dev_put(pdev); + } kfree(i7core_dev->pdev); + list_del(&i7core_dev->list); kfree(i7core_dev); } @@ -1863,31 +1870,39 @@ fail0: static void __devexit i7core_remove(struct pci_dev *pdev) { struct mem_ctl_info *mci; - struct i7core_pvt *pvt; - struct i7core_dev *i7core_dev; + struct i7core_dev *i7core_dev, *tmp; debugf0(__FILE__ ": %s()\n", __func__); if (i7core_pci) edac_pci_release_generic_ctl(i7core_pci); + /* + * we have a trouble here: pdev value for removal will be wrong, since + * it will point to the X58 register used to detect that the machine + * is a Nehalem or upper design. However, due to the way several PCI + * devices are grouped together to provide MC functionality, we need + * to use a different method for releasing the devices + */ - mci = edac_mc_del_mc(&pdev->dev); - if (!mci) - return; - - /* Unregisters on edac_mce in order to receive memory errors */ - pvt = mci->pvt_info; - i7core_dev = pvt->i7core_dev; - edac_mce_unregister(&pvt->edac_mce); - - /* retrieve references to resources, and free those resources */ mutex_lock(&i7core_edac_lock); - i7core_put_devices(i7core_dev); + list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) { + mci = edac_mc_del_mc(&i7core_dev->pdev[0]->dev); + if (mci) { + struct i7core_pvt *pvt = mci->pvt_info; + + i7core_dev = pvt->i7core_dev; + edac_mce_unregister(&pvt->edac_mce); + kfree(mci->ctl_name); + edac_mc_free(mci); + i7core_put_devices(i7core_dev); + } else { + i7core_printk(KERN_ERR, + "Couldn't find mci for socket %d\n", + i7core_dev->socket); + } + } mutex_unlock(&i7core_edac_lock); - - kfree(mci->ctl_name); - edac_mc_free(mci); } MODULE_DEVICE_TABLE(pci, i7core_pci_tbl); -- GitLab From 4253868034221db6e42dbbb61e0305fe1757f8da Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 24 Sep 2009 09:59:13 -0300 Subject: [PATCH 139/842] i7core_edac: We need to use list_for_each_entry_safe to avoid errors Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index c3fec5de3e51..2e4b0abf9d43 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1124,6 +1124,7 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { .show = i7core_ce_regs_show, .store = NULL, }, + { .attr = { .name = NULL } } }; /**************************************************************************** @@ -1155,9 +1156,9 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev) static void i7core_put_all_devices(void) { - struct i7core_dev *i7core_dev; + struct i7core_dev *i7core_dev, *tmp; - list_for_each_entry(i7core_dev, &i7core_edac_list, list) + list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) i7core_put_devices(i7core_dev); } -- GitLab From 4af91889e02c9933823ca8c62fc6f05dfd15f3bd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 24 Sep 2009 09:58:26 -0300 Subject: [PATCH 140/842] i7core_edac: Avoid printing a warning when debug is disabled Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 2e4b0abf9d43..0478cc85e920 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -471,7 +471,6 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) struct csrow_info *csr; struct pci_dev *pdev; int i, j; - u8 socket = pvt->i7core_dev->socket; unsigned long last_page = 0; enum edac_type mode; enum mem_type mtype; @@ -488,7 +487,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map); debugf0("QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n", - socket, pvt->info.mc_control, pvt->info.mc_status, + pvt->i7core_dev->socket, pvt->info.mc_control, pvt->info.mc_status, pvt->info.max_dod, pvt->info.ch_map); if (ECC_ENABLED(pvt)) { -- GitLab From 9fa2fc2e2d641df7d69dc4e06cf2552c44b58e95 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 23 Sep 2009 16:26:09 -0300 Subject: [PATCH 141/842] edac_core: Allow the creation of sysfs groups Currently, all sysfs nodes are stored at /sys/.*/mc. (regex) However, sometimes it is needed to create attribute groups. This patch extends edac_core to allow groups creation. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/edac_core.h | 12 +++++- drivers/edac/edac_mc_sysfs.c | 83 ++++++++++++++++++++++++------------ 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 001b2e797fb3..97071ff1d22d 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -341,12 +341,22 @@ struct csrow_info { struct channel_info *channels; }; +struct mcidev_sysfs_group { + const char *name; + struct mcidev_sysfs_attribute *mcidev_attr; + struct kobject kobj; +}; + + /* mcidev_sysfs_attribute structure * used for driver sysfs attributes and in mem_ctl_info * sysfs top level entries */ struct mcidev_sysfs_attribute { - struct attribute attr; + struct attribute attr; + + struct mcidev_sysfs_group *grp; + ssize_t (*show)(struct mem_ctl_info *,char *); ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); }; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 418b65f1a1da..655aa1a1f4f9 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -728,26 +728,43 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) /* * edac_create_mci_instance_attributes - * create MC driver specific attributes at the topmost level - * directory of this mci instance. + * create MC driver specific attributes bellow an specified kobj + * This routine calls itself recursively, in order to create an entire + * object tree. */ -static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci) +static int edac_create_mci_instance_attributes( + struct mcidev_sysfs_attribute *sysfs_attrib, + struct kobject *kobj) { int err; - struct mcidev_sysfs_attribute *sysfs_attrib; - /* point to the start of the array and iterate over it - * adding each attribute listed to this mci instance's kobject - */ - sysfs_attrib = mci->mc_driver_sysfs_attributes; + while (sysfs_attrib) { + if (sysfs_attrib->grp) { + struct kobject *newkobj = &sysfs_attrib->grp->kobj; + debugf0("%s() grp %s\n", __func__, + sysfs_attrib->grp->name); + + err = kobject_init_and_add(newkobj, NULL, + kobj, + sysfs_attrib->grp->name); + if (err) + return err; + + err = edac_create_mci_instance_attributes( + sysfs_attrib->grp->mcidev_attr, newkobj); + if (err) + return err; + } else if (sysfs_attrib->attr.name) { + debugf0("%s() file %s\n", __func__, + sysfs_attrib->attr.name); + + err = sysfs_create_file(kobj, &sysfs_attrib->attr); + } else + break; - while (sysfs_attrib && sysfs_attrib->attr.name) { - err = sysfs_create_file(&mci->edac_mci_kobj, - (struct attribute*) sysfs_attrib); if (err) { return err; } - sysfs_attrib++; } @@ -759,19 +776,28 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci) * remove MC driver specific attributes at the topmost level * directory of this mci instance. */ -static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci) +static void edac_remove_mci_instance_attributes( + struct mcidev_sysfs_attribute *sysfs_attrib, + struct kobject *kobj) { - struct mcidev_sysfs_attribute *sysfs_attrib; - - /* point to the start of the array and iterate over it - * adding each attribute listed to this mci instance's kobject - */ - sysfs_attrib = mci->mc_driver_sysfs_attributes; - /* loop if there are attributes and until we hit a NULL entry */ - while (sysfs_attrib && sysfs_attrib->attr.name) { - sysfs_remove_file(&mci->edac_mci_kobj, - (struct attribute *) sysfs_attrib); + while (sysfs_attrib) { + if (sysfs_attrib->grp) { + struct kobject *newkobj = &sysfs_attrib->grp->kobj; + + debugf0("%s() grp %s\n", __func__, + sysfs_attrib->grp->name); + + edac_remove_mci_instance_attributes( + sysfs_attrib->grp->mcidev_attr, newkobj); + + kobject_put(newkobj); + } else if (sysfs_attrib->attr.name) { + debugf0("%s() file %s\n", __func__, + sysfs_attrib->attr.name); + sysfs_remove_file(kobj, &sysfs_attrib->attr); + } else + break; sysfs_attrib++; } } @@ -806,7 +832,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) * then create them now for the driver. */ if (mci->mc_driver_sysfs_attributes) { - err = edac_create_mci_instance_attributes(mci); + err = edac_create_mci_instance_attributes( + mci->mc_driver_sysfs_attributes, + &mci->edac_mci_kobj); if (err) { debugf1("%s() failure to create mci attributes\n", __func__); @@ -841,7 +869,8 @@ fail1: } /* remove the mci instance's attributes, if any */ - edac_remove_mci_instance_attributes(mci); + edac_remove_mci_instance_attributes( + mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj); /* remove the symlink */ sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK); @@ -875,8 +904,8 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) debugf0("%s() remove_mci_instance\n", __func__); /* remove this mci instance's attribtes */ - edac_remove_mci_instance_attributes(mci); - + edac_remove_mci_instance_attributes(mci->mc_driver_sysfs_attributes, + &mci->edac_mci_kobj); debugf0("%s() unregister this mci kobj\n", __func__); /* unregister this instance's kobject */ -- GitLab From a5538e531fc1e00ac7185dcfcebf33c37b5d742e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 23 Sep 2009 18:56:47 -0300 Subject: [PATCH 142/842] i7core_edac: Add support for sysfs addrmatch group Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 173 +++++++++++++++---------------------- 1 file changed, 70 insertions(+), 103 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 0478cc85e920..afa5281e8df9 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -778,105 +778,59 @@ static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci, * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an * uncorrectable error to be injected. */ -static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci, - const char *data, size_t count) -{ - struct i7core_pvt *pvt = mci->pvt_info; - char *cmd, *val; - long value; - int rc; - - if (pvt->inject.enable) - disable_inject(mci); - - do { - cmd = strsep((char **) &data, ":"); - if (!cmd) - break; - val = strsep((char **) &data, " \n\t"); - if (!val) - return cmd - data; - - if (!strcasecmp(val, "any")) - value = -1; - else { - rc = strict_strtol(val, 10, &value); - if ((rc < 0) || (value < 0)) - return cmd - data; - } - - if (!strcasecmp(cmd, "channel")) { - if (value < 3) - pvt->inject.channel = value; - else - return cmd - data; - } else if (!strcasecmp(cmd, "dimm")) { - if (value < 3) - pvt->inject.dimm = value; - else - return cmd - data; - } else if (!strcasecmp(cmd, "rank")) { - if (value < 4) - pvt->inject.rank = value; - else - return cmd - data; - } else if (!strcasecmp(cmd, "bank")) { - if (value < 32) - pvt->inject.bank = value; - else - return cmd - data; - } else if (!strcasecmp(cmd, "page")) { - if (value <= 0xffff) - pvt->inject.page = value; - else - return cmd - data; - } else if (!strcasecmp(cmd, "col") || - !strcasecmp(cmd, "column")) { - if (value <= 0x3fff) - pvt->inject.col = value; - else - return cmd - data; - } - } while (1); - return count; +#define DECLARE_ADDR_MATCH(param, limit) \ +static ssize_t i7core_inject_store_##param( \ + struct mem_ctl_info *mci, \ + const char *data, size_t count) \ +{ \ + struct i7core_pvt *pvt = mci->pvt_info; \ + long value; \ + int rc; \ + \ + if (pvt->inject.enable) \ + disable_inject(mci); \ + \ + if (!strcasecmp(data, "any")) \ + value = -1; \ + else { \ + rc = strict_strtoul(data, 10, &value); \ + if ((rc < 0) || (value >= limit)) \ + return -EIO; \ + } \ + \ + pvt->inject.param = value; \ + \ + return count; \ +} \ + \ +static ssize_t i7core_inject_show_##param( \ + struct mem_ctl_info *mci, \ + char *data) \ +{ \ + struct i7core_pvt *pvt = mci->pvt_info; \ + if (pvt->inject.param < 0) \ + return sprintf(data, "any\n"); \ + else \ + return sprintf(data, "%d\n", pvt->inject.param);\ } -static ssize_t i7core_inject_addrmatch_show(struct mem_ctl_info *mci, - char *data) -{ - struct i7core_pvt *pvt = mci->pvt_info; - char channel[4], dimm[4], bank[4], rank[4], page[7], col[7]; - - if (pvt->inject.channel < 0) - sprintf(channel, "any"); - else - sprintf(channel, "%d", pvt->inject.channel); - if (pvt->inject.dimm < 0) - sprintf(dimm, "any"); - else - sprintf(dimm, "%d", pvt->inject.dimm); - if (pvt->inject.bank < 0) - sprintf(bank, "any"); - else - sprintf(bank, "%d", pvt->inject.bank); - if (pvt->inject.rank < 0) - sprintf(rank, "any"); - else - sprintf(rank, "%d", pvt->inject.rank); - if (pvt->inject.page < 0) - sprintf(page, "any"); - else - sprintf(page, "0x%04x", pvt->inject.page); - if (pvt->inject.col < 0) - sprintf(col, "any"); - else - sprintf(col, "0x%04x", pvt->inject.col); +#define ATTR_ADDR_MATCH(param) \ + { \ + .attr = { \ + .name = #param, \ + .mode = (S_IRUGO | S_IWUSR) \ + }, \ + .show = i7core_inject_show_##param, \ + .store = i7core_inject_store_##param, \ + } - return sprintf(data, "channel: %s\ndimm: %s\nbank: %s\n" - "rank: %s\npage: %s\ncolumn: %s\n", - channel, dimm, bank, rank, page, col); -} +DECLARE_ADDR_MATCH(channel, 3); +DECLARE_ADDR_MATCH(dimm, 3); +DECLARE_ADDR_MATCH(rank, 4); +DECLARE_ADDR_MATCH(bank, 32); +DECLARE_ADDR_MATCH(page, 0x10000); +DECLARE_ADDR_MATCH(col, 0x4000); static int write_and_test(struct pci_dev *dev, int where, u32 val) { @@ -1079,7 +1033,25 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) /* * Sysfs struct */ -static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { + + +static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = { + ATTR_ADDR_MATCH(channel), + ATTR_ADDR_MATCH(dimm), + ATTR_ADDR_MATCH(rank), + ATTR_ADDR_MATCH(bank), + ATTR_ADDR_MATCH(page), + ATTR_ADDR_MATCH(col), + { .attr = { .name = NULL } } +}; + + +static struct mcidev_sysfs_group i7core_inject_addrmatch = { + .name = "inject_addrmatch", + .mcidev_attr = i7core_addrmatch_attrs, +}; + +static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { { .attr = { .name = "inject_section", @@ -1102,12 +1074,7 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { .show = i7core_inject_eccmask_show, .store = i7core_inject_eccmask_store, }, { - .attr = { - .name = "inject_addrmatch", - .mode = (S_IRUGO | S_IWUSR) - }, - .show = i7core_inject_addrmatch_show, - .store = i7core_inject_addrmatch_store, + .grp = &i7core_inject_addrmatch, }, { .attr = { .name = "inject_enable", @@ -1750,7 +1717,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, i7core_dev->socket); mci->dev_name = pci_name(i7core_dev->pdev[0]); mci->ctl_page_to_phys = NULL; - mci->mc_driver_sysfs_attributes = i7core_inj_attrs; + mci->mc_driver_sysfs_attributes = i7core_sysfs_attrs; /* Set the function pointer to an actual operation function */ mci->edac_check = i7core_check_error; -- GitLab From cc301b3ae3f615fe243f023e68e22b8298a6f883 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 24 Sep 2009 16:23:42 -0300 Subject: [PATCH 143/842] edac: store/show methods for device groups weren't working Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/edac_core.h | 2 + drivers/edac/edac_mc_sysfs.c | 85 +++++++++++++++++++++++++++++++++--- drivers/edac/i7core_edac.c | 10 ++++- 3 files changed, 88 insertions(+), 9 deletions(-) diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 97071ff1d22d..02bbbc9696d9 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -345,6 +345,8 @@ struct mcidev_sysfs_group { const char *name; struct mcidev_sysfs_attribute *mcidev_attr; struct kobject kobj; + + struct mem_ctl_info *mci; /* the parent */ }; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 655aa1a1f4f9..6088ae6e8ea5 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -557,6 +557,8 @@ static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, struct mem_ctl_info *mem_ctl_info = to_mci(kobj); struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); + debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info); + if (mcidev_attr->show) return mcidev_attr->show(mem_ctl_info, buffer); @@ -569,6 +571,8 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, struct mem_ctl_info *mem_ctl_info = to_mci(kobj); struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); + debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info); + if (mcidev_attr->store) return mcidev_attr->store(mem_ctl_info, buffer, count); @@ -726,32 +730,97 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) #define EDAC_DEVICE_SYMLINK "device" +#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group, kobj)->mci) + +/* MCI show/store functions for top most object */ +static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr, + char *buffer) +{ + struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj); + struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); + + debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info); + + if (mcidev_attr->show) + return mcidev_attr->show(mem_ctl_info, buffer); + + return -EIO; +} + +static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj); + struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr); + + debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info); + + if (mcidev_attr->store) + return mcidev_attr->store(mem_ctl_info, buffer, count); + + return -EIO; +} + +/* No memory to release for this kobj */ +static void edac_inst_grp_release(struct kobject *kobj) +{ + struct mcidev_sysfs_group *grp; + struct mem_ctl_info *mci; + + debugf1("%s()\n", __func__); + + grp = container_of(kobj, struct mcidev_sysfs_group, kobj); + mci = grp->mci; + + kobject_put(&mci->edac_mci_kobj); +} + +/* Intermediate show/store table */ +static struct sysfs_ops inst_grp_ops = { + .show = inst_grp_show, + .store = inst_grp_store +}; + +/* the kobj_type instance for a instance group */ +static struct kobj_type ktype_inst_grp = { + .release = edac_inst_grp_release, + .sysfs_ops = &inst_grp_ops, + .default_attrs = (struct attribute **)default_csrow_attr, +}; + + /* * edac_create_mci_instance_attributes * create MC driver specific attributes bellow an specified kobj * This routine calls itself recursively, in order to create an entire * object tree. */ -static int edac_create_mci_instance_attributes( +static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, struct mcidev_sysfs_attribute *sysfs_attrib, struct kobject *kobj) { int err; + debugf1("%s()\n", __func__); + while (sysfs_attrib) { if (sysfs_attrib->grp) { struct kobject *newkobj = &sysfs_attrib->grp->kobj; - debugf0("%s() grp %s\n", __func__, - sysfs_attrib->grp->name); + debugf0("%s() grp %s, mci %p\n", __func__, + sysfs_attrib->grp->name, mci); + + sysfs_attrib->grp->mci = mci; - err = kobject_init_and_add(newkobj, NULL, + err = kobject_init_and_add(newkobj, &ktype_inst_grp, kobj, sysfs_attrib->grp->name); if (err) return err; - err = edac_create_mci_instance_attributes( - sysfs_attrib->grp->mcidev_attr, newkobj); + err = edac_create_mci_instance_attributes(mci, + sysfs_attrib->grp->mcidev_attr, + newkobj); + if (err) return err; } else if (sysfs_attrib->attr.name) { @@ -780,6 +849,8 @@ static void edac_remove_mci_instance_attributes( struct mcidev_sysfs_attribute *sysfs_attrib, struct kobject *kobj) { + debugf1("%s()\n", __func__); + /* loop if there are attributes and until we hit a NULL entry */ while (sysfs_attrib) { if (sysfs_attrib->grp) { @@ -832,7 +903,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) * then create them now for the driver. */ if (mci->mc_driver_sysfs_attributes) { - err = edac_create_mci_instance_attributes( + err = edac_create_mci_instance_attributes(mci, mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj); if (err) { diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index afa5281e8df9..e013004745de 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -784,10 +784,13 @@ static ssize_t i7core_inject_store_##param( \ struct mem_ctl_info *mci, \ const char *data, size_t count) \ { \ - struct i7core_pvt *pvt = mci->pvt_info; \ + struct i7core_pvt *pvt; \ long value; \ int rc; \ \ + debugf1("%s()\n", __func__); \ + pvt = mci->pvt_info; \ + \ if (pvt->inject.enable) \ disable_inject(mci); \ \ @@ -808,7 +811,10 @@ static ssize_t i7core_inject_show_##param( \ struct mem_ctl_info *mci, \ char *data) \ { \ - struct i7core_pvt *pvt = mci->pvt_info; \ + struct i7core_pvt *pvt; \ + \ + pvt = mci->pvt_info; \ + debugf1("%s() pvt=%p\n", __func__, pvt); \ if (pvt->inject.param < 0) \ return sprintf(data, "any\n"); \ else \ -- GitLab From c419d921e68c54232ce6d369a3b528cd7644b2ae Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 24 Sep 2009 16:36:32 -0300 Subject: [PATCH 144/842] edac: Don't create csrow entries on instance groups Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/edac_mc_sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 6088ae6e8ea5..f689d7d6ab46 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -785,7 +785,6 @@ static struct sysfs_ops inst_grp_ops = { static struct kobj_type ktype_inst_grp = { .release = edac_inst_grp_release, .sysfs_ops = &inst_grp_ops, - .default_attrs = (struct attribute **)default_csrow_attr, }; @@ -806,13 +805,14 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, while (sysfs_attrib) { if (sysfs_attrib->grp) { struct kobject *newkobj = &sysfs_attrib->grp->kobj; + debugf0("%s() grp %s, mci %p\n", __func__, sysfs_attrib->grp->name, mci); sysfs_attrib->grp->mci = mci; err = kobject_init_and_add(newkobj, &ktype_inst_grp, - kobj, + &mci->edac_mci_kobj, sysfs_attrib->grp->name); if (err) return err; -- GitLab From f338d736910edf00e8426ee4322cfda585268d50 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 24 Sep 2009 17:25:43 -0300 Subject: [PATCH 145/842] i7core_edac: Convert UDIMM error counters into a proper sysfs group Instead of displaying 3 values at the same var, break it into 3 different sysfs nodes: /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm0 /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm1 /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm2 For registered dimms, however, the error counters are already being displayed at: /sys/devices/system/edac/mc/mc0/csrow*/ce_count So, there's no need to add any extra sysfs nodes. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 81 +++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e013004745de..97f6d1759c99 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1003,38 +1003,32 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, return sprintf(data, "%d\n", pvt->inject.enable); } -static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) -{ - unsigned i, count, total = 0; - struct i7core_pvt *pvt = mci->pvt_info; +#define DECLARE_COUNTER(param) \ +static ssize_t i7core_show_counter_##param( \ + struct mem_ctl_info *mci, \ + char *data) \ +{ \ + struct i7core_pvt *pvt = mci->pvt_info; \ + \ + debugf1("%s() \n", __func__); \ + if (!pvt->ce_count_available || (pvt->is_registered)) \ + return sprintf(data, "data unavailable\n"); \ + return sprintf(data, "%lu\n", \ + pvt->udimm_ce_count[param]); \ +} - if (!pvt->ce_count_available) { - count = sprintf(data, "data unavailable\n"); - return 0; - } - if (!pvt->is_registered) { - count = sprintf(data, "all channels " - "UDIMM0: %lu UDIMM1: %lu UDIMM2: %lu\n", - pvt->udimm_ce_count[0], - pvt->udimm_ce_count[1], - pvt->udimm_ce_count[2]); - data += count; - total += count; - } else { - for (i = 0; i < NUM_CHANS; i++) { - count = sprintf(data, "channel %d RDIMM0: %lu " - "RDIMM1: %lu RDIMM2: %lu\n", - i, - pvt->rdimm_ce_count[i][0], - pvt->rdimm_ce_count[i][1], - pvt->rdimm_ce_count[i][2]); - data += count; - total += count; - } +#define ATTR_COUNTER(param) \ + { \ + .attr = { \ + .name = __stringify(udimm##param), \ + .mode = (S_IRUGO | S_IWUSR) \ + }, \ + .show = i7core_show_counter_##param \ } - return total; -} +DECLARE_COUNTER(0); +DECLARE_COUNTER(1); +DECLARE_COUNTER(2); /* * Sysfs struct @@ -1051,12 +1045,22 @@ static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = { { .attr = { .name = NULL } } }; - static struct mcidev_sysfs_group i7core_inject_addrmatch = { .name = "inject_addrmatch", .mcidev_attr = i7core_addrmatch_attrs, }; +static struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = { + ATTR_COUNTER(0), + ATTR_COUNTER(1), + ATTR_COUNTER(2), +}; + +static struct mcidev_sysfs_group i7core_udimm_counters = { + .name = "all_channel_counts", + .mcidev_attr = i7core_udimm_counters_attrs, +}; + static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { { .attr = { @@ -1088,14 +1092,8 @@ static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { }, .show = i7core_inject_enable_show, .store = i7core_inject_enable_store, - }, { - .attr = { - .name = "corrected_error_counts", - .mode = (S_IRUGO | S_IWUSR) - }, - .show = i7core_ce_regs_show, - .store = NULL, }, + { .attr = { .name = NULL } }, /* Reserved for udimm counters */ { .attr = { .name = NULL } } }; @@ -1323,6 +1321,15 @@ static int mci_bind_devs(struct mem_ctl_info *mci, pvt->is_registered = 1; } + /* + * Add extra nodes to count errors on udimm + * For registered memory, this is not needed, since the counters + * are already displayed at the standard locations + */ + if (!pvt->is_registered) + i7core_sysfs_attrs[ARRAY_SIZE(i7core_sysfs_attrs)-2].grp = + &i7core_udimm_counters; + return 0; error: -- GitLab From 35be95446734cbb10b088a6b38269ac4a8ac3a86 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 24 Sep 2009 17:28:50 -0300 Subject: [PATCH 146/842] Documentation/edac.txt: Reflect the sysfs changes at the document Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- Documentation/edac.txt | 56 ++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/Documentation/edac.txt b/Documentation/edac.txt index bd3f8a3905af..0b875e8da969 100644 --- a/Documentation/edac.txt +++ b/Documentation/edac.txt @@ -766,7 +766,7 @@ exports one For injecting a memory error, there are some sysfs nodes, under /sys/devices/system/edac/mc/mc?/: - inject_addrmatch: + inject_addrmatch/*: Controls the error injection mask register. It is possible to specify several characteristics of the address to match an error code: dimm = the affected dimm. Numbers are relative to a channel; @@ -781,10 +781,12 @@ exports one For example, to generate an error at rank 1 of dimm 2, for any channel, any bank, any page, any column: - echo "dimm:2 rank:1" >/sys/devices/system/edac/mc/mc0/inject_addrmatch + echo 2 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/dimm + echo 1 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/rank To return to the default behaviour of matching any, you can do: - echo "dimm:any rank:any" >/sys/devices/system/edac/mc/mc0/inject_addrmatch + echo any >/sys/devices/system/edac/mc/mc0/inject_addrmatch/dimm + echo any >/sys/devices/system/edac/mc/mc0/inject_addrmatch/rank inject_eccmask: specifies what bits will have troubles, @@ -813,7 +815,7 @@ exports one For example, the following code will generate an error for any write access at socket 0, on any DIMM/address on channel 2: - echo "channel:2" > /sys/devices/system/edac/mc/mc0/inject_addrmatch + echo 2 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/channel echo 2 >/sys/devices/system/edac/mc/mc0/inject_type echo 64 >/sys/devices/system/edac/mc/mc0/inject_eccmask echo 3 >/sys/devices/system/edac/mc/mc0/inject_section @@ -829,18 +831,23 @@ exports one 3) Nehalem specific Corrected Error memory counters - Nehalem have some registers to count memory errors, reporting it on a - way that it is different from what EDAC API allows. Due to that, a - separate sysfs note were created to handle such counters. + Nehalem have some registers to count memory errors. The driver uses those + registers to report Corrected Errors on devices with Registered Dimms. - They can be read by looking at the contents of "corrected_error_counts" - counter. Due to hardware limits, the output is different on machines - with unregistered memories and machines with registered ones. + However, those counters don't work with Unregistered Dimms. As the chipset + offers some counters that also work with UDIMMS (but with a worse level of + granularity than the default ones), the driver exposes those registers for + UDIMM memories. - With unregistered memories, it outputs: + They can be read by looking at the contents of all_channel_counts/ - $ cat /sys/devices/system/edac/mc/mc0/corrected_error_counts - all channels UDIMM0: 0 UDIMM1: 0 UDIMM2: 0 + $ for i in /sys/devices/system/edac/mc/mc0/all_channel_counts/*; do echo $i; cat $i; done + /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm0 + 0 + /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm1 + 0 + /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm2 + 0 What happens here is that errors on different csrows, but at the same dimm number will increment the same counter. @@ -849,21 +856,16 @@ exports one csrow1: channel 0, dimm1 csrow2: channel 1, dimm0 csrow3: channel 2, dimm0 - The hardware will increment UDIMM0 for an error at either csrow0, csrow2 - or csrow3. - - With registered memories, it outputs: - - $cat /sys/devices/system/edac/mc/mc0/corrected_error_counts - channel 0 RDIMM0: 0 RDIMM1: 0 RDIMM2: 0 - channel 1 RDIMM0: 0 RDIMM1: 0 RDIMM2: 0 - channel 2 RDIMM0: 0 RDIMM1: 0 RDIMM2: 0 - - So, with registered memories, there's a direct map between a csrow and a - counter. + The hardware will increment udimm0 for an error at the first dimm at either + csrow0, csrow2 or csrow3; + The hardware will increment udimm1 for an error at the second dimm at either + csrow0, csrow2 or csrow3; + The hardware will increment udimm2 for an error at the third dimm at either + csrow0, csrow2 or csrow3; 4) Standard error counters The standard error counters are generated when an mcelog error is received - by the driver. Since it is counted by software, it is possible that some - errors could be lost. + by the driver. Since, with udimm, this is counted by software, it is + possible that some errors could be lost. With rdimm's, they displays the + contents of the registers -- GitLab From b968759ee7102f86fec5f3349f7a8ab4556884a3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Fri, 25 Sep 2009 13:42:25 -0300 Subject: [PATCH 147/842] edac: Create an unique instance for each kobj Current code only works when there's just one memory controller, since we need one kobj for each instance. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/edac_core.h | 21 +++++++--- drivers/edac/edac_mc_sysfs.c | 75 +++++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 02bbbc9696d9..efca9343d26a 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -342,23 +342,29 @@ struct csrow_info { }; struct mcidev_sysfs_group { - const char *name; - struct mcidev_sysfs_attribute *mcidev_attr; - struct kobject kobj; + const char *name; /* group name */ + struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */ +}; + +struct mcidev_sysfs_group_kobj { + struct list_head list; /* list for all instances within a mc */ + + struct kobject kobj; /* kobj for the group */ + struct mcidev_sysfs_group *grp; /* group description table */ struct mem_ctl_info *mci; /* the parent */ }; - /* mcidev_sysfs_attribute structure * used for driver sysfs attributes and in mem_ctl_info * sysfs top level entries */ struct mcidev_sysfs_attribute { + /* It should use either attr or grp */ struct attribute attr; + struct mcidev_sysfs_group *grp; /* Points to a group of attributes */ - struct mcidev_sysfs_group *grp; - + /* Ops for show/store values at the attribute - not used on group */ ssize_t (*show)(struct mem_ctl_info *,char *); ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); }; @@ -436,6 +442,9 @@ struct mem_ctl_info { /* edac sysfs device control */ struct kobject edac_mci_kobj; + /* list for all grp instances within a mc */ + struct list_head grp_kobj_list; + /* Additional top controller level attributes, but specified * by the low level driver. * diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index f689d7d6ab46..c200c2fd43ea 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -730,7 +730,7 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) #define EDAC_DEVICE_SYMLINK "device" -#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group, kobj)->mci) +#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci) /* MCI show/store functions for top most object */ static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr, @@ -764,12 +764,12 @@ static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr, /* No memory to release for this kobj */ static void edac_inst_grp_release(struct kobject *kobj) { - struct mcidev_sysfs_group *grp; + struct mcidev_sysfs_group_kobj *grp; struct mem_ctl_info *mci; debugf1("%s()\n", __func__); - grp = container_of(kobj, struct mcidev_sysfs_group, kobj); + grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj); mci = grp->mci; kobject_put(&mci->edac_mci_kobj); @@ -804,22 +804,30 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, while (sysfs_attrib) { if (sysfs_attrib->grp) { - struct kobject *newkobj = &sysfs_attrib->grp->kobj; + struct mcidev_sysfs_group_kobj *grp_kobj; + + grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL); + if (!grp_kobj) + return -ENOMEM; + + list_add_tail(&grp_kobj->list, &mci->grp_kobj_list); + + grp_kobj->grp = sysfs_attrib->grp; + grp_kobj->mci = mci; debugf0("%s() grp %s, mci %p\n", __func__, sysfs_attrib->grp->name, mci); - sysfs_attrib->grp->mci = mci; - - err = kobject_init_and_add(newkobj, &ktype_inst_grp, + err = kobject_init_and_add(&grp_kobj->kobj, + &ktype_inst_grp, &mci->edac_mci_kobj, sysfs_attrib->grp->name); if (err) return err; err = edac_create_mci_instance_attributes(mci, - sysfs_attrib->grp->mcidev_attr, - newkobj); + grp_kobj->grp->mcidev_attr, + &grp_kobj->kobj); if (err) return err; @@ -845,25 +853,27 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, * remove MC driver specific attributes at the topmost level * directory of this mci instance. */ -static void edac_remove_mci_instance_attributes( +static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, struct mcidev_sysfs_attribute *sysfs_attrib, - struct kobject *kobj) + struct kobject *kobj, int count) { + struct mcidev_sysfs_group_kobj *grp_kobj, *tmp; + debugf1("%s()\n", __func__); - /* loop if there are attributes and until we hit a NULL entry */ + /* + * loop if there are attributes and until we hit a NULL entry + * Remove first all the atributes + */ while (sysfs_attrib) { if (sysfs_attrib->grp) { - struct kobject *newkobj = &sysfs_attrib->grp->kobj; - - debugf0("%s() grp %s\n", __func__, - sysfs_attrib->grp->name); - - edac_remove_mci_instance_attributes( - sysfs_attrib->grp->mcidev_attr, newkobj); - - kobject_put(newkobj); - } else if (sysfs_attrib->attr.name) { + list_for_each_entry(grp_kobj, &mci->grp_kobj_list, + list) + if (grp_kobj->grp == sysfs_attrib->grp) + edac_remove_mci_instance_attributes(mci, + grp_kobj->grp->mcidev_attr, + &grp_kobj->kobj, count + 1); + } else if (sysfs_attrib->attr.name) { debugf0("%s() file %s\n", __func__, sysfs_attrib->attr.name); sysfs_remove_file(kobj, &sysfs_attrib->attr); @@ -871,6 +881,16 @@ static void edac_remove_mci_instance_attributes( break; sysfs_attrib++; } + + /* + * Now that all attributes got removed, it is save to remove all groups + */ + if (!count) + list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list, + list) { + debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name); + kobject_put(&grp_kobj->kobj); + } } @@ -891,6 +911,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) debugf0("%s() idx=%d\n", __func__, mci->mc_idx); + INIT_LIST_HEAD(&mci->grp_kobj_list); + /* create a symlink for the device */ err = sysfs_create_link(kobj_mci, &mci->dev->kobj, EDAC_DEVICE_SYMLINK); @@ -940,8 +962,8 @@ fail1: } /* remove the mci instance's attributes, if any */ - edac_remove_mci_instance_attributes( - mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj); + edac_remove_mci_instance_attributes(mci, + mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0); /* remove the symlink */ sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK); @@ -975,8 +997,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) debugf0("%s() remove_mci_instance\n", __func__); /* remove this mci instance's attribtes */ - edac_remove_mci_instance_attributes(mci->mc_driver_sysfs_attributes, - &mci->edac_mci_kobj); + edac_remove_mci_instance_attributes(mci, + mci->mc_driver_sysfs_attributes, + &mci->edac_mci_kobj, 0); debugf0("%s() unregister this mci kobj\n", __func__); /* unregister this instance's kobject */ -- GitLab From ca9c90ba09ca3c9799319f46a56f397afbf617c2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sun, 4 Oct 2009 10:15:40 -0300 Subject: [PATCH 148/842] i7core_edac: Use a lockless ringbuffer Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 83 +++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 97f6d1759c99..94aeca011ac4 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -28,7 +28,6 @@ #include <linux/edac.h> #include <linux/mmzone.h> #include <linux/edac_mce.h> -#include <linux/spinlock.h> #include <linux/smp.h> #include <asm/processor.h> @@ -239,9 +238,16 @@ struct i7core_pvt { /* mcelog glue */ struct edac_mce edac_mce; + + /* Fifo double buffers */ struct mce mce_entry[MCE_LOG_LEN]; - unsigned mce_count; - spinlock_t mce_lock; + struct mce mce_outentry[MCE_LOG_LEN]; + + /* Fifo in/out counters */ + unsigned mce_in, mce_out; + + /* Count indicator to show errors not got */ + unsigned mce_overrun; }; /* Static vars */ @@ -1617,30 +1623,50 @@ static void i7core_check_error(struct mem_ctl_info *mci) struct i7core_pvt *pvt = mci->pvt_info; int i; unsigned count = 0; - struct mce *m = NULL; - unsigned long flags; + struct mce *m; - /* Copy all mce errors into a temporary buffer */ - spin_lock_irqsave(&pvt->mce_lock, flags); - if (pvt->mce_count) { - m = kmalloc(sizeof(*m) * pvt->mce_count, GFP_ATOMIC); + /* + * MCE first step: Copy all mce errors into a temporary buffer + * We use a double buffering here, to reduce the risk of + * loosing an error. + */ + smp_rmb(); + count = (pvt->mce_out + sizeof(mce_entry) - pvt->mce_in) + % sizeof(mce_entry); + if (!count) + return; - if (m) { - count = pvt->mce_count; - memcpy(m, &pvt->mce_entry, sizeof(*m) * count); - } - pvt->mce_count = 0; - } + m = pvt->mce_outentry; + if (pvt->mce_in + count > sizeof(mce_entry)) { + unsigned l = sizeof(mce_entry) - pvt->mce_in; - spin_unlock_irqrestore(&pvt->mce_lock, flags); + memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * l); + smp_wmb(); + pvt->mce_in = 0; + count -= l; + m += l; + } + memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * count); + smp_wmb(); + pvt->mce_in += count; + + smp_rmb(); + if (pvt->mce_overrun) { + i7core_printk(KERN_ERR, "Lost %d memory errors\n", + pvt->mce_overrun); + smp_wmb(); + pvt->mce_overrun = 0; + } - /* proccess mcelog errors */ + /* + * MCE second step: parse errors and display + */ for (i = 0; i < count; i++) - i7core_mce_output_error(mci, &m[i]); + i7core_mce_output_error(mci, &pvt->mce_outentry[i]); - kfree(m); - - /* check memory count errors */ + /* + * Now, let's increment CE error counts + */ if (!pvt->is_registered) i7core_udimm_check_mc_ecc_err(mci); else @@ -1657,7 +1683,6 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) { struct mem_ctl_info *mci = priv; struct i7core_pvt *pvt = mci->pvt_info; - unsigned long flags; /* * Just let mcelog handle it if the error is @@ -1679,12 +1704,15 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 0; } - spin_lock_irqsave(&pvt->mce_lock, flags); - if (pvt->mce_count < MCE_LOG_LEN) { - memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); - pvt->mce_count++; + smp_rmb(); + if ((pvt->mce_out + 1) % sizeof(mce_entry) == pvt->mce_in) { + smp_wmb(); + pvt->mce_overrun++; + return 0; } - spin_unlock_irqrestore(&pvt->mce_lock, flags); + smp_wmb(); + pvt->mce_out = (pvt->mce_out + 1) % sizeof(mce_entry); + memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce)); /* Handle fatal errors immediately */ if (mce->mcgstatus & 1) @@ -1777,7 +1805,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, /* Registers on edac_mce in order to receive memory errors */ pvt->edac_mce.priv = mci; pvt->edac_mce.check_error = i7core_mce_check_error; - spin_lock_init(&pvt->mce_lock); rc = edac_mce_register(&pvt->edac_mce); if (unlikely(rc < 0)) { -- GitLab From 4f87fad1d32fcdda448f9eb430c9c234a1939ece Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Sun, 4 Oct 2009 11:54:56 -0300 Subject: [PATCH 149/842] i7core_edac: Better parse "any" addrmask Instead of accepting just "any", accept also "any\n" Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 94aeca011ac4..477b62a74dbf 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -800,7 +800,7 @@ static ssize_t i7core_inject_store_##param( \ if (pvt->inject.enable) \ disable_inject(mci); \ \ - if (!strcasecmp(data, "any")) \ + if (!strcasecmp(data, "any") || !strcasecmp(data, "any\n"))\ value = -1; \ else { \ rc = strict_strtoul(data, 10, &value); \ -- GitLab From 6e103be1c7c4adb50f25aaf1f1e8f828833c1719 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Mon, 5 Oct 2009 09:40:09 -0300 Subject: [PATCH 150/842] i7core_edac: First store, then increment Fix ringbuffer store logic. While here, add a few comments to the code and remove the undesired printk that could otherwise be called during NMI time. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 477b62a74dbf..59ec44175560 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1678,6 +1678,8 @@ static void i7core_check_error(struct mem_ctl_info *mci) * This routine simply queues mcelog errors, and * return. The error itself should be handled later * by i7core_check_error. + * WARNING: As this routine should be called at NMI time, extra care should + * be taken to avoid deadlocks, and to be as fast as possible. */ static int i7core_mce_check_error(void *priv, struct mce *mce) { @@ -1696,13 +1698,8 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 0; /* Only handle if it is the right mc controller */ - if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) { - debugf0("mc%d: ignoring mce log for socket %d. " - "Another mc should get it.\n", - pvt->i7core_dev->socket, - cpu_data(mce->cpu).phys_proc_id); + if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) return 0; - } smp_rmb(); if ((pvt->mce_out + 1) % sizeof(mce_entry) == pvt->mce_in) { @@ -1710,9 +1707,11 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) pvt->mce_overrun++; return 0; } + + /* Copy memory error at the ringbuffer */ + memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce)); smp_wmb(); pvt->mce_out = (pvt->mce_out + 1) % sizeof(mce_entry); - memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce)); /* Handle fatal errors immediately */ if (mce->mcgstatus & 1) -- GitLab From 321ece4dda32f52d4a28d6eb11f2ca2a5c93c191 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Thu, 8 Oct 2009 13:11:08 -0300 Subject: [PATCH 151/842] i7core_edac: Fix ringbuffer maxsize Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 59ec44175560..c2857f60ae6a 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1631,14 +1631,14 @@ static void i7core_check_error(struct mem_ctl_info *mci) * loosing an error. */ smp_rmb(); - count = (pvt->mce_out + sizeof(mce_entry) - pvt->mce_in) - % sizeof(mce_entry); + count = (pvt->mce_out + MCE_LOG_LEN - pvt->mce_in) + % MCE_LOG_LEN; if (!count) return; m = pvt->mce_outentry; - if (pvt->mce_in + count > sizeof(mce_entry)) { - unsigned l = sizeof(mce_entry) - pvt->mce_in; + if (pvt->mce_in + count > MCE_LOG_LEN) { + unsigned l = MCE_LOG_LEN - pvt->mce_in; memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * l); smp_wmb(); @@ -1702,7 +1702,7 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 0; smp_rmb(); - if ((pvt->mce_out + 1) % sizeof(mce_entry) == pvt->mce_in) { + if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) { smp_wmb(); pvt->mce_overrun++; return 0; @@ -1711,7 +1711,7 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) /* Copy memory error at the ringbuffer */ memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce)); smp_wmb(); - pvt->mce_out = (pvt->mce_out + 1) % sizeof(mce_entry); + pvt->mce_out = (pvt->mce_out + 1) % MCE_LOG_LEN; /* Handle fatal errors immediately */ if (mce->mcgstatus & 1) -- GitLab From fd3826549db7f73d22b9c9abb80e01effb95c2ba Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 14 Oct 2009 06:07:07 -0300 Subject: [PATCH 152/842] i7core_edac: PCI device is called NONCORE, instead of NOCORE Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 6 +++--- include/linux/pci_ids.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index c2857f60ae6a..bb538dfbdc6c 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -291,7 +291,7 @@ struct pci_id_descr pci_dev_descr[] = { * the probing code needs to test for the other address in case of * failure of this one */ - { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE) }, + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE) }, }; #define N_DEVS ARRAY_SIZE(pci_dev_descr) @@ -1177,9 +1177,9 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) * is at addr 8086:2c40, instead of 8086:2c41. So, we need * to probe for the alternate address in case of failure */ - if (pci_dev_descr[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev) + if (pci_dev_descr[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, *prev); + PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); if (!pdev) { if (*prev) { diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index bf6db4814c27..382476a8a339 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2548,8 +2548,8 @@ #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR 0x2c31 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK 0x2c32 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33 -#define PCI_DEVICE_ID_INTEL_I7_NOCORE 0x2c41 -#define PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT 0x2c40 +#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41 +#define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 #define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a -- GitLab From de06eeef5809a69ff4daaae2bd63977e5404553d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 14 Oct 2009 08:02:40 -0300 Subject: [PATCH 153/842] i7core_edac: Use a more generic approach for probing PCI devices Currently, only one PCI set of tables is allowed. This prevents using the driver for other devices like Lynnfield, with have a different set of PCI ID's. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 79 +++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index bb538dfbdc6c..b6fce2e38e3d 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -202,12 +202,14 @@ struct pci_id_descr { int dev; int func; int dev_id; + int optional; }; struct i7core_dev { struct list_head list; u8 socket; struct pci_dev **pdev; + int n_devs; struct mem_ctl_info *mci; }; @@ -259,11 +261,12 @@ static DEFINE_MUTEX(i7core_edac_lock); .func = (function), \ .dev_id = (device_id) -struct pci_id_descr pci_dev_descr[] = { +struct pci_id_descr pci_dev_descr_i7core[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, - { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM */ + /* Exists only for RDIMM */ + { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1 }, { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, /* Channel 0 */ @@ -294,7 +297,6 @@ struct pci_id_descr pci_dev_descr[] = { { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE) }, }; -#define N_DEVS ARRAY_SIZE(pci_dev_descr) /* * pci_device_id table for which devices we are looking for @@ -380,7 +382,7 @@ static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, if (!i7core_dev) return NULL; - for (i = 0; i < N_DEVS; i++) { + for (i = 0; i < i7core_dev->n_devs; i++) { if (!i7core_dev->pdev[i]) continue; @@ -1116,7 +1118,7 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev) int i; debugf0(__FILE__ ": %s()\n", __func__); - for (i = 0; i < N_DEVS; i++) { + for (i = 0; i < i7core_dev->n_devs; i++) { struct pci_dev *pdev = i7core_dev->pdev[i]; if (!pdev) continue; @@ -1138,7 +1140,7 @@ static void i7core_put_all_devices(void) i7core_put_devices(i7core_dev); } -static void i7core_xeon_pci_fixup(void) +static void i7core_xeon_pci_fixup(int dev_id) { struct pci_dev *pdev = NULL; int i; @@ -1147,8 +1149,7 @@ static void i7core_xeon_pci_fixup(void) * aren't announced by acpi. So, we need to use a legacy scan probing * to detect them */ - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_dev_descr[0].dev_id, NULL); + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL); if (unlikely(!pdev)) { for (i = 0; i < MAX_SOCKET_BUSES; i++) pcibios_scan_specific_bus(255-i); @@ -1161,7 +1162,8 @@ static void i7core_xeon_pci_fixup(void) * * Need to 'get' device 16 func 1 and func 2 */ -int i7core_get_onedevice(struct pci_dev **prev, int devno) +int i7core_get_onedevice(struct pci_dev **prev, int devno, + struct pci_id_descr *dev_descr, unsigned n_devs) { struct i7core_dev *i7core_dev; @@ -1170,14 +1172,14 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) u8 socket = 0; pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - pci_dev_descr[devno].dev_id, *prev); + dev_descr->dev_id, *prev); /* * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs * is at addr 8086:2c40, instead of 8086:2c41. So, we need * to probe for the alternate address in case of failure */ - if (pci_dev_descr[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); @@ -1187,19 +1189,13 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) return 0; } - /* - * Dev 3 function 2 only exists on chips with RDIMMs - * so, it is ok to not found it - */ - if ((pci_dev_descr[devno].dev == 3) && (pci_dev_descr[devno].func == 2)) { - *prev = pdev; + if (dev_descr->optional) return 0; - } i7core_printk(KERN_ERR, "Device not found: dev %02x.%d PCI ID %04x:%04x\n", - pci_dev_descr[devno].dev, pci_dev_descr[devno].func, - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); + dev_descr->dev, dev_descr->func, + PCI_VENDOR_ID_INTEL, dev_descr->dev_id); /* End of list, leave */ return -ENODEV; @@ -1216,11 +1212,12 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL); if (!i7core_dev) return -ENOMEM; - i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * N_DEVS, + i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs, GFP_KERNEL); if (!i7core_dev->pdev) return -ENOMEM; i7core_dev->socket = socket; + i7core_dev->n_devs = n_devs; list_add_tail(&i7core_dev->list, &i7core_edac_list); } @@ -1228,8 +1225,8 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) i7core_printk(KERN_ERR, "Duplicated device for " "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); + bus, dev_descr->dev, dev_descr->func, + PCI_VENDOR_ID_INTEL, dev_descr->dev_id); pci_dev_put(pdev); return -ENODEV; } @@ -1237,14 +1234,14 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) i7core_dev->pdev[devno] = pdev; /* Sanity check */ - if (unlikely(PCI_SLOT(pdev->devfn) != pci_dev_descr[devno].dev || - PCI_FUNC(pdev->devfn) != pci_dev_descr[devno].func)) { + if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev || + PCI_FUNC(pdev->devfn) != dev_descr->func)) { i7core_printk(KERN_ERR, "Device PCI ID %04x:%04x " "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n", - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id, + PCI_VENDOR_ID_INTEL, dev_descr->dev_id, bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), - bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func); + bus, dev_descr->dev, dev_descr->func); return -ENODEV; } @@ -1253,30 +1250,32 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) i7core_printk(KERN_ERR, "Couldn't enable " "dev %02x:%02x.%d PCI ID %04x:%04x\n", - bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func, - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); + bus, dev_descr->dev, dev_descr->func, + PCI_VENDOR_ID_INTEL, dev_descr->dev_id); return -ENODEV; } debugf0("Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n", - socket, bus, pci_dev_descr[devno].dev, - pci_dev_descr[devno].func, - PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id); + socket, bus, dev_descr->dev, + dev_descr->func, + PCI_VENDOR_ID_INTEL, dev_descr->dev_id); *prev = pdev; return 0; } -static int i7core_get_devices(void) +static int i7core_get_devices(struct pci_id_descr dev_descr[], unsigned n_devs) { - int i; + int i, rc; struct pci_dev *pdev = NULL; - for (i = 0; i < N_DEVS; i++) { + for (i = 0; i < n_devs; i++) { pdev = NULL; do { - if (i7core_get_onedevice(&pdev, i) < 0) { + rc = i7core_get_onedevice(&pdev, i, &dev_descr[i], + n_devs); + if (rc < 0) { i7core_put_all_devices(); return -ENODEV; } @@ -1298,7 +1297,7 @@ static int mci_bind_devs(struct mem_ctl_info *mci, i7core_dev->mci = mci; pvt->is_registered = 0; - for (i = 0; i < N_DEVS; i++) { + for (i = 0; i < i7core_dev->n_devs; i++) { pdev = i7core_dev->pdev[i]; if (!pdev) continue; @@ -1838,7 +1837,9 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* get the pci devices we want to reserve for our use */ mutex_lock(&i7core_edac_lock); - rc = i7core_get_devices(); + + rc = i7core_get_devices(pci_dev_descr_i7core, + ARRAY_SIZE(pci_dev_descr_i7core)); if (unlikely(rc < 0)) goto fail0; @@ -1937,7 +1938,7 @@ static int __init i7core_init(void) /* Ensure that the OPSTATE is set correctly for POLL or NMI */ opstate_init(); - i7core_xeon_pci_fixup(); + i7core_xeon_pci_fixup(pci_dev_descr_i7core[0].dev_id); pci_rc = pci_register_driver(&i7core_driver); -- GitLab From 486dd09f129da01cd02b212ba48dce987488b860 Mon Sep 17 00:00:00 2001 From: Alan Cox <alan@linux.intel.com> Date: Sun, 8 Nov 2009 01:34:27 -0200 Subject: [PATCH 154/842] edac: i7core_edac produces undefined behaviour on 32bit Fix the shifts up Signed-off-by: Alan Cox <alan@linux.intel.com> Acked-by: Doug Thompson <dougthompson@xmission.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index b6fce2e38e3d..bd7c727030a3 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -916,41 +916,41 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, /* Sets pvt->inject.dimm mask */ if (pvt->inject.dimm < 0) - mask |= 1L << 41; + mask |= 1LL << 41; else { if (pvt->channel[pvt->inject.channel].dimms > 2) - mask |= (pvt->inject.dimm & 0x3L) << 35; + mask |= (pvt->inject.dimm & 0x3LL) << 35; else - mask |= (pvt->inject.dimm & 0x1L) << 36; + mask |= (pvt->inject.dimm & 0x1LL) << 36; } /* Sets pvt->inject.rank mask */ if (pvt->inject.rank < 0) - mask |= 1L << 40; + mask |= 1LL << 40; else { if (pvt->channel[pvt->inject.channel].dimms > 2) - mask |= (pvt->inject.rank & 0x1L) << 34; + mask |= (pvt->inject.rank & 0x1LL) << 34; else - mask |= (pvt->inject.rank & 0x3L) << 34; + mask |= (pvt->inject.rank & 0x3LL) << 34; } /* Sets pvt->inject.bank mask */ if (pvt->inject.bank < 0) - mask |= 1L << 39; + mask |= 1LL << 39; else - mask |= (pvt->inject.bank & 0x15L) << 30; + mask |= (pvt->inject.bank & 0x15LL) << 30; /* Sets pvt->inject.page mask */ if (pvt->inject.page < 0) - mask |= 1L << 38; + mask |= 1LL << 38; else - mask |= (pvt->inject.page & 0xffffL) << 14; + mask |= (pvt->inject.page & 0xffff) << 14; /* Sets pvt->inject.column mask */ if (pvt->inject.col < 0) - mask |= 1L << 37; + mask |= 1LL << 37; else - mask |= (pvt->inject.col & 0x3fffL); + mask |= (pvt->inject.col & 0x3fff); /* * bit 0: REPEAT_EN -- GitLab From 3b918c12df4f624140456d6c6f982bada8e1f095 Mon Sep 17 00:00:00 2001 From: Randy Dunlap <randy.dunlap@oracle.com> Date: Sun, 8 Nov 2009 01:36:40 -0200 Subject: [PATCH 155/842] edac: fix i7core build Fix build warning (missing header file) and build error when CONFIG_SMP=n. drivers/edac/i7core_edac.c:860: error: implicit declaration of function 'msleep' drivers/edac/i7core_edac.c:1700: error: 'struct cpuinfo_x86' has no member named 'phys_proc_id' Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index bd7c727030a3..e944b63d9f06 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -25,6 +25,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/delay.h> #include <linux/edac.h> #include <linux/mmzone.h> #include <linux/edac_mce.h> @@ -1696,9 +1697,11 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) if (mce->bank != 8) return 0; +#ifdef CONFIG_SMP /* Only handle if it is the right mc controller */ if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) return 0; +#endif smp_rmb(); if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) { -- GitLab From 4f7b9e7cbe68c97dbe1266709ecfc8b807b0d0ee Mon Sep 17 00:00:00 2001 From: Stephen Rothwell <sfr@canb.auug.org.au> Date: Fri, 4 Dec 2009 16:49:34 -0200 Subject: [PATCH 156/842] i7core_edac: do not export static functions Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- arch/x86/pci/legacy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c index d6cc2eddf339..8d460eaf524f 100644 --- a/arch/x86/pci/legacy.c +++ b/arch/x86/pci/legacy.c @@ -35,7 +35,6 @@ int __init pci_legacy_init(void) return 0; } -EXPORT_SYMBOL_GPL(pci_legacy_init); void pcibios_scan_specific_bus(int busn) { -- GitLab From 52a2e4fc3712d12888decd386d78ad526078a1fa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 14 Oct 2009 11:21:58 -0300 Subject: [PATCH 157/842] i7core_edac: Add initial support for Lynnfield Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 39 ++++++++++++++++++++++++++++++++++++-- include/linux/pci_ids.h | 15 +++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e944b63d9f06..e525d571cb25 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -299,11 +299,30 @@ struct pci_id_descr pci_dev_descr_i7core[] = { }; +struct pci_id_descr pci_dev_descr_lynnfield[] = { + { PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR) }, + { PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD) }, + { PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST) }, + + { PCI_DESCR( 4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL) }, + { PCI_DESCR( 4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR) }, + { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK) }, + { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC) }, + + { PCI_DESCR( 4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL) }, + { PCI_DESCR( 4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) }, + { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, + { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, + + { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) }, +}; + /* * pci_device_id table for which devices we are looking for */ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE)}, {0,} /* 0 terminated list. */ }; @@ -522,6 +541,9 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) for (i = 0; i < NUM_CHANS; i++) { u32 data, dimm_dod[3], value[8]; + if (!pvt->pci_ch[i][0]) + continue; + if (!CH_ACTIVE(pvt, i)) { debugf0("Channel %i is not active\n", i); continue; @@ -1001,6 +1023,9 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, struct i7core_pvt *pvt = mci->pvt_info; u32 injectmask; + if (!pvt->pci_ch[pvt->inject.channel][0]) + return 0; + pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], MC_CHANNEL_ERROR_INJECT, &injectmask); @@ -1841,8 +1866,18 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* get the pci devices we want to reserve for our use */ mutex_lock(&i7core_edac_lock); - rc = i7core_get_devices(pci_dev_descr_i7core, - ARRAY_SIZE(pci_dev_descr_i7core)); + if (pdev->device == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) { + printk(KERN_INFO "i7core_edac: detected a " + "Lynnfield processor\n"); + rc = i7core_get_devices(pci_dev_descr_lynnfield, + ARRAY_SIZE(pci_dev_descr_lynnfield)); + } else { + printk(KERN_INFO "i7core_edac: detected a " + "Nehalem/Nehalem-EP processor\n"); + rc = i7core_get_devices(pci_dev_descr_i7core, + ARRAY_SIZE(pci_dev_descr_i7core)); + } + if (unlikely(rc < 0)) goto fail0; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 382476a8a339..ebc0fa4c7a66 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2550,6 +2550,21 @@ #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33 #define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41 #define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE 0x2c50 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_SAD 0x2c81 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0 0x2c90 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_PHY0 0x2c91 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR 0x2c98 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD 0x2c99 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST 0x2c9C +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL 0x2ca0 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR 0x2ca1 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK 0x2ca2 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC 0x2ca3 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL 0x2ca8 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR 0x2ca9 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK 0x2caa +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC 0x2cab #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 #define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a -- GitLab From f05da2f7855b3b88a831ca79e037245872549ec0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 14 Oct 2009 13:31:06 -0300 Subject: [PATCH 158/842] i7core: add support for Lynnfield alternate address Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 13 +++++++++++-- include/linux/pci_ids.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e525d571cb25..d3f5c016c5eb 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -314,6 +314,10 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = { { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, + /* + * This is the PCI device has an alternate address on some + * processors like Core i7 860 + */ { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) }, }; @@ -322,7 +326,7 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = { */ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0)}, {0,} /* 0 terminated list. */ }; @@ -1209,6 +1213,11 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT, + *prev); + if (!pdev) { if (*prev) { *prev = pdev; @@ -1866,7 +1875,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* get the pci devices we want to reserve for our use */ mutex_lock(&i7core_edac_lock); - if (pdev->device == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) { + if (pdev->device == PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0) { printk(KERN_INFO "i7core_edac: detected a " "Lynnfield processor\n"); rc = i7core_get_devices(pci_dev_descr_lynnfield, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ebc0fa4c7a66..e67cb20b8401 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2551,6 +2551,7 @@ #define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41 #define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE 0x2c50 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT 0x2c51 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_SAD 0x2c81 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0 0x2c90 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_PHY0 0x2c91 -- GitLab From 508fa179f8e0da5d7241e12ad1562b96f291e800 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Wed, 14 Oct 2009 13:44:37 -0300 Subject: [PATCH 159/842] i7core_edac: Fix wrong device id for channel 1 devices Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index d3f5c016c5eb..4d6ecf1291b8 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -309,10 +309,10 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = { { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK) }, { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC) }, - { PCI_DESCR( 4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL) }, - { PCI_DESCR( 4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) }, - { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, - { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, + { PCI_DESCR( 5, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL) }, + { PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) }, + { PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, + { PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, /* * This is the PCI device has an alternate address on some -- GitLab From 58645c7f36b22d1c7b5ed966ce3f01129fa87813 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: Tue, 11 May 2010 16:22:50 +0000 Subject: [PATCH 160/842] powerpc/44x: Fix UART clocks on 440SPe The code to fixup the serial ports on 440SPe uses the incorrect addresses for these. This fixes it. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Acked-by: Stefan Roese <sr@denx.de> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com> --- arch/powerpc/boot/4xx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/boot/4xx.c b/arch/powerpc/boot/4xx.c index 27db8938827a..9d3bd4c45a24 100644 --- a/arch/powerpc/boot/4xx.c +++ b/arch/powerpc/boot/4xx.c @@ -519,7 +519,7 @@ void ibm440ep_fixup_clocks(unsigned int sys_clk, { unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 0); - /* serial clocks beed fixup based on int/ext */ + /* serial clocks need fixup based on int/ext */ eplike_fixup_uart_clk(0, "/plb/opb/serial@ef600300", ser_clk, plb_clk); eplike_fixup_uart_clk(1, "/plb/opb/serial@ef600400", ser_clk, plb_clk); eplike_fixup_uart_clk(2, "/plb/opb/serial@ef600500", ser_clk, plb_clk); @@ -532,7 +532,7 @@ void ibm440gx_fixup_clocks(unsigned int sys_clk, { unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1); - /* serial clocks beed fixup based on int/ext */ + /* serial clocks need fixup based on int/ext */ eplike_fixup_uart_clk(0, "/plb/opb/serial@40000200", ser_clk, plb_clk); eplike_fixup_uart_clk(1, "/plb/opb/serial@40000300", ser_clk, plb_clk); } @@ -543,10 +543,10 @@ void ibm440spe_fixup_clocks(unsigned int sys_clk, { unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1); - /* serial clocks beed fixup based on int/ext */ - eplike_fixup_uart_clk(0, "/plb/opb/serial@10000200", ser_clk, plb_clk); - eplike_fixup_uart_clk(1, "/plb/opb/serial@10000300", ser_clk, plb_clk); - eplike_fixup_uart_clk(2, "/plb/opb/serial@10000600", ser_clk, plb_clk); + /* serial clocks need fixup based on int/ext */ + eplike_fixup_uart_clk(0, "/plb/opb/serial@f0000200", ser_clk, plb_clk); + eplike_fixup_uart_clk(1, "/plb/opb/serial@f0000300", ser_clk, plb_clk); + eplike_fixup_uart_clk(2, "/plb/opb/serial@f0000600", ser_clk, plb_clk); } void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk) -- GitLab From a89eda26753311d8ff2da64da621714b2f8d5dcc Mon Sep 17 00:00:00 2001 From: Stefan Roese <sr@denx.de> Date: Tue, 11 May 2010 03:55:34 +0000 Subject: [PATCH 161/842] powerpc/44x: Add basic ICON PPC440SPe board support ICON is based on the AppliedMicro 440SPe. It is equipped with 64MByte NOR FLASH, SODIMM, Gigabit ethernet, SM502 on PCI(X), LSI SAS1068E on PCIe0 and custom FPGA on PCIe1. Signed-off-by: Stefan Roese <sr@denx.de> Cc: Josh Boyer <jwboyer@linux.vnet.ibm.com> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com> --- arch/powerpc/boot/dts/icon.dts | 447 +++++++ arch/powerpc/configs/44x/icon_defconfig | 1316 ++++++++++++++++++++ arch/powerpc/platforms/44x/Kconfig | 11 + arch/powerpc/platforms/44x/ppc44x_simple.c | 3 +- 4 files changed, 1776 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/boot/dts/icon.dts create mode 100644 arch/powerpc/configs/44x/icon_defconfig diff --git a/arch/powerpc/boot/dts/icon.dts b/arch/powerpc/boot/dts/icon.dts new file mode 100644 index 000000000000..abcd0caeccae --- /dev/null +++ b/arch/powerpc/boot/dts/icon.dts @@ -0,0 +1,447 @@ +/* + * Device Tree Source for Mosaix Technologies, Inc. ICON board + * + * Copyright 2010 DENX Software Engineering, Stefan Roese <sr@denx.de> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "mosaixtech,icon"; + compatible = "mosaixtech,icon"; + dcr-parent = <&{/cpus/cpu@0}>; + + aliases { + ethernet0 = &EMAC0; + serial0 = &UART0; + serial1 = &UART1; + serial2 = &UART2; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "PowerPC,440SPe"; + reg = <0x00000000>; + clock-frequency = <0>; /* Filled in by U-Boot */ + timebase-frequency = <0>; /* Filled in by U-Boot */ + i-cache-line-size = <32>; + d-cache-line-size = <32>; + i-cache-size = <32768>; + d-cache-size = <32768>; + dcr-controller; + dcr-access-method = "native"; + reset-type = <2>; /* Use chip-reset */ + }; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x00000000 0x0 0x00000000>; /* Filled in by U-Boot */ + }; + + UIC0: interrupt-controller0 { + compatible = "ibm,uic-440spe","ibm,uic"; + interrupt-controller; + cell-index = <0>; + dcr-reg = <0x0c0 0x009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + }; + + UIC1: interrupt-controller1 { + compatible = "ibm,uic-440spe","ibm,uic"; + interrupt-controller; + cell-index = <1>; + dcr-reg = <0x0d0 0x009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */ + interrupt-parent = <&UIC0>; + }; + + UIC2: interrupt-controller2 { + compatible = "ibm,uic-440spe","ibm,uic"; + interrupt-controller; + cell-index = <2>; + dcr-reg = <0x0e0 0x009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <0xa 0x4 0xb 0x4>; /* cascade */ + interrupt-parent = <&UIC0>; + }; + + UIC3: interrupt-controller3 { + compatible = "ibm,uic-440spe","ibm,uic"; + interrupt-controller; + cell-index = <3>; + dcr-reg = <0x0f0 0x009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <0x10 0x4 0x11 0x4>; /* cascade */ + interrupt-parent = <&UIC0>; + }; + + SDR0: sdr { + compatible = "ibm,sdr-440spe"; + dcr-reg = <0x00e 0x002>; + }; + + CPR0: cpr { + compatible = "ibm,cpr-440spe"; + dcr-reg = <0x00c 0x002>; + }; + + MQ0: mq { + compatible = "ibm,mq-440spe"; + dcr-reg = <0x040 0x020>; + }; + + plb { + compatible = "ibm,plb-440spe", "ibm,plb-440gp", "ibm,plb4"; + #address-cells = <2>; + #size-cells = <1>; + /* addr-child addr-parent size */ + ranges = <0x4 0x00100000 0x4 0x00100000 0x00001000 + 0x4 0x00200000 0x4 0x00200000 0x00000400 + 0x4 0xe0000000 0x4 0xe0000000 0x20000000 + 0xc 0x00000000 0xc 0x00000000 0x20000000 + 0xd 0x00000000 0xd 0x00000000 0x80000000 + 0xd 0x80000000 0xd 0x80000000 0x80000000 + 0xe 0x00000000 0xe 0x00000000 0x80000000 + 0xe 0x80000000 0xe 0x80000000 0x80000000 + 0xf 0x00000000 0xf 0x00000000 0x80000000 + 0xf 0x80000000 0xf 0x80000000 0x80000000>; + clock-frequency = <0>; /* Filled in by U-Boot */ + + SDRAM0: sdram { + compatible = "ibm,sdram-440spe", "ibm,sdram-405gp"; + dcr-reg = <0x010 0x002>; + }; + + MAL0: mcmal { + compatible = "ibm,mcmal-440spe", "ibm,mcmal2"; + dcr-reg = <0x180 0x062>; + num-tx-chans = <2>; + num-rx-chans = <1>; + interrupt-parent = <&MAL0>; + interrupts = <0x0 0x1 0x2 0x3 0x4>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = </*TXEOB*/ 0x0 &UIC1 0x6 0x4 + /*RXEOB*/ 0x1 &UIC1 0x7 0x4 + /*SERR*/ 0x2 &UIC1 0x1 0x4 + /*TXDE*/ 0x3 &UIC1 0x2 0x4 + /*RXDE*/ 0x4 &UIC1 0x3 0x4>; + }; + + POB0: opb { + compatible = "ibm,opb-440spe", "ibm,opb-440gp", "ibm,opb"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xe0000000 0x00000004 0xe0000000 0x20000000>; + clock-frequency = <0>; /* Filled in by U-Boot */ + + EBC0: ebc { + compatible = "ibm,ebc-440spe", "ibm,ebc-440gp", "ibm,ebc"; + dcr-reg = <0x012 0x002>; + #address-cells = <2>; + #size-cells = <1>; + clock-frequency = <0>; /* Filled in by U-Boot */ + /* ranges property is supplied by U-Boot */ + interrupts = <0x5 0x1>; + interrupt-parent = <&UIC1>; + + nor_flash@0,0 { + compatible = "cfi-flash"; + bank-width = <2>; + reg = <0x00000000 0x00000000 0x01000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "kernel"; + reg = <0x00000000 0x001e0000>; + }; + partition@1e0000 { + label = "dtb"; + reg = <0x001e0000 0x00020000>; + }; + partition@200000 { + label = "root"; + reg = <0x00200000 0x00200000>; + }; + partition@400000 { + label = "user"; + reg = <0x00400000 0x00b60000>; + }; + partition@f60000 { + label = "env"; + reg = <0x00f60000 0x00040000>; + }; + partition@fa0000 { + label = "u-boot"; + reg = <0x00fa0000 0x00060000>; + }; + }; + + SysACE_CompactFlash: sysace@1,0 { + compatible = "xlnx,sysace"; + interrupt-parent = <&UIC2>; + interrupts = <24 0x4>; + reg = <0x00000001 0x00000000 0x10000>; + }; + }; + + UART0: serial@f0000200 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0xf0000200 0x00000008>; + virtual-reg = <0xa0000200>; + clock-frequency = <0>; /* Filled in by U-Boot */ + current-speed = <115200>; + interrupt-parent = <&UIC0>; + interrupts = <0x0 0x4>; + }; + + UART1: serial@f0000300 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0xf0000300 0x00000008>; + virtual-reg = <0xa0000300>; + clock-frequency = <0>; + current-speed = <0>; + interrupt-parent = <&UIC0>; + interrupts = <0x1 0x4>; + }; + + + UART2: serial@f0000600 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0xf0000600 0x00000008>; + virtual-reg = <0xa0000600>; + clock-frequency = <0>; + current-speed = <0>; + interrupt-parent = <&UIC1>; + interrupts = <0x5 0x4>; + }; + + IIC0: i2c@f0000400 { + compatible = "ibm,iic-440spe", "ibm,iic-440gp", "ibm,iic"; + reg = <0xf0000400 0x00000014>; + interrupt-parent = <&UIC0>; + interrupts = <0x2 0x4>; + }; + + IIC1: i2c@f0000500 { + compatible = "ibm,iic-440spe", "ibm,iic-440gp", "ibm,iic"; + reg = <0xf0000500 0x00000014>; + interrupt-parent = <&UIC0>; + interrupts = <0x3 0x4>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@68 { + compatible = "stm,m41t00"; + reg = <0x68>; + }; + }; + + EMAC0: ethernet@f0000800 { + linux,network-index = <0x0>; + device_type = "network"; + compatible = "ibm,emac-440spe", "ibm,emac4"; + interrupt-parent = <&UIC1>; + interrupts = <0x1c 0x4 0x1d 0x4>; + reg = <0xf0000800 0x00000074>; + local-mac-address = [000000000000]; + mal-device = <&MAL0>; + mal-tx-channel = <0>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <9000>; + rx-fifo-size = <4096>; + tx-fifo-size = <2048>; + phy-mode = "gmii"; + phy-map = <0x00000000>; + has-inverted-stacr-oc; + has-new-stacr-staopc; + }; + }; + + PCIX0: pci@c0ec00000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pcix-440spe", "ibm,plb-pcix"; + primary; + large-inbound-windows; + enable-msi-hole; + reg = <0x0000000c 0x0ec00000 0x00000008 /* Config space access */ + 0x00000000 0x00000000 0x00000000 /* no IACK cycles */ + 0x0000000c 0x0ed00000 0x00000004 /* Special cycles */ + 0x0000000c 0x0ec80000 0x00000100 /* Internal registers */ + 0x0000000c 0x0ec80100 0x000000fc>; /* Internal messaging registers */ + + /* Outbound ranges, one memory and one IO, + * later cannot be changed + */ + ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000 + 0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>; + + /* Inbound 4GB range starting at 0 */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>; + + /* This drives busses 0 to 0xf */ + bus-range = <0x0 0xf>; + + /* PCI-X interrupt (SM502) is routed to extIRQ10 (UIC1, 19) */ + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &UIC1 19 0x8>; + }; + + PCIE0: pciex@d00000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex"; + primary; + port = <0x0>; /* port number */ + reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */ + 0x0000000c 0x10000000 0x00001000>; /* Registers */ + dcr-reg = <0x100 0x020>; + sdr-base = <0x300>; + + /* Outbound ranges, one memory and one IO, + * later cannot be changed + */ + ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000 + 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>; + + /* Inbound 4GB range starting at 0 */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>; + + /* This drives busses 0x10 to 0x1f */ + bus-range = <0x10 0x1f>; + + /* Legacy interrupts (note the weird polarity, the bridge seems + * to invert PCIe legacy interrupts). + * We are de-swizzling here because the numbers are actually for + * port of the root complex virtual P2P bridge. But I want + * to avoid putting a node for it in the tree, so the numbers + * below are basically de-swizzled numbers. + * The real slot is on idsel 0, so the swizzling is 1:1 + */ + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = < + 0x0 0x0 0x0 0x1 &UIC3 0x0 0x4 /* swizzled int A */ + 0x0 0x0 0x0 0x2 &UIC3 0x1 0x4 /* swizzled int B */ + 0x0 0x0 0x0 0x3 &UIC3 0x2 0x4 /* swizzled int C */ + 0x0 0x0 0x0 0x4 &UIC3 0x3 0x4 /* swizzled int D */>; + }; + + PCIE1: pciex@d20000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex"; + primary; + port = <0x1>; /* port number */ + reg = <0x0000000d 0x20000000 0x20000000 /* Config space access */ + 0x0000000c 0x10001000 0x00001000>; /* Registers */ + dcr-reg = <0x120 0x020>; + sdr-base = <0x340>; + + /* Outbound ranges, one memory and one IO, + * later cannot be changed + */ + ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000 + 0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>; + + /* Inbound 4GB range starting at 0 */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>; + + /* This drives busses 0x20 to 0x2f */ + bus-range = <0x20 0x2f>; + + /* Legacy interrupts (note the weird polarity, the bridge seems + * to invert PCIe legacy interrupts). + * We are de-swizzling here because the numbers are actually for + * port of the root complex virtual P2P bridge. But I want + * to avoid putting a node for it in the tree, so the numbers + * below are basically de-swizzled numbers. + * The real slot is on idsel 0, so the swizzling is 1:1 + */ + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = < + 0x0 0x0 0x0 0x1 &UIC3 0x4 0x4 /* swizzled int A */ + 0x0 0x0 0x0 0x2 &UIC3 0x5 0x4 /* swizzled int B */ + 0x0 0x0 0x0 0x3 &UIC3 0x6 0x4 /* swizzled int C */ + 0x0 0x0 0x0 0x4 &UIC3 0x7 0x4 /* swizzled int D */>; + }; + + I2O: i2o@400100000 { + compatible = "ibm,i2o-440spe"; + reg = <0x00000004 0x00100000 0x100>; + dcr-reg = <0x060 0x020>; + }; + + DMA0: dma0@400100100 { + compatible = "ibm,dma-440spe"; + cell-index = <0>; + reg = <0x00000004 0x00100100 0x100>; + dcr-reg = <0x060 0x020>; + interrupt-parent = <&DMA0>; + interrupts = <0 1>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = < + 0 &UIC0 0x14 4 + 1 &UIC1 0x16 4>; + }; + + DMA1: dma1@400100200 { + compatible = "ibm,dma-440spe"; + cell-index = <1>; + reg = <0x00000004 0x00100200 0x100>; + dcr-reg = <0x060 0x020>; + interrupt-parent = <&DMA1>; + interrupts = <0 1>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = < + 0 &UIC0 0x16 4 + 1 &UIC1 0x16 4>; + }; + + xor-accel@400200000 { + compatible = "amcc,xor-accelerator"; + reg = <0x00000004 0x00200000 0x400>; + interrupt-parent = <&UIC1>; + interrupts = <0x1f 4>; + }; + }; + + chosen { + linux,stdout-path = "/plb/opb/serial@f0000200"; + }; +}; diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig new file mode 100644 index 000000000000..40a755b65939 --- /dev/null +++ b/arch/powerpc/configs/44x/icon_defconfig @@ -0,0 +1,1316 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.34-rc5 +# Mon Apr 26 16:44:40 2010 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_PPC_BOOK3S_32 is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +CONFIG_44x=y +# CONFIG_E200 is not set +CONFIG_4xx=y +CONFIG_BOOKE=y +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y +CONFIG_PPC_MMU_NOHASH=y +CONFIG_PPC_MMU_NOHASH_32=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_PPC32=y +CONFIG_WORD_SIZE=32 +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_MMU=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set +# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set +CONFIG_IRQ_PER_CPU=y +CONFIG_NR_IRQS=512 +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +CONFIG_PPC_UDBG_16550=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DTC=y +# CONFIG_DEFAULT_UIMAGE is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_PPC_DCR_NATIVE=y +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_DCR=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_PPC_ADV_DEBUG_REGS=y +CONFIG_PPC_ADV_DEBUG_IACS=4 +CONFIG_PPC_ADV_DEBUG_DACS=2 +CONFIG_PPC_ADV_DEBUG_DVCS=2 +CONFIG_PPC_ADV_DEBUG_DAC_RANGE=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TINY_RCU is not set +# CONFIG_RCU_TRACE is not set +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +# CONFIG_LOGBUFFER is not set +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_HAVE_PERF_EVENTS=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_PCI_QUIRKS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_API_DEBUG=y + +# +# GCOV-based kernel profiling +# +# CONFIG_SLOW_WORK is not set +# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_FREEZER is not set +CONFIG_PPC4xx_PCI_EXPRESS=y + +# +# Platform support +# +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +# CONFIG_BAMBOO is not set +# CONFIG_EBONY is not set +# CONFIG_SAM440EP is not set +# CONFIG_SEQUOIA is not set +# CONFIG_TAISHAN is not set +# CONFIG_KATMAI is not set +# CONFIG_RAINIER is not set +# CONFIG_WARP is not set +# CONFIG_ARCHES is not set +# CONFIG_CANYONLANDS is not set +# CONFIG_GLACIER is not set +# CONFIG_REDWOOD is not set +# CONFIG_EIGER is not set +# CONFIG_YOSEMITE is not set +CONFIG_ICON=y +# CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set +CONFIG_PPC44x_SIMPLE=y +# CONFIG_PPC4xx_GPIO is not set +CONFIG_440SPe=y +CONFIG_STDBINUTILS=y +# CONFIG_IPIC is not set +# CONFIG_MPIC is not set +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_FSL_ULI1575 is not set +# CONFIG_SIMPLE_GPIO is not set + +# +# Kernel options +# +CONFIG_HIGHMEM=y +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_SCHED_HRTICK is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_MATH_EMULATION is not set +# CONFIG_IOMMU_HELPER is not set +# CONFIG_SWIOTLB is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_HAS_WALK_MEMORY=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_SPARSE_IRQ=y +CONFIG_MAX_ACTIVE_REGIONS=32 +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_PROC_DEVICETREE=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="" +CONFIG_EXTRA_TARGETS="" +# CONFIG_ARCH_HAS_NMI_WATCHDOG is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_4xx_SOC=y +CONFIG_PPC_PCI_CHOICE=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +CONFIG_ARCH_SUPPORTS_MSI=y +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCCARD is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HAS_RAPIDIO is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_PAGE_OFFSET=0xc0000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_PHYSICAL_START=0x00000000 +CONFIG_TASK_SIZE=0xc0000000 +CONFIG_CONSISTENT_SIZE=0x00200000 +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_DEVICE=y +CONFIG_OF_I2C=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=35000 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_XILINX_SYSACE=y +# CONFIG_BLK_DEV_HD is not set +# CONFIG_MISC_DEVICES is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +CONFIG_SCSI_SAS_ATTRS=y +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_FUSION=y +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +CONFIG_FUSION_SAS=y +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_CTL=y +CONFIG_FUSION_LOGGING=y + +# +# IEEE 1394 (FireWire) support +# + +# +# You can enable one or both FireWire driver stacks. +# + +# +# The newer stack is recommended. +# +# CONFIG_FIREWIRE is not set +# CONFIG_IEEE1394 is not set +# CONFIG_I2O is not set +# CONFIG_MACINTOSH_DRIVERS is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_ARCNET is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_ETHOC is not set +# CONFIG_DNET is not set +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_IBM_NEW_EMAC=y +CONFIG_IBM_NEW_EMAC_RXB=128 +CONFIG_IBM_NEW_EMAC_TXB=64 +CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32 +CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256 +CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0 +# CONFIG_IBM_NEW_EMAC_DEBUG is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +CONFIG_IBM_NEW_EMAC_EMAC4=y +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_NET_PCI is not set +# CONFIG_B44 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_ATL2 is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_PCI is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_HVC_UDBG is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_BOOTCOUNT is not set +# CONFIG_DISPLAY_PDSP1880 is not set +# CONFIG_MUCMC52_IO is not set +# CONFIG_UC101_IO is not set +# CONFIG_SRAM is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +CONFIG_I2C_IBM_IIC=y +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_SPI is not set + +# +# PPS support +# +# CONFIG_PPS is not set +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_LPC_SCH is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_AGP is not set +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=m +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_SOUND is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_UWB is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=y +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# TI VLYNQ +# +# CONFIG_STAGING is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4_FS is not set +CONFIG_JBD=y +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_YAFFS_FS is not set +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=y +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +CONFIG_NLS_ISO8859_15=y +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_HAVE_LMB=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +# CONFIG_BOOT_TRACER is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_PPC_DISABLE_WERROR is not set +CONFIG_PPC_WERROR=y +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_XMON is not set +# CONFIG_IRQSTACKS is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_PPC_EARLY_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_PCBC=y +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_PPC4XX is not set +# CONFIG_PPC_CLOCK is not set +# CONFIG_VIRTUALIZATION is not set diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index eeba0a70e466..69d668c072ae 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -171,6 +171,17 @@ config ISS4xx help This option enables support for the IBM ISS simulation environment +config ICON + bool "Icon" + depends on 44x + default n + select PPC44x_SIMPLE + select 440SPe + select PCI + select PPC4xx_PCI_EXPRESS + help + This option enables support for the AMCC PPC440SPe evaluation board. + #config LUAN # bool "Luan" # depends on 44x diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c index e8c23ccaa1fc..5f7a29d7f590 100644 --- a/arch/powerpc/platforms/44x/ppc44x_simple.c +++ b/arch/powerpc/platforms/44x/ppc44x_simple.c @@ -61,7 +61,8 @@ static char *board[] __initdata = { "amcc,redwood", "amcc,sequoia", "amcc,taishan", - "amcc,yosemite" + "amcc,yosemite", + "mosaixtech,icon" }; static int __init ppc44x_probe(void) -- GitLab From 71753e0141a220ecbf9c71a66e0a8acce9705fb5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Wed, 9 Dec 2009 16:55:15 -0300 Subject: [PATCH 162/842] EDAC: add __init to i7core_xeon_pci_fixup It's called only from an __init function and is the only user of pcibios_scan_specific_bus which will be marked as __devinit in the next patch. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 4d6ecf1291b8..37ade251e9e2 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1170,7 +1170,7 @@ static void i7core_put_all_devices(void) i7core_put_devices(i7core_dev); } -static void i7core_xeon_pci_fixup(int dev_id) +static void __init i7core_xeon_pci_fixup(int dev_id) { struct pci_dev *pdev = NULL; int i; -- GitLab From 2a6fae326713ec84f307c045f6b497d4afaeb1d4 Mon Sep 17 00:00:00 2001 From: Alexander Beregalov <a.beregalov@gmail.com> Date: Thu, 7 Jan 2010 23:27:30 -0300 Subject: [PATCH 163/842] i7core_edac: fix memory leak of i7core_dev Free already allocated i7core_dev. Signed-off-by: Alexander Beregalov <a.beregalov@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 37ade251e9e2..8e93df637bca 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1249,8 +1249,10 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, return -ENOMEM; i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs, GFP_KERNEL); - if (!i7core_dev->pdev) + if (!i7core_dev->pdev) { + kfree(i7core_dev); return -ENOMEM; + } i7core_dev->socket = socket; i7core_dev->n_devs = n_devs; list_add_tail(&i7core_dev->list, &i7core_edac_list); -- GitLab From 8a311e179e52d122ac203d8e88014284c18ca8ab Mon Sep 17 00:00:00 2001 From: Vernon Mauery <vernux@us.ibm.com> Date: Fri, 16 Apr 2010 19:40:19 -0300 Subject: [PATCH 164/842] Always call i7core_[ur]dimm_check_mc_ecc_err This fixes an error in function i7core_check_error In commit ca9c90ba09ca3c9799319f46a56f397afbf617c2 which converts the driver to use double buffering, there is a change in the logic. Before, if mce_count was zero, it skipped over a couple of statements and finished out with a call to the *check_mc_ecc_err function. The current code checks to see if mce_count is 0 and then exits. This change reverts the behavior back to the original where if there are no errors to report, we skip to the end and call the *check_mc_ecc_err function. This fix allows the driver to work again on my Nehalem based blades again. Signed-off-by: Vernon Mauery <vernux@us.ibm.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 8e93df637bca..cd51709c4d89 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1670,7 +1670,7 @@ static void i7core_check_error(struct mem_ctl_info *mci) count = (pvt->mce_out + MCE_LOG_LEN - pvt->mce_in) % MCE_LOG_LEN; if (!count) - return; + goto check_ce_error; m = pvt->mce_outentry; if (pvt->mce_in + count > MCE_LOG_LEN) { @@ -1703,6 +1703,7 @@ static void i7core_check_error(struct mem_ctl_info *mci) /* * Now, let's increment CE error counts */ +check_ce_error: if (!pvt->is_registered) i7core_udimm_check_mc_ecc_err(mci); else -- GitLab From ac1ececea995fd77c8da6a1299674f22991cecaa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Tue, 18 May 2010 13:00:31 -0300 Subject: [PATCH 165/842] i7core_edac: Add support for X5670 As reported by Vernon Mauery <vernux@us.ibm.com>, X5670 (Westmere-EP) uses a different register for one of the uncore PCI devices. Add support for it. Those are the PCI ID's on this new chipset: fe:00.0 0600: 8086:2c70 (rev 02) fe:00.1 0600: 8086:2d81 (rev 02) fe:02.0 0600: 8086:2d90 (rev 02) fe:02.1 0600: 8086:2d91 (rev 02) fe:02.2 0600: 8086:2d92 (rev 02) fe:02.3 0600: 8086:2d93 (rev 02) fe:02.4 0600: 8086:2d94 (rev 02) fe:02.5 0600: 8086:2d95 (rev 02) fe:03.0 0600: 8086:2d98 (rev 02) fe:03.1 0600: 8086:2d99 (rev 02) fe:03.2 0600: 8086:2d9a (rev 02) fe:03.4 0600: 8086:2d9c (rev 02) fe:04.0 0600: 8086:2da0 (rev 02) fe:04.1 0600: 8086:2da1 (rev 02) fe:04.2 0600: 8086:2da2 (rev 02) fe:04.3 0600: 8086:2da3 (rev 02) fe:05.0 0600: 8086:2da8 (rev 02) fe:05.1 0600: 8086:2da9 (rev 02) fe:05.2 0600: 8086:2daa (rev 02) fe:05.3 0600: 8086:2dab (rev 02) fe:06.0 0600: 8086:2db0 (rev 02) fe:06.1 0600: 8086:2db1 (rev 02) fe:06.2 0600: 8086:2db2 (rev 02) fe:06.3 0600: 8086:2db3 (rev 02) (as usual, the same PCI devices repeat at ff: bus) The PCI device 8086:2c70 is shown as: fe:00.0 Host bridge: Intel Corporation QuickPath Architecture Generic Non-core Registers (rev 02) So, for this device to be recognized, it is only a matter of adding this new PCI ID to the driver. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 7 ++++++- include/linux/pci_ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index cd51709c4d89..82acfbd01779 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1213,10 +1213,15 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); - if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT, *prev); + if (!pdev) + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2, + *prev); + } if (!pdev) { if (*prev) { diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index e67cb20b8401..46d76e985bac 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2552,6 +2552,7 @@ #define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE 0x2c50 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT 0x2c51 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2 0x2c70 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_SAD 0x2c81 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0 0x2c90 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_PHY0 0x2c91 -- GitLab From d4d1ef4515cca074d5bbe1c63420822d6b20fe63 Mon Sep 17 00:00:00 2001 From: Tony Luck <tony.luck@intel.com> Date: Tue, 18 May 2010 10:53:25 -0300 Subject: [PATCH 166/842] i7core_edac: don't free on success Signed-off-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 82acfbd01779..3e2b5379bc05 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1856,7 +1856,8 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, } fail: - edac_mc_free(mci); + if (rc < 0) + edac_mc_free(mci); return rc; } -- GitLab From bd9e19ca46b54fa85141c4d20afd668379d94c81 Mon Sep 17 00:00:00 2001 From: Vernon Mauery <vernux@us.ibm.com> Date: Tue, 18 May 2010 19:02:50 -0300 Subject: [PATCH 167/842] Add support for Westmere to i7core_edac driver This adds new PCI IDs for the Westmere's memory controller devices and modifies the i7core_edac driver to be able to probe both Nehalem and Westmere processors. Signed-off-by: Vernon Mauery <vernux@us.ibm.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 117 +++++++++++++++++++++++++------------ include/linux/pci_ids.h | 16 +++++ 2 files changed, 96 insertions(+), 37 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 3e2b5379bc05..8d63b0046480 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -206,6 +206,11 @@ struct pci_id_descr { int optional; }; +struct pci_id_table { + struct pci_id_descr *descr; + int n_devs; +}; + struct i7core_dev { struct list_head list; u8 socket; @@ -262,7 +267,7 @@ static DEFINE_MUTEX(i7core_edac_lock); .func = (function), \ .dev_id = (device_id) -struct pci_id_descr pci_dev_descr_i7core[] = { +struct pci_id_descr pci_dev_descr_i7core_nehalem[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, @@ -321,6 +326,44 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = { { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) }, }; +struct pci_id_descr pci_dev_descr_i7core_westmere[] = { + /* Memory controller */ + { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2) }, + { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2) }, + /* Exists only for RDIMM */ + { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_RAS_REV2), .optional = 1 }, + { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST_REV2) }, + + /* Channel 0 */ + { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL_REV2) }, + { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR_REV2) }, + { PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK_REV2) }, + { PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC_REV2) }, + + /* Channel 1 */ + { PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL_REV2) }, + { PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR_REV2) }, + { PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK_REV2) }, + { PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC_REV2) }, + + /* Channel 2 */ + { PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_CTRL_REV2) }, + { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) }, + { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) }, + { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2) }, + + /* Generic Non-core registers */ + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2) }, + +}; + +#define PCI_ID_TABLE_ENTRY(A) { A, ARRAY_SIZE(A) } +struct pci_id_table pci_dev_table[] = { + PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem), + PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield), + PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere), +}; + /* * pci_device_id table for which devices we are looking for */ @@ -1170,7 +1213,7 @@ static void i7core_put_all_devices(void) i7core_put_devices(i7core_dev); } -static void __init i7core_xeon_pci_fixup(int dev_id) +static void __init i7core_xeon_pci_fixup(struct pci_id_table *table) { struct pci_dev *pdev = NULL; int i; @@ -1179,10 +1222,13 @@ static void __init i7core_xeon_pci_fixup(int dev_id) * aren't announced by acpi. So, we need to use a legacy scan probing * to detect them */ - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL); - if (unlikely(!pdev)) { - for (i = 0; i < MAX_SOCKET_BUSES; i++) - pcibios_scan_specific_bus(255-i); + while (table && table->descr) { + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, table->descr[0].dev_id, NULL); + if (unlikely(!pdev)) { + for (i = 0; i < MAX_SOCKET_BUSES; i++) + pcibios_scan_specific_bus(255-i); + } + table++; } } @@ -1213,15 +1259,10 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); - if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) { + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT, *prev); - if (!pdev) - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2, - *prev); - } if (!pdev) { if (*prev) { @@ -1232,6 +1273,9 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, if (dev_descr->optional) return 0; + if (devno == 0) + return -ENODEV; + i7core_printk(KERN_ERR, "Device not found: dev %02x.%d PCI ID %04x:%04x\n", dev_descr->dev, dev_descr->func, @@ -1307,24 +1351,34 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, return 0; } -static int i7core_get_devices(struct pci_id_descr dev_descr[], unsigned n_devs) +static int i7core_get_devices(struct pci_id_table *table) { int i, rc; struct pci_dev *pdev = NULL; - - for (i = 0; i < n_devs; i++) { - pdev = NULL; - do { - rc = i7core_get_onedevice(&pdev, i, &dev_descr[i], - n_devs); - if (rc < 0) { - i7core_put_all_devices(); - return -ENODEV; - } - } while (pdev); + struct pci_id_descr *dev_descr; + + while (table && table->descr) { + dev_descr = table->descr; + for (i = 0; i < table->n_devs; i++) { + pdev = NULL; + do { + rc = i7core_get_onedevice(&pdev, i, &dev_descr[i], + table->n_devs); + if (rc < 0) { + if (i == 0) { + i = table->n_devs; + break; + } + i7core_put_all_devices(); + return -ENODEV; + } + } while (pdev); + } + table++; } return 0; + return 0; } static int mci_bind_devs(struct mem_ctl_info *mci, @@ -1884,18 +1938,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, /* get the pci devices we want to reserve for our use */ mutex_lock(&i7core_edac_lock); - if (pdev->device == PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0) { - printk(KERN_INFO "i7core_edac: detected a " - "Lynnfield processor\n"); - rc = i7core_get_devices(pci_dev_descr_lynnfield, - ARRAY_SIZE(pci_dev_descr_lynnfield)); - } else { - printk(KERN_INFO "i7core_edac: detected a " - "Nehalem/Nehalem-EP processor\n"); - rc = i7core_get_devices(pci_dev_descr_i7core, - ARRAY_SIZE(pci_dev_descr_i7core)); - } - + rc = i7core_get_devices(pci_dev_table); if (unlikely(rc < 0)) goto fail0; @@ -1994,7 +2037,7 @@ static int __init i7core_init(void) /* Ensure that the OPSTATE is set correctly for POLL or NMI */ opstate_init(); - i7core_xeon_pci_fixup(pci_dev_descr_i7core[0].dev_id); + i7core_xeon_pci_fixup(pci_dev_table); pci_rc = pci_register_driver(&i7core_driver); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 46d76e985bac..413fab765a5f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2567,6 +2567,22 @@ #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR 0x2ca9 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK 0x2caa #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC 0x2cab +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2 0x2d98 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2 0x2d99 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_RAS_REV2 0x2d9a +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST_REV2 0x2d9c +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL_REV2 0x2da0 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR_REV2 0x2da1 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK_REV2 0x2da2 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC_REV2 0x2da3 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL_REV2 0x2da8 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR_REV2 0x2da9 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK_REV2 0x2daa +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC_REV2 0x2dab +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_CTRL_REV2 0x2db0 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2 0x2db1 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2 0x2db2 +#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2 0x2db3 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 #define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a -- GitLab From 52707f918cca231f8461d45e78a60014795f20d9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@redhat.com> Date: Tue, 18 May 2010 20:43:52 -0300 Subject: [PATCH 168/842] i7core_edac: Better describe the supported devices Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/edac/i7core_edac.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 8d63b0046480..6b8b7b41ec5f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1,9 +1,14 @@ -/* Intel 7 core Memory Controller kernel module (Nehalem) +/* Intel i7 core/Nehalem Memory Controller kernel module + * + * This driver supports yhe memory controllers found on the Intel + * processor families i7core, i7core 7xx/8xx, i5core, Xeon 35xx, + * Xeon 55xx and Xeon 56xx also known as Nehalem, Nehalem-EP, Lynnfield + * and Westmere-EP. * * This file may be distributed under the terms of the * GNU General Public License version 2 only. * - * Copyright (c) 2009 by: + * Copyright (c) 2009-2010 by: * Mauro Carvalho Chehab <mchehab@redhat.com> * * Red Hat Inc. http://www.redhat.com -- GitLab From fe04b1121511a97982a1fcdd38e44d2029304a6d Mon Sep 17 00:00:00 2001 From: Scott Wood <scottwood@freescale.com> Date: Thu, 8 Apr 2010 00:38:22 -0500 Subject: [PATCH 169/842] powerpc/e500mc: Implement machine check handler. Most of the MSCR bit assigments are different in e500mc versus e500, and they are now write-one-to-clear. Some e500mc machine check conditions are made recoverable (as long as they aren't stuck on), most notably L1 instruction cache parity errors. Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/include/asm/cputable.h | 1 + arch/powerpc/include/asm/reg_booke.h | 33 +++++++---- arch/powerpc/kernel/cputable.c | 2 +- arch/powerpc/kernel/traps.c | 88 +++++++++++++++++++++++++++- 4 files changed, 112 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index e3cba4e1eb34..b0b21134f61a 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -70,6 +70,7 @@ struct pt_regs; extern int machine_check_generic(struct pt_regs *regs); extern int machine_check_4xx(struct pt_regs *regs); extern int machine_check_440A(struct pt_regs *regs); +extern int machine_check_e500mc(struct pt_regs *regs); extern int machine_check_e500(struct pt_regs *regs); extern int machine_check_e200(struct pt_regs *regs); extern int machine_check_47x(struct pt_regs *regs); diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 5304a37ba425..2360317179a9 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -4,6 +4,12 @@ * are not true Book E PowerPCs, they borrowed a number of features * before Book E was finalized, and are included here as well. Unfortunatly, * they sometimes used different locations than true Book E CPUs did. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Copyright 2009-2010 Freescale Semiconductor, Inc. */ #ifdef __KERNEL__ #ifndef __ASM_POWERPC_REG_BOOKE_H__ @@ -88,6 +94,7 @@ #define SPRN_IVOR35 0x213 /* Interrupt Vector Offset Register 35 */ #define SPRN_IVOR36 0x214 /* Interrupt Vector Offset Register 36 */ #define SPRN_IVOR37 0x215 /* Interrupt Vector Offset Register 37 */ +#define SPRN_MCARU 0x239 /* Machine Check Address Register Upper */ #define SPRN_MCSRR0 0x23A /* Machine Check Save and Restore Register 0 */ #define SPRN_MCSRR1 0x23B /* Machine Check Save and Restore Register 1 */ #define SPRN_MCSR 0x23C /* Machine Check Status Register */ @@ -196,8 +203,11 @@ #define PPC47x_MCSR_IPR 0x00400000 /* Imprecise Machine Check Exception */ #ifdef CONFIG_E500 +/* All e500 */ #define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */ #define MCSR_ICPERR 0x40000000UL /* I-Cache Parity Error */ + +/* e500v1/v2 */ #define MCSR_DCP_PERR 0x20000000UL /* D-Cache Push Parity Error */ #define MCSR_DCPERR 0x10000000UL /* D-Cache Parity Error */ #define MCSR_BUS_IAERR 0x00000080UL /* Instruction Address Error */ @@ -209,12 +219,20 @@ #define MCSR_BUS_IPERR 0x00000002UL /* Instruction parity Error */ #define MCSR_BUS_RPERR 0x00000001UL /* Read parity Error */ -/* e500 parts may set unused bits in MCSR; mask these off */ -#define MCSR_MASK (MCSR_MCP | MCSR_ICPERR | MCSR_DCP_PERR | \ - MCSR_DCPERR | MCSR_BUS_IAERR | MCSR_BUS_RAERR | \ - MCSR_BUS_WAERR | MCSR_BUS_IBERR | MCSR_BUS_RBERR | \ - MCSR_BUS_WBERR | MCSR_BUS_IPERR | MCSR_BUS_RPERR) +/* e500mc */ +#define MCSR_DCPERR_MC 0x20000000UL /* D-Cache Parity Error */ +#define MCSR_L2MMU_MHIT 0x04000000UL /* Hit on multiple TLB entries */ +#define MCSR_NMI 0x00100000UL /* Non-Maskable Interrupt */ +#define MCSR_MAV 0x00080000UL /* MCAR address valid */ +#define MCSR_MEA 0x00040000UL /* MCAR is effective address */ +#define MCSR_IF 0x00010000UL /* Instruction Fetch */ +#define MCSR_LD 0x00008000UL /* Load */ +#define MCSR_ST 0x00004000UL /* Store */ +#define MCSR_LDG 0x00002000UL /* Guarded Load */ +#define MCSR_TLBSYNC 0x00000002UL /* Multiple tlbsyncs detected */ +#define MCSR_BSL2_ERR 0x00000001UL /* Backside L2 cache error */ #endif + #ifdef CONFIG_E200 #define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */ #define MCSR_CP_PERR 0x20000000UL /* Cache Push Parity Error */ @@ -225,11 +243,6 @@ #define MCSR_BUS_DRERR 0x00000008UL /* Read Bus Error on data load */ #define MCSR_BUS_WRERR 0x00000004UL /* Write Bus Error on buffered store or cache line push */ - -/* e200 parts may set unused bits in MCSR; mask these off */ -#define MCSR_MASK (MCSR_MCP | MCSR_CP_PERR | MCSR_CPERR | \ - MCSR_EXCP_ERR | MCSR_BUS_IRERR | MCSR_BUS_DRERR | \ - MCSR_BUS_WRERR) #endif /* Bit definitions for the DBSR. */ diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 9556be903e96..87aa0f3c6047 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1840,7 +1840,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_cpu_type = "ppc/e500mc", .oprofile_type = PPC_OPROFILE_FSL_EMB, .cpu_setup = __setup_cpu_e500mc, - .machine_check = machine_check_e500, + .machine_check = machine_check_e500mc, .platform = "ppce500mc", }, { /* default match */ diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index ca7ce85ebc2e..5ed46758f4e9 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1,5 +1,6 @@ /* * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Copyright 2007-2010 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -305,7 +306,7 @@ static inline int check_io_access(struct pt_regs *regs) #ifndef CONFIG_FSL_BOOKE #define get_mc_reason(regs) ((regs)->dsisr) #else -#define get_mc_reason(regs) (mfspr(SPRN_MCSR) & MCSR_MASK) +#define get_mc_reason(regs) (mfspr(SPRN_MCSR)) #endif #define REASON_FP ESR_FP #define REASON_ILLEGAL (ESR_PIL | ESR_PUO) @@ -421,6 +422,91 @@ int machine_check_47x(struct pt_regs *regs) return 0; } #elif defined(CONFIG_E500) +int machine_check_e500mc(struct pt_regs *regs) +{ + unsigned long mcsr = mfspr(SPRN_MCSR); + unsigned long reason = mcsr; + int recoverable = 1; + + printk("Machine check in kernel mode.\n"); + printk("Caused by (from MCSR=%lx): ", reason); + + if (reason & MCSR_MCP) + printk("Machine Check Signal\n"); + + if (reason & MCSR_ICPERR) { + printk("Instruction Cache Parity Error\n"); + + /* + * This is recoverable by invalidating the i-cache. + */ + mtspr(SPRN_L1CSR1, mfspr(SPRN_L1CSR1) | L1CSR1_ICFI); + while (mfspr(SPRN_L1CSR1) & L1CSR1_ICFI) + ; + + /* + * This will generally be accompanied by an instruction + * fetch error report -- only treat MCSR_IF as fatal + * if it wasn't due to an L1 parity error. + */ + reason &= ~MCSR_IF; + } + + if (reason & MCSR_DCPERR_MC) { + printk("Data Cache Parity Error\n"); + recoverable = 0; + } + + if (reason & MCSR_L2MMU_MHIT) { + printk("Hit on multiple TLB entries\n"); + recoverable = 0; + } + + if (reason & MCSR_NMI) + printk("Non-maskable interrupt\n"); + + if (reason & MCSR_IF) { + printk("Instruction Fetch Error Report\n"); + recoverable = 0; + } + + if (reason & MCSR_LD) { + printk("Load Error Report\n"); + recoverable = 0; + } + + if (reason & MCSR_ST) { + printk("Store Error Report\n"); + recoverable = 0; + } + + if (reason & MCSR_LDG) { + printk("Guarded Load Error Report\n"); + recoverable = 0; + } + + if (reason & MCSR_TLBSYNC) + printk("Simultaneous tlbsync operations\n"); + + if (reason & MCSR_BSL2_ERR) { + printk("Level 2 Cache Error\n"); + recoverable = 0; + } + + if (reason & MCSR_MAV) { + u64 addr; + + addr = mfspr(SPRN_MCAR); + addr |= (u64)mfspr(SPRN_MCARU) << 32; + + printk("Machine Check %s Address: %#llx\n", + reason & MCSR_MEA ? "Effective" : "Physical", addr); + } + + mtspr(SPRN_MCSR, mcsr); + return mfspr(SPRN_MCSR) == 0 && recoverable; +} + int machine_check_e500(struct pt_regs *regs) { unsigned long reason = get_mc_reason(regs); -- GitLab From 90103f932f0d94e0a1a0e4faf20fb24a0b07264c Mon Sep 17 00:00:00 2001 From: Anton Vorontsov <avorontsov@mvista.com> Date: Mon, 17 May 2010 22:56:52 +0400 Subject: [PATCH 170/842] powerpc/fsl-booke: Add hibernation support for FSL BookE processors This is started as swsusp_32.S modifications, but the amount of #ifdefs made the whole file horribly unreadable, so let's put the support into its own separate file. The code should be relatively easy to modify to support 44x BookEs as well, but since I don't have any 44x to test, let's confine the code to FSL BookE. (The only FSL-specific part so far is 'flush_dcache_L1'.) Signed-off-by: Anton Vorontsov <avorontsov@mvista.com> Acked-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/kernel/Makefile | 8 +- arch/powerpc/kernel/swsusp_booke.S | 193 +++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/kernel/swsusp_booke.S diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 877326320e74..58d0572de6f9 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -57,8 +57,12 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_E500) += idle_e500.o obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o obj-$(CONFIG_TAU) += tau_6xx.o -obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o \ - swsusp_$(CONFIG_WORD_SIZE).o +obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o +ifeq ($(CONFIG_FSL_BOOKE),y) +obj-$(CONFIG_HIBERNATION) += swsusp_booke.o +else +obj-$(CONFIG_HIBERNATION) += swsusp_$(CONFIG_WORD_SIZE).o +endif obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_44x) += cpu_setup_44x.o diff --git a/arch/powerpc/kernel/swsusp_booke.S b/arch/powerpc/kernel/swsusp_booke.S new file mode 100644 index 000000000000..11a39307dd71 --- /dev/null +++ b/arch/powerpc/kernel/swsusp_booke.S @@ -0,0 +1,193 @@ +/* + * Based on swsusp_32.S, modified for FSL BookE by + * Anton Vorontsov <avorontsov@ru.mvista.com> + * Copyright (c) 2009-2010 MontaVista Software, LLC. + */ + +#include <linux/threads.h> +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/cputable.h> +#include <asm/thread_info.h> +#include <asm/ppc_asm.h> +#include <asm/asm-offsets.h> +#include <asm/mmu.h> + +/* + * Structure for storing CPU registers on the save area. + */ +#define SL_SP 0 +#define SL_PC 4 +#define SL_MSR 8 +#define SL_TCR 0xc +#define SL_SPRG0 0x10 +#define SL_SPRG1 0x14 +#define SL_SPRG2 0x18 +#define SL_SPRG3 0x1c +#define SL_SPRG4 0x20 +#define SL_SPRG5 0x24 +#define SL_SPRG6 0x28 +#define SL_SPRG7 0x2c +#define SL_TBU 0x30 +#define SL_TBL 0x34 +#define SL_R2 0x38 +#define SL_CR 0x3c +#define SL_LR 0x40 +#define SL_R12 0x44 /* r12 to r31 */ +#define SL_SIZE (SL_R12 + 80) + + .section .data + .align 5 + +_GLOBAL(swsusp_save_area) + .space SL_SIZE + + + .section .text + .align 5 + +_GLOBAL(swsusp_arch_suspend) + lis r11,swsusp_save_area@h + ori r11,r11,swsusp_save_area@l + + mflr r0 + stw r0,SL_LR(r11) + mfcr r0 + stw r0,SL_CR(r11) + stw r1,SL_SP(r11) + stw r2,SL_R2(r11) + stmw r12,SL_R12(r11) + + /* Save MSR & TCR */ + mfmsr r4 + stw r4,SL_MSR(r11) + mfspr r4,SPRN_TCR + stw r4,SL_TCR(r11) + + /* Get a stable timebase and save it */ +1: mfspr r4,SPRN_TBRU + stw r4,SL_TBU(r11) + mfspr r5,SPRN_TBRL + stw r5,SL_TBL(r11) + mfspr r3,SPRN_TBRU + cmpw r3,r4 + bne 1b + + /* Save SPRGs */ + mfsprg r4,0 + stw r4,SL_SPRG0(r11) + mfsprg r4,1 + stw r4,SL_SPRG1(r11) + mfsprg r4,2 + stw r4,SL_SPRG2(r11) + mfsprg r4,3 + stw r4,SL_SPRG3(r11) + mfsprg r4,4 + stw r4,SL_SPRG4(r11) + mfsprg r4,5 + stw r4,SL_SPRG5(r11) + mfsprg r4,6 + stw r4,SL_SPRG6(r11) + mfsprg r4,7 + stw r4,SL_SPRG7(r11) + + /* Call the low level suspend stuff (we should probably have made + * a stackframe... + */ + bl swsusp_save + + /* Restore LR from the save area */ + lis r11,swsusp_save_area@h + ori r11,r11,swsusp_save_area@l + lwz r0,SL_LR(r11) + mtlr r0 + + blr + +_GLOBAL(swsusp_arch_resume) + sync + + /* Load ptr the list of pages to copy in r3 */ + lis r11,(restore_pblist)@h + ori r11,r11,restore_pblist@l + lwz r3,0(r11) + + /* Copy the pages. This is a very basic implementation, to + * be replaced by something more cache efficient */ +1: + li r0,256 + mtctr r0 + lwz r5,pbe_address(r3) /* source */ + lwz r6,pbe_orig_address(r3) /* destination */ +2: + lwz r8,0(r5) + lwz r9,4(r5) + lwz r10,8(r5) + lwz r11,12(r5) + addi r5,r5,16 + stw r8,0(r6) + stw r9,4(r6) + stw r10,8(r6) + stw r11,12(r6) + addi r6,r6,16 + bdnz 2b + lwz r3,pbe_next(r3) + cmpwi 0,r3,0 + bne 1b + + bl flush_dcache_L1 + bl flush_instruction_cache + + lis r11,swsusp_save_area@h + ori r11,r11,swsusp_save_area@l + + lwz r4,SL_SPRG0(r11) + mtsprg 0,r4 + lwz r4,SL_SPRG1(r11) + mtsprg 1,r4 + lwz r4,SL_SPRG2(r11) + mtsprg 2,r4 + lwz r4,SL_SPRG3(r11) + mtsprg 3,r4 + lwz r4,SL_SPRG4(r11) + mtsprg 4,r4 + lwz r4,SL_SPRG5(r11) + mtsprg 5,r4 + lwz r4,SL_SPRG6(r11) + mtsprg 6,r4 + lwz r4,SL_SPRG7(r11) + mtsprg 7,r4 + + /* restore the MSR */ + lwz r3,SL_MSR(r11) + mtmsr r3 + + /* Restore TB */ + li r3,0 + mtspr SPRN_TBWL,r3 + lwz r3,SL_TBU(r11) + lwz r4,SL_TBL(r11) + mtspr SPRN_TBWU,r3 + mtspr SPRN_TBWL,r4 + + /* Restore TCR and clear any pending bits in TSR. */ + lwz r4,SL_TCR(r11) + mtspr SPRN_TCR,r4 + lis r4, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h + mtspr SPRN_TSR,r4 + + /* Kick decrementer */ + li r0,1 + mtdec r0 + + /* Restore the callee-saved registers and return */ + lwz r0,SL_CR(r11) + mtcr r0 + lwz r2,SL_R2(r11) + lmw r12,SL_R12(r11) + lwz r1,SL_SP(r11) + lwz r0,SL_LR(r11) + mtlr r0 + + li r3,0 + blr -- GitLab From 0472fd0755fed200c750ba57e5ea46f941914adb Mon Sep 17 00:00:00 2001 From: Andy Fleming <afleming@freescale.com> Date: Mon, 29 Mar 2010 20:39:08 -0500 Subject: [PATCH 171/842] powerpc/85xx: Enable support for ports 3 and 4 on 8548 CDS I believe support was disabled due to issues with earlier versions of the board/processor. At worst, adding the ports back into the device tree should result in enabling ports that don't work on older systems, so the default should be to enable them. Signed-off-by: Andy Fleming <afleming@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/boot/dts/mpc8548cds.dts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts index 4173af387c63..0f5262452682 100644 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ b/arch/powerpc/boot/dts/mpc8548cds.dts @@ -20,10 +20,8 @@ aliases { ethernet0 = &enet0; ethernet1 = &enet1; -/* ethernet2 = &enet2; ethernet3 = &enet3; -*/ serial0 = &serial0; serial1 = &serial1; pci0 = &pci0; @@ -254,7 +252,6 @@ }; }; -/* eTSEC 3/4 are currently broken enet2: ethernet@26000 { #address-cells = <1>; #size-cells = <1>; @@ -310,7 +307,6 @@ }; }; }; - */ serial0: serial@4500 { cell-index = <0>; -- GitLab From 39c5837d7968ffd68e1d3c79efba1631b7f513d9 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten <hsweeten@visionengravers.com> Date: Mon, 17 May 2010 16:21:11 -0700 Subject: [PATCH 172/842] docbook: make mtd nand module init static In the example the module_init function should be static. Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com> Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> --- Documentation/DocBook/mtdnand.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl index 133cd6c3f3c1..020ac80d4682 100644 --- a/Documentation/DocBook/mtdnand.tmpl +++ b/Documentation/DocBook/mtdnand.tmpl @@ -269,7 +269,7 @@ static void board_hwcontrol(struct mtd_info *mtd, int cmd) information about the device. </para> <programlisting> -int __init board_init (void) +static int __init board_init (void) { struct nand_chip *this; int err = 0; -- GitLab From df1f1d1cb43b4ffdef5ba5f0623e2f73e94ce030 Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Sat, 22 May 2010 10:22:49 +0200 Subject: [PATCH 173/842] drivers/mtd: Use memdup_user Use memdup_user when user data is immediately copied into the allocated region. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // <smpl> @@ expression from,to,size,flag; position p; identifier l1,l2; @@ - to = \(kmalloc@p\|kzalloc@p\)(size,flag); + to = memdup_user(from,size); if ( - to==NULL + IS_ERR(to) || ...) { <+... when != goto l1; - -ENOMEM + PTR_ERR(to) ...+> } - if (copy_from_user(to, from, size) != 0) { - <+... when != goto l2; - -EFAULT - ...+> - } // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> --- drivers/mtd/mtdchar.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 8bb5e4a66328..8b223c0343ee 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -404,14 +404,9 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; - ops.oobbuf = kmalloc(length, GFP_KERNEL); - if (!ops.oobbuf) - return -ENOMEM; - - if (copy_from_user(ops.oobbuf, ptr, length)) { - kfree(ops.oobbuf); - return -EFAULT; - } + ops.oobbuf = memdup_user(ptr, length); + if (IS_ERR(ops.oobbuf)) + return PTR_ERR(ops.oobbuf); start &= ~((uint64_t)mtd->oobsize - 1); ret = mtd->write_oob(mtd, start, &ops); -- GitLab From bca4b914b5da3d8e7b9b647f620b71dc85c0c394 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov <khlebnikov@openvz.org> Date: Thu, 20 May 2010 23:21:34 +0400 Subject: [PATCH 174/842] cfq-iosched: remove dead_key from cfq_io_context Remove ->dead_key field from cfq_io_context to shrink its size to 128 bytes. (64 bytes for 32-bit hosts) Use lower bit in ->key as dead-mark, instead of moving key to separate field. After this for dead cfq_io_context we got cic->key != cfqd automatically. Thus, io_context's last-hit cache should work without changing. Now to check ->key for non-dead state compare it with cfqd, instead of checking ->key for non-null value as it was before. Plus remove obsolete race protection in cfq_cic_lookup. This race gone after v2.6.24-1728-g4ac845a Signed-off-by: Konstantin Khlebnikov <khlebnikov@openvz.org> Signed-off-by: Jens Axboe <jens.axboe@oracle.com> --- block/cfq-iosched.c | 41 ++++++++++++++++++++++++++------------- include/linux/iocontext.h | 1 - 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index ed897b5ef315..407602350350 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -430,6 +430,23 @@ static inline void cic_set_cfqq(struct cfq_io_context *cic, cic->cfqq[is_sync] = cfqq; } +#define CIC_DEAD_KEY 1ul + +static inline void *cfqd_dead_key(struct cfq_data *cfqd) +{ + return (void *)((unsigned long) cfqd | CIC_DEAD_KEY); +} + +static inline struct cfq_data *cic_to_cfqd(struct cfq_io_context *cic) +{ + struct cfq_data *cfqd = cic->key; + + if (unlikely((unsigned long) cfqd & CIC_DEAD_KEY)) + return NULL; + + return cfqd; +} + /* * We regard a request as SYNC, if it's either a read or has the SYNC bit * set (in which case it could also be direct WRITE). @@ -2510,11 +2527,12 @@ static void cfq_cic_free(struct cfq_io_context *cic) static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic) { unsigned long flags; + unsigned long dead_key = (unsigned long) cic->key; - BUG_ON(!cic->dead_key); + BUG_ON(!(dead_key & CIC_DEAD_KEY)); spin_lock_irqsave(&ioc->lock, flags); - radix_tree_delete(&ioc->radix_root, cic->dead_key); + radix_tree_delete(&ioc->radix_root, dead_key & ~CIC_DEAD_KEY); hlist_del_rcu(&cic->cic_list); spin_unlock_irqrestore(&ioc->lock, flags); @@ -2573,11 +2591,10 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd, list_del_init(&cic->queue_list); /* - * Make sure key == NULL is seen for dead queues + * Make sure dead mark is seen for dead queues */ smp_wmb(); - cic->dead_key = (unsigned long) cic->key; - cic->key = NULL; + cic->key = cfqd_dead_key(cfqd); if (ioc->ioc_data == cic) rcu_assign_pointer(ioc->ioc_data, NULL); @@ -2596,7 +2613,7 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd, static void cfq_exit_single_io_context(struct io_context *ioc, struct cfq_io_context *cic) { - struct cfq_data *cfqd = cic->key; + struct cfq_data *cfqd = cic_to_cfqd(cic); if (cfqd) { struct request_queue *q = cfqd->queue; @@ -2609,7 +2626,7 @@ static void cfq_exit_single_io_context(struct io_context *ioc, * race between exiting task and queue */ smp_read_barrier_depends(); - if (cic->key) + if (cic->key == cfqd) __cfq_exit_single_io_context(cfqd, cic); spin_unlock_irqrestore(q->queue_lock, flags); @@ -2689,7 +2706,7 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc) static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic) { - struct cfq_data *cfqd = cic->key; + struct cfq_data *cfqd = cic_to_cfqd(cic); struct cfq_queue *cfqq; unsigned long flags; @@ -2746,7 +2763,7 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq, static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic) { struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1); - struct cfq_data *cfqd = cic->key; + struct cfq_data *cfqd = cic_to_cfqd(cic); unsigned long flags; struct request_queue *q; @@ -2883,6 +2900,7 @@ cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc, unsigned long flags; WARN_ON(!list_empty(&cic->queue_list)); + BUG_ON(cic->key != cfqd_dead_key(cfqd)); spin_lock_irqsave(&ioc->lock, flags); @@ -2900,7 +2918,6 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc) { struct cfq_io_context *cic; unsigned long flags; - void *k; if (unlikely(!ioc)) return NULL; @@ -2921,9 +2938,7 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc) rcu_read_unlock(); if (!cic) break; - /* ->key must be copied to avoid race with cfq_exit_queue() */ - k = cic->key; - if (unlikely(!k)) { + if (unlikely(cic->key != cfqd)) { cfq_drop_dead_cic(cfqd, ioc, cic); rcu_read_lock(); continue; diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h index a0bb301afac0..64d529133031 100644 --- a/include/linux/iocontext.h +++ b/include/linux/iocontext.h @@ -7,7 +7,6 @@ struct cfq_queue; struct cfq_io_context { void *key; - unsigned long dead_key; struct cfq_queue *cfqq[2]; -- GitLab From 80b15c7389caa81a3860f9fc2ee47ec0ea572a63 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov <khlebnikov@openvz.org> Date: Thu, 20 May 2010 23:21:41 +0400 Subject: [PATCH 175/842] cfq-iosched: compact io_context radix_tree Use small consequent indexes as radix tree keys instead of sparse cfqd address. This change will reduce radix tree depth from 11 (6 for 32-bit hosts) to 1 if host have <=64 disks under cfq control, or to 0 if there only one disk. So, this patch save 10*560 bytes for each process (5*296 for 32-bit hosts) For each cfqd allocate cic index from ida. To unlink dead cic from tree without cfqd access store index into ->key. (bit 0 -- dead mark, bits 1..30 -- index: ida produce id in range 0..2^31-1) Signed-off-by: Konstantin Khlebnikov <khlebnikov@openvz.org> Signed-off-by: Jens Axboe <jens.axboe@oracle.com> --- block/cfq-iosched.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 407602350350..c72e5acc573d 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -64,6 +64,9 @@ static DEFINE_PER_CPU(unsigned long, cfq_ioc_count); static struct completion *ioc_gone; static DEFINE_SPINLOCK(ioc_gone_lock); +static DEFINE_SPINLOCK(cic_index_lock); +static DEFINE_IDA(cic_index_ida); + #define CFQ_PRIO_LISTS IOPRIO_BE_NR #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) #define cfq_class_rt(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_RT) @@ -271,6 +274,7 @@ struct cfq_data { unsigned int cfq_latency; unsigned int cfq_group_isolation; + unsigned int cic_index; struct list_head cic_list; /* @@ -431,10 +435,11 @@ static inline void cic_set_cfqq(struct cfq_io_context *cic, } #define CIC_DEAD_KEY 1ul +#define CIC_DEAD_INDEX_SHIFT 1 static inline void *cfqd_dead_key(struct cfq_data *cfqd) { - return (void *)((unsigned long) cfqd | CIC_DEAD_KEY); + return (void *)(cfqd->cic_index << CIC_DEAD_INDEX_SHIFT | CIC_DEAD_KEY); } static inline struct cfq_data *cic_to_cfqd(struct cfq_io_context *cic) @@ -2532,7 +2537,7 @@ static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic) BUG_ON(!(dead_key & CIC_DEAD_KEY)); spin_lock_irqsave(&ioc->lock, flags); - radix_tree_delete(&ioc->radix_root, dead_key & ~CIC_DEAD_KEY); + radix_tree_delete(&ioc->radix_root, dead_key >> CIC_DEAD_INDEX_SHIFT); hlist_del_rcu(&cic->cic_list); spin_unlock_irqrestore(&ioc->lock, flags); @@ -2906,7 +2911,7 @@ cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc, BUG_ON(ioc->ioc_data == cic); - radix_tree_delete(&ioc->radix_root, (unsigned long) cfqd); + radix_tree_delete(&ioc->radix_root, cfqd->cic_index); hlist_del_rcu(&cic->cic_list); spin_unlock_irqrestore(&ioc->lock, flags); @@ -2934,7 +2939,7 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc) } do { - cic = radix_tree_lookup(&ioc->radix_root, (unsigned long) cfqd); + cic = radix_tree_lookup(&ioc->radix_root, cfqd->cic_index); rcu_read_unlock(); if (!cic) break; @@ -2971,7 +2976,7 @@ static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc, spin_lock_irqsave(&ioc->lock, flags); ret = radix_tree_insert(&ioc->radix_root, - (unsigned long) cfqd, cic); + cfqd->cic_index, cic); if (!ret) hlist_add_head_rcu(&cic->cic_list, &ioc->cic_list); spin_unlock_irqrestore(&ioc->lock, flags); @@ -3723,10 +3728,32 @@ static void cfq_exit_queue(struct elevator_queue *e) cfq_shutdown_timer_wq(cfqd); + spin_lock(&cic_index_lock); + ida_remove(&cic_index_ida, cfqd->cic_index); + spin_unlock(&cic_index_lock); + /* Wait for cfqg->blkg->key accessors to exit their grace periods. */ call_rcu(&cfqd->rcu, cfq_cfqd_free); } +static int cfq_alloc_cic_index(void) +{ + int index, error; + + do { + if (!ida_pre_get(&cic_index_ida, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(&cic_index_lock); + error = ida_get_new(&cic_index_ida, &index); + spin_unlock(&cic_index_lock); + if (error && error != -EAGAIN) + return error; + } while (error); + + return index; +} + static void *cfq_init_queue(struct request_queue *q) { struct cfq_data *cfqd; @@ -3734,10 +3761,16 @@ static void *cfq_init_queue(struct request_queue *q) struct cfq_group *cfqg; struct cfq_rb_root *st; + i = cfq_alloc_cic_index(); + if (i < 0) + return NULL; + cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node); if (!cfqd) return NULL; + cfqd->cic_index = i; + /* Init root service tree */ cfqd->grp_service_tree = CFQ_RB_ROOT; @@ -3999,6 +4032,7 @@ static void __exit cfq_exit(void) */ if (elv_ioc_count_read(cfq_ioc_count)) wait_for_completion(&all_gone); + ida_destroy(&cic_index_ida); cfq_slab_kill(); } -- GitLab From e36f724b4ae70e443a7d152929b60059cbfa1a26 Mon Sep 17 00:00:00 2001 From: Mike Snitzer <snitzer@redhat.com> Date: Mon, 24 May 2010 09:07:32 +0200 Subject: [PATCH 176/842] block: Adjust elv_iosched_show to return "none" for bio-based DM Bio-based DM doesn't use an elevator (queue is !blk_queue_stackable()). Longer-term DM will not allocate an elevator for bio-based DM. But even then there will be small potential for an elevator to be allocated for a request-based DM table only to have a bio-based table be loaded in the end. Displaying "none" for bio-based DM will help avoid user confusion. Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com> --- block/elevator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/elevator.c b/block/elevator.c index 6df2b5056b51..0abce473d606 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -1097,7 +1097,7 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name) struct elevator_type *__e; int len = 0; - if (!q->elevator) + if (!q->elevator || !blk_queue_stackable(q)) return sprintf(name, "none\n"); elv = e->elevator_type; -- GitLab From 0191f8697bbdfefcd36e7b8dc3eeddfe82893e4b Mon Sep 17 00:00:00 2001 From: Jens Axboe <jens.axboe@oracle.com> Date: Mon, 24 May 2010 19:15:57 +0200 Subject: [PATCH 177/842] pipe: F_SETPIPE_SZ should return -EPERM for non-root If the passed in size is larger than what has been set as the system wide limit and the user is not root, we want to return permission denied (not invalid value). Signed-off-by: Jens Axboe <jens.axboe@oracle.com> --- fs/pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/pipe.c b/fs/pipe.c index d79872eba09a..01ca9fab95fa 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1170,7 +1170,7 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) switch (cmd) { case F_SETPIPE_SZ: if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) - return -EINVAL; + return -EPERM; /* * The pipe needs to be at least 2 pages large to * guarantee POSIX behaviour. -- GitLab From b9598db3401282bb27b4aef77e3eee12015f7f29 Mon Sep 17 00:00:00 2001 From: Jens Axboe <jens.axboe@oracle.com> Date: Mon, 24 May 2010 19:34:43 +0200 Subject: [PATCH 178/842] pipe: make F_{GET,SET}PIPE_SZ deal with byte sizes Instead of requiring an exact number of pages as the argument and return value, change the API to deal with number of bytes instead. This also relaxes the requirement that the passed in size must result in a power-of-2 page array size. Round up to the nearest power-of-2 automatically and return the resulting size of the pipe on success. Signed-off-by: Jens Axboe <jens.axboe@oracle.com> --- fs/pipe.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/fs/pipe.c b/fs/pipe.c index 01ca9fab95fa..bdd3f96054b9 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1112,26 +1112,20 @@ SYSCALL_DEFINE1(pipe, int __user *, fildes) * Allocate a new array of pipe buffers and copy the info over. Returns the * pipe size if successful, or return -ERROR on error. */ -static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) +static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) { struct pipe_buffer *bufs; - /* - * Must be a power-of-2 currently - */ - if (!is_power_of_2(arg)) - return -EINVAL; - /* * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't * expect a lot of shrink+grow operations, just free and allocate * again like we would do for growing. If the pipe currently * contains more buffers than arg, then return busy. */ - if (arg < pipe->nrbufs) + if (nr_pages < pipe->nrbufs) return -EBUSY; - bufs = kcalloc(arg, sizeof(struct pipe_buffer), GFP_KERNEL); + bufs = kcalloc(nr_pages, sizeof(struct pipe_buffer), GFP_KERNEL); if (unlikely(!bufs)) return -ENOMEM; @@ -1152,8 +1146,8 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) pipe->curbuf = 0; kfree(pipe->bufs); pipe->bufs = bufs; - pipe->buffers = arg; - return arg; + pipe->buffers = nr_pages; + return nr_pages * PAGE_SIZE; } long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) @@ -1168,19 +1162,30 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) mutex_lock(&pipe->inode->i_mutex); switch (cmd) { - case F_SETPIPE_SZ: - if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) + case F_SETPIPE_SZ: { + unsigned long nr_pages; + + /* + * Currently the array must be a power-of-2 size, so adjust + * upwards if needed. + */ + nr_pages = (arg + PAGE_SIZE - 1) >> PAGE_SHIFT; + nr_pages = roundup_pow_of_two(nr_pages); + + if (!capable(CAP_SYS_ADMIN) && nr_pages > pipe_max_pages) return -EPERM; + /* * The pipe needs to be at least 2 pages large to * guarantee POSIX behaviour. */ - if (arg < 2) + if (nr_pages < 2) return -EINVAL; - ret = pipe_set_size(pipe, arg); + ret = pipe_set_size(pipe, nr_pages); break; + } case F_GETPIPE_SZ: - ret = pipe->buffers; + ret = pipe->buffers * PAGE_SIZE; break; default: ret = -EINVAL; -- GitLab From 2289d2d1a8574a11e66b00c5a59090c6fc227751 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Date: Sun, 4 Apr 2010 22:19:01 +0200 Subject: [PATCH 179/842] powerpc/fsl-booke: fix the case where we are not in the first page During boot we change the mapping a few times until we have a "defined" mapping. During this procedure a small 4KiB mapping is created and after that one a 64MiB. Currently the offset of the 4KiB page in that we run is zero because the complete startup up code is in first page which starts at RPN zero. If the code is recycled and moved to another location then its execution will fail because the start address in 64 MiB mapping is computed wrongly. It does not consider the offset to the page from the begin of the memory. This patch fixes this. Usually (system boot) r25 is zero so this does not change anything unless the code is recycled. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/kernel/head_fsl_booke.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index edd4a57fd29e..36ee1db5fc47 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -275,6 +275,7 @@ skpinv: addi r6,r6,1 /* Increment */ 1: mflr r9 rlwimi r6,r9,0,20,31 addi r6,r6,(2f - 1b) + add r6, r6, r25 mtspr SPRN_SRR0,r6 mtspr SPRN_SRR1,r7 rfi /* start execution out of TLB1[0] entry */ -- GitLab From 7c08ce718fd04e373d7473918ae02f1c04d5d504 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Date: Sun, 4 Apr 2010 22:19:02 +0200 Subject: [PATCH 180/842] powerpc/fsl-booke: Move the entry setup code into a seperate file This patch only moves the initial entry code which setups the mapping from what ever to KERNELBASE into a seperate file. No code change has been made here. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/kernel/fsl_booke_entry_mapping.S | 200 ++++++++++++++++++ arch/powerpc/kernel/head_fsl_booke.S | 199 +---------------- 2 files changed, 201 insertions(+), 198 deletions(-) create mode 100644 arch/powerpc/kernel/fsl_booke_entry_mapping.S diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S new file mode 100644 index 000000000000..cdb1296f972d --- /dev/null +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S @@ -0,0 +1,200 @@ + +/* 1. Find the index of the entry we're executing in */ + bl invstr /* Find our address */ +invstr: mflr r6 /* Make it accessible */ + mfmsr r7 + rlwinm r4,r7,27,31,31 /* extract MSR[IS] */ + mfspr r7, SPRN_PID0 + slwi r7,r7,16 + or r7,r7,r4 + mtspr SPRN_MAS6,r7 + tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */ + mfspr r7,SPRN_MAS1 + andis. r7,r7,MAS1_VALID@h + bne match_TLB + + mfspr r7,SPRN_MMUCFG + rlwinm r7,r7,21,28,31 /* extract MMUCFG[NPIDS] */ + cmpwi r7,3 + bne match_TLB /* skip if NPIDS != 3 */ + + mfspr r7,SPRN_PID1 + slwi r7,r7,16 + or r7,r7,r4 + mtspr SPRN_MAS6,r7 + tlbsx 0,r6 /* search MSR[IS], SPID=PID1 */ + mfspr r7,SPRN_MAS1 + andis. r7,r7,MAS1_VALID@h + bne match_TLB + mfspr r7, SPRN_PID2 + slwi r7,r7,16 + or r7,r7,r4 + mtspr SPRN_MAS6,r7 + tlbsx 0,r6 /* Fall through, we had to match */ + +match_TLB: + mfspr r7,SPRN_MAS0 + rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */ + + mfspr r7,SPRN_MAS1 /* Insure IPROT set */ + oris r7,r7,MAS1_IPROT@h + mtspr SPRN_MAS1,r7 + tlbwe + +/* 2. Invalidate all entries except the entry we're executing in */ + mfspr r9,SPRN_TLB1CFG + andi. r9,r9,0xfff + li r6,0 /* Set Entry counter to 0 */ +1: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r6,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r6) */ + mtspr SPRN_MAS0,r7 + tlbre + mfspr r7,SPRN_MAS1 + rlwinm r7,r7,0,2,31 /* Clear MAS1 Valid and IPROT */ + cmpw r3,r6 + beq skpinv /* Dont update the current execution TLB */ + mtspr SPRN_MAS1,r7 + tlbwe + isync +skpinv: addi r6,r6,1 /* Increment */ + cmpw r6,r9 /* Are we done? */ + bne 1b /* If not, repeat */ + + /* Invalidate TLB0 */ + li r6,0x04 + tlbivax 0,r6 + TLBSYNC + /* Invalidate TLB1 */ + li r6,0x0c + tlbivax 0,r6 + TLBSYNC + +/* 3. Setup a temp mapping and jump to it */ + andi. r5, r3, 0x1 /* Find an entry not used and is non-zero */ + addi r5, r5, 0x1 + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r7 + tlbre + + /* grab and fixup the RPN */ + mfspr r6,SPRN_MAS1 /* extract MAS1[SIZE] */ + rlwinm r6,r6,25,27,31 + li r8,-1 + addi r6,r6,10 + slw r6,r8,r6 /* convert to mask */ + + bl 1f /* Find our address */ +1: mflr r7 + + mfspr r8,SPRN_MAS3 +#ifdef CONFIG_PHYS_64BIT + mfspr r23,SPRN_MAS7 +#endif + and r8,r6,r8 + subfic r9,r6,-4096 + and r9,r9,r7 + + or r25,r8,r9 + ori r8,r25,(MAS3_SX|MAS3_SW|MAS3_SR) + + /* Just modify the entry ID and EPN for the temp mapping */ + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ + mtspr SPRN_MAS0,r7 + xori r6,r4,1 /* Setup TMP mapping in the other Address space */ + slwi r6,r6,12 + oris r6,r6,(MAS1_VALID|MAS1_IPROT)@h + ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_4K))@l + mtspr SPRN_MAS1,r6 + mfspr r6,SPRN_MAS2 + li r7,0 /* temp EPN = 0 */ + rlwimi r7,r6,0,20,31 + mtspr SPRN_MAS2,r7 + mtspr SPRN_MAS3,r8 + tlbwe + + xori r6,r4,1 + slwi r6,r6,5 /* setup new context with other address space */ + bl 1f /* Find our address */ +1: mflr r9 + rlwimi r7,r9,0,20,31 + addi r7,r7,(2f - 1b) + mtspr SPRN_SRR0,r7 + mtspr SPRN_SRR1,r6 + rfi +2: +/* 4. Clear out PIDs & Search info */ + li r6,0 + mtspr SPRN_MAS6,r6 + mtspr SPRN_PID0,r6 + + mfspr r7,SPRN_MMUCFG + rlwinm r7,r7,21,28,31 /* extract MMUCFG[NPIDS] */ + cmpwi r7,3 + bne 2f /* skip if NPIDS != 3 */ + + mtspr SPRN_PID1,r6 + mtspr SPRN_PID2,r6 + +/* 5. Invalidate mapping we started in */ +2: + lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ + mtspr SPRN_MAS0,r7 + tlbre + mfspr r6,SPRN_MAS1 + rlwinm r6,r6,0,2,0 /* clear IPROT */ + mtspr SPRN_MAS1,r6 + tlbwe + /* Invalidate TLB1 */ + li r9,0x0c + tlbivax 0,r9 + TLBSYNC + +/* The mapping only needs to be cache-coherent on SMP */ +#ifdef CONFIG_SMP +#define M_IF_SMP MAS2_M +#else +#define M_IF_SMP 0 +#endif + +/* 6. Setup KERNELBASE mapping in TLB1[0] */ + lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */ + mtspr SPRN_MAS0,r6 + lis r6,(MAS1_VALID|MAS1_IPROT)@h + ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_64M))@l + mtspr SPRN_MAS1,r6 + lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h + ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l + mtspr SPRN_MAS2,r6 + mtspr SPRN_MAS3,r8 + tlbwe + +/* 7. Jump to KERNELBASE mapping */ + lis r6,(KERNELBASE & ~0xfff)@h + ori r6,r6,(KERNELBASE & ~0xfff)@l + lis r7,MSR_KERNEL@h + ori r7,r7,MSR_KERNEL@l + bl 1f /* Find our address */ +1: mflr r9 + rlwimi r6,r9,0,20,31 + addi r6,r6,(2f - 1b) + add r6, r6, r25 + mtspr SPRN_SRR0,r6 + mtspr SPRN_SRR1,r7 + rfi /* start execution out of TLB1[0] entry */ + +/* 8. Clear out the temp mapping */ +2: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ + rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ + mtspr SPRN_MAS0,r7 + tlbre + mfspr r8,SPRN_MAS1 + rlwinm r8,r8,0,2,0 /* clear IPROT */ + mtspr SPRN_MAS1,r8 + tlbwe + /* Invalidate TLB1 */ + li r9,0x0c + tlbivax 0,r9 + TLBSYNC diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 36ee1db5fc47..6b5b1f3b6112 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -94,205 +94,8 @@ _ENTRY(_start); */ _ENTRY(__early_start) -/* 1. Find the index of the entry we're executing in */ - bl invstr /* Find our address */ -invstr: mflr r6 /* Make it accessible */ - mfmsr r7 - rlwinm r4,r7,27,31,31 /* extract MSR[IS] */ - mfspr r7, SPRN_PID0 - slwi r7,r7,16 - or r7,r7,r4 - mtspr SPRN_MAS6,r7 - tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */ - mfspr r7,SPRN_MAS1 - andis. r7,r7,MAS1_VALID@h - bne match_TLB - - mfspr r7,SPRN_MMUCFG - rlwinm r7,r7,21,28,31 /* extract MMUCFG[NPIDS] */ - cmpwi r7,3 - bne match_TLB /* skip if NPIDS != 3 */ - - mfspr r7,SPRN_PID1 - slwi r7,r7,16 - or r7,r7,r4 - mtspr SPRN_MAS6,r7 - tlbsx 0,r6 /* search MSR[IS], SPID=PID1 */ - mfspr r7,SPRN_MAS1 - andis. r7,r7,MAS1_VALID@h - bne match_TLB - mfspr r7, SPRN_PID2 - slwi r7,r7,16 - or r7,r7,r4 - mtspr SPRN_MAS6,r7 - tlbsx 0,r6 /* Fall through, we had to match */ - -match_TLB: - mfspr r7,SPRN_MAS0 - rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */ - - mfspr r7,SPRN_MAS1 /* Insure IPROT set */ - oris r7,r7,MAS1_IPROT@h - mtspr SPRN_MAS1,r7 - tlbwe - -/* 2. Invalidate all entries except the entry we're executing in */ - mfspr r9,SPRN_TLB1CFG - andi. r9,r9,0xfff - li r6,0 /* Set Entry counter to 0 */ -1: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ - rlwimi r7,r6,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r6) */ - mtspr SPRN_MAS0,r7 - tlbre - mfspr r7,SPRN_MAS1 - rlwinm r7,r7,0,2,31 /* Clear MAS1 Valid and IPROT */ - cmpw r3,r6 - beq skpinv /* Dont update the current execution TLB */ - mtspr SPRN_MAS1,r7 - tlbwe - isync -skpinv: addi r6,r6,1 /* Increment */ - cmpw r6,r9 /* Are we done? */ - bne 1b /* If not, repeat */ - - /* Invalidate TLB0 */ - li r6,0x04 - tlbivax 0,r6 - TLBSYNC - /* Invalidate TLB1 */ - li r6,0x0c - tlbivax 0,r6 - TLBSYNC - -/* 3. Setup a temp mapping and jump to it */ - andi. r5, r3, 0x1 /* Find an entry not used and is non-zero */ - addi r5, r5, 0x1 - lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ - rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ - mtspr SPRN_MAS0,r7 - tlbre - - /* grab and fixup the RPN */ - mfspr r6,SPRN_MAS1 /* extract MAS1[SIZE] */ - rlwinm r6,r6,25,27,31 - li r8,-1 - addi r6,r6,10 - slw r6,r8,r6 /* convert to mask */ - - bl 1f /* Find our address */ -1: mflr r7 - - mfspr r8,SPRN_MAS3 -#ifdef CONFIG_PHYS_64BIT - mfspr r23,SPRN_MAS7 -#endif - and r8,r6,r8 - subfic r9,r6,-4096 - and r9,r9,r7 - - or r25,r8,r9 - ori r8,r25,(MAS3_SX|MAS3_SW|MAS3_SR) - - /* Just modify the entry ID and EPN for the temp mapping */ - lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ - rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ - mtspr SPRN_MAS0,r7 - xori r6,r4,1 /* Setup TMP mapping in the other Address space */ - slwi r6,r6,12 - oris r6,r6,(MAS1_VALID|MAS1_IPROT)@h - ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_4K))@l - mtspr SPRN_MAS1,r6 - mfspr r6,SPRN_MAS2 - li r7,0 /* temp EPN = 0 */ - rlwimi r7,r6,0,20,31 - mtspr SPRN_MAS2,r7 - mtspr SPRN_MAS3,r8 - tlbwe - - xori r6,r4,1 - slwi r6,r6,5 /* setup new context with other address space */ - bl 1f /* Find our address */ -1: mflr r9 - rlwimi r7,r9,0,20,31 - addi r7,r7,(2f - 1b) - mtspr SPRN_SRR0,r7 - mtspr SPRN_SRR1,r6 - rfi -2: -/* 4. Clear out PIDs & Search info */ - li r6,0 - mtspr SPRN_MAS6,r6 - mtspr SPRN_PID0,r6 - - mfspr r7,SPRN_MMUCFG - rlwinm r7,r7,21,28,31 /* extract MMUCFG[NPIDS] */ - cmpwi r7,3 - bne 2f /* skip if NPIDS != 3 */ - mtspr SPRN_PID1,r6 - mtspr SPRN_PID2,r6 - -/* 5. Invalidate mapping we started in */ -2: - lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ - rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ - mtspr SPRN_MAS0,r7 - tlbre - mfspr r6,SPRN_MAS1 - rlwinm r6,r6,0,2,0 /* clear IPROT */ - mtspr SPRN_MAS1,r6 - tlbwe - /* Invalidate TLB1 */ - li r9,0x0c - tlbivax 0,r9 - TLBSYNC - -/* The mapping only needs to be cache-coherent on SMP */ -#ifdef CONFIG_SMP -#define M_IF_SMP MAS2_M -#else -#define M_IF_SMP 0 -#endif - -/* 6. Setup KERNELBASE mapping in TLB1[0] */ - lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */ - mtspr SPRN_MAS0,r6 - lis r6,(MAS1_VALID|MAS1_IPROT)@h - ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_64M))@l - mtspr SPRN_MAS1,r6 - lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h - ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l - mtspr SPRN_MAS2,r6 - mtspr SPRN_MAS3,r8 - tlbwe - -/* 7. Jump to KERNELBASE mapping */ - lis r6,(KERNELBASE & ~0xfff)@h - ori r6,r6,(KERNELBASE & ~0xfff)@l - lis r7,MSR_KERNEL@h - ori r7,r7,MSR_KERNEL@l - bl 1f /* Find our address */ -1: mflr r9 - rlwimi r6,r9,0,20,31 - addi r6,r6,(2f - 1b) - add r6, r6, r25 - mtspr SPRN_SRR0,r6 - mtspr SPRN_SRR1,r7 - rfi /* start execution out of TLB1[0] entry */ - -/* 8. Clear out the temp mapping */ -2: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ - rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */ - mtspr SPRN_MAS0,r7 - tlbre - mfspr r8,SPRN_MAS1 - rlwinm r8,r8,0,2,0 /* clear IPROT */ - mtspr SPRN_MAS1,r8 - tlbwe - /* Invalidate TLB1 */ - li r9,0x0c - tlbivax 0,r9 - TLBSYNC +#include "fsl_booke_entry_mapping.S" /* Establish the interrupt vector offsets */ SET_IVOR(0, CriticalInput); -- GitLab From b3df895aebe091b1657a42a8c859bd49fc96646b Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Date: Sun, 4 Apr 2010 22:19:03 +0200 Subject: [PATCH 181/842] powerpc/kexec: Add support for FSL-BookE This adds support kexec on FSL-BookE where the MMU can not be simply switched off. The code borrows the initial MMU-setup code to create the identical mapping mapping. The only difference to the original boot code is the size of the mapping(s) and the executeable address. The kexec code maps the first 2 GiB of memory in 256 MiB steps. This should work also on e500v1 boxes. SMP support is still not available. (Kumar: Added minor change to build to ifdef CONFIG_PPC_STD_MMU_64 some code that was PPC64 specific) Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/kexec.h | 13 +++++++ arch/powerpc/kernel/crash.c | 4 ++ arch/powerpc/kernel/fsl_booke_entry_mapping.S | 37 +++++++++++++++++++ arch/powerpc/kernel/head_fsl_booke.S | 2 + arch/powerpc/kernel/misc_32.S | 17 +++++++++ 6 files changed, 74 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index c4c4549c22bb..5887cff16785 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -351,7 +351,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE config KEXEC bool "kexec system call (EXPERIMENTAL)" - depends on PPC_BOOK3S && EXPERIMENTAL + depends on (PPC_BOOK3S || (FSL_BOOKE && !SMP)) && EXPERIMENTAL help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index a6ca6da1430b..2a9cd74a841e 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -2,6 +2,18 @@ #define _ASM_POWERPC_KEXEC_H #ifdef __KERNEL__ +#ifdef CONFIG_FSL_BOOKE + +/* + * On FSL-BookE we setup a 1:1 mapping which covers the first 2GiB of memory + * and therefore we can only deal with memory within this range + */ +#define KEXEC_SOURCE_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL) +#define KEXEC_DESTINATION_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL) +#define KEXEC_CONTROL_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL) + +#else + /* * Maximum page that is mapped directly into kernel memory. * XXX: Since we copy virt we can use any page we allocate @@ -21,6 +33,7 @@ /* TASK_SIZE, probably left over from use_mm ?? */ #define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE #endif +#endif #define KEXEC_CONTROL_PAGE_SIZE 4096 diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 8c066d6a8e4b..b46f2e09bd81 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -163,6 +163,7 @@ static void crash_kexec_prepare_cpus(int cpu) } /* wait for all the CPUs to hit real mode but timeout if they don't come in */ +#ifdef CONFIG_PPC_STD_MMU_64 static void crash_kexec_wait_realmode(int cpu) { unsigned int msecs; @@ -187,6 +188,7 @@ static void crash_kexec_wait_realmode(int cpu) } mb(); } +#endif /* * This function will be called by secondary cpus or by kexec cpu @@ -445,7 +447,9 @@ void default_machine_crash_shutdown(struct pt_regs *regs) crash_kexec_prepare_cpus(crashing_cpu); cpu_set(crashing_cpu, cpus_in_crash); crash_kexec_stop_spus(); +#ifdef CONFIG_PPC_STD_MMU_64 crash_kexec_wait_realmode(crashing_cpu); +#endif if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(1, 0); } diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S index cdb1296f972d..beb4d78a2304 100644 --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S @@ -159,6 +159,8 @@ skpinv: addi r6,r6,1 /* Increment */ #define M_IF_SMP 0 #endif +#if defined(ENTRY_MAPPING_BOOT_SETUP) + /* 6. Setup KERNELBASE mapping in TLB1[0] */ lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */ mtspr SPRN_MAS0,r6 @@ -174,6 +176,41 @@ skpinv: addi r6,r6,1 /* Increment */ /* 7. Jump to KERNELBASE mapping */ lis r6,(KERNELBASE & ~0xfff)@h ori r6,r6,(KERNELBASE & ~0xfff)@l + +#elif defined(ENTRY_MAPPING_KEXEC_SETUP) +/* + * 6. Setup a 1:1 mapping in TLB1. Esel 0 is unsued, 1 or 2 contains the tmp + * mapping so we start at 3. We setup 8 mappings, each 256MiB in size. This + * will cover the first 2GiB of memory. + */ + + lis r10, (MAS1_VALID|MAS1_IPROT)@h + ori r10,r10, (MAS1_TSIZE(BOOK3E_PAGESZ_256M))@l + li r11, 0 + li r0, 8 + mtctr r0 + +next_tlb_setup: + addi r0, r11, 3 + rlwinm r0, r0, 16, 4, 15 // Compute esel + rlwinm r9, r11, 28, 0, 3 // Compute [ER]PN + oris r0, r0, (MAS0_TLBSEL(1))@h + mtspr SPRN_MAS0,r0 + mtspr SPRN_MAS1,r10 + mtspr SPRN_MAS2,r9 + ori r9, r9, (MAS3_SX|MAS3_SW|MAS3_SR) + mtspr SPRN_MAS3,r9 + tlbwe + addi r11, r11, 1 + bdnz+ next_tlb_setup + +/* 7. Jump to our 1:1 mapping */ + li r6, 0 + +#else + #error You need to specify the mapping or not use this at all. +#endif + lis r7,MSR_KERNEL@h ori r7,r7,MSR_KERNEL@l bl 1f /* Find our address */ diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 6b5b1f3b6112..4faeba247854 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -95,7 +95,9 @@ _ENTRY(_start); _ENTRY(__early_start) +#define ENTRY_MAPPING_BOOT_SETUP #include "fsl_booke_entry_mapping.S" +#undef ENTRY_MAPPING_BOOT_SETUP /* Establish the interrupt vector offsets */ SET_IVOR(0, CriticalInput); diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 8043d1b73cf0..dc66d52dcff5 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -711,6 +711,22 @@ relocate_new_kernel: /* r4 = reboot_code_buffer */ /* r5 = start_address */ +#ifdef CONFIG_FSL_BOOKE + + mr r29, r3 + mr r30, r4 + mr r31, r5 + +#define ENTRY_MAPPING_KEXEC_SETUP +#include "fsl_booke_entry_mapping.S" +#undef ENTRY_MAPPING_KEXEC_SETUP + + mr r3, r29 + mr r4, r30 + mr r5, r31 + + li r0, 0 +#else li r0, 0 /* @@ -727,6 +743,7 @@ relocate_new_kernel: rfi 1: +#endif /* from this point address translation is turned off */ /* and interrupts are disabled */ -- GitLab From 8081881327d4791f26ebf56cf304992673503ad4 Mon Sep 17 00:00:00 2001 From: Lan Chunhe-B25806 <B25806@freescale.com> Date: Mon, 15 Mar 2010 06:38:33 +0000 Subject: [PATCH 182/842] powerpc/fsl_msi: Add multiple MSI bank support Freescale QorIQ P4080 has three MSI banks and the original code can not work well. This patch adds multiple MSI banks support for Freescale processor. Signed-off-by: Lan Chunhe-B25806 <b25806@freescale.com> Signed-off-by: Roy Zang <tie-fei.zang@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/sysdev/fsl_msi.c | 40 ++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 3482e3fd89c0..c84fbb1c1b42 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. * * Author: Tony Li <tony.li@freescale.com> * Jason Jin <Jason.jin@freescale.com> @@ -29,7 +29,6 @@ struct fsl_msi_feature { u32 msiir_offset; }; -static struct fsl_msi *fsl_msi; static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg) { @@ -54,10 +53,12 @@ static struct irq_chip fsl_msi_chip = { static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { + struct fsl_msi *msi_data = h->host_data; struct irq_chip *chip = &fsl_msi_chip; irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING; + set_irq_chip_data(virq, msi_data); set_irq_chip_and_handler(virq, chip, handle_edge_irq); return 0; @@ -96,11 +97,12 @@ static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type) static void fsl_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; - struct fsl_msi *msi_data = fsl_msi; + struct fsl_msi *msi_data; list_for_each_entry(entry, &pdev->msi_list, list) { if (entry->irq == NO_IRQ) continue; + msi_data = get_irq_chip_data(entry->irq); set_irq_msi(entry->irq, NULL); msi_bitmap_free_hwirqs(&msi_data->bitmap, virq_to_hw(entry->irq), 1); @@ -111,9 +113,10 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev) } static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq, - struct msi_msg *msg) + struct msi_msg *msg, + struct fsl_msi *fsl_msi_data) { - struct fsl_msi *msi_data = fsl_msi; + struct fsl_msi *msi_data = fsl_msi_data; struct pci_controller *hose = pci_bus_to_host(pdev->bus); u32 base = 0; @@ -134,9 +137,11 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) unsigned int virq; struct msi_desc *entry; struct msi_msg msg; - struct fsl_msi *msi_data = fsl_msi; + struct fsl_msi *msi_data; list_for_each_entry(entry, &pdev->msi_list, list) { + msi_data = get_irq_chip_data(entry->irq); + hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); if (hwirq < 0) { rc = hwirq; @@ -156,7 +161,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) } set_irq_msi(virq, entry); - fsl_compose_msi_msg(pdev, hwirq, &msg); + fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data); write_msi_msg(virq, &msg); } return 0; @@ -168,7 +173,7 @@ out_free: static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) { unsigned int cascade_irq; - struct fsl_msi *msi_data = fsl_msi; + struct fsl_msi *msi_data = get_irq_chip_data(irq); int msir_index = -1; u32 msir_value = 0; u32 intr_index; @@ -193,7 +198,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) cascade_irq = NO_IRQ; desc->status |= IRQ_INPROGRESS; - switch (fsl_msi->feature & FSL_PIC_IP_MASK) { + switch (msi_data->feature & FSL_PIC_IP_MASK) { case FSL_PIC_IP_MPIC: msir_value = fsl_msi_read(msi_data->msi_regs, msir_index * 0x10); @@ -307,15 +312,20 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, if (virt_msir != NO_IRQ) { set_irq_data(virt_msir, (void *)i); set_irq_chained_handler(virt_msir, fsl_msi_cascade); + set_irq_chip_data(virt_msir, msi); } } - fsl_msi = msi; - - WARN_ON(ppc_md.setup_msi_irqs); - ppc_md.setup_msi_irqs = fsl_setup_msi_irqs; - ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs; - ppc_md.msi_check_device = fsl_msi_check_device; + /* The multiple setting ppc_md.setup_msi_irqs will not harm things */ + if (!ppc_md.setup_msi_irqs) { + ppc_md.setup_msi_irqs = fsl_setup_msi_irqs; + ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs; + ppc_md.msi_check_device = fsl_msi_check_device; + } else if (ppc_md.setup_msi_irqs != fsl_setup_msi_irqs) { + dev_err(&dev->dev, "Different MSI driver already installed!\n"); + err = -ENODEV; + goto error_out; + } return 0; error_out: kfree(msi); -- GitLab From 02adac6051b0ff8df3877ae3d94e0e68063c6a30 Mon Sep 17 00:00:00 2001 From: Li Yang <leoli@freescale.com> Date: Thu, 22 Apr 2010 16:31:35 +0800 Subject: [PATCH 183/842] powerpc/fsl_msi: fix the conflict of virt_msir's chip_data In fsl_of_msi_probe(), the virt_msir's chip_data have been stored the pointer to struct mpic. We add a struct fsl_msi_cascade_data to store the pointer to struct fsl_msi and msir_index in hanler_data. Otherwise, the pointer to struct mpic will be over-written, and will cause problem when calling eoi() of the irq. Signed-off-by: Zhao Chenhui <b26998@freescale.com> Signed-off-by: Li Yang <leoli@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/sysdev/fsl_msi.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index c84fbb1c1b42..b769982612a0 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -22,6 +22,7 @@ #include <asm/prom.h> #include <asm/hw_irq.h> #include <asm/ppc-pci.h> +#include <asm/mpic.h> #include "fsl_msi.h" struct fsl_msi_feature { @@ -29,6 +30,10 @@ struct fsl_msi_feature { u32 msiir_offset; }; +struct fsl_msi_cascade_data { + struct fsl_msi *msi_data; + int index; +}; static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg) { @@ -102,7 +107,7 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev) list_for_each_entry(entry, &pdev->msi_list, list) { if (entry->irq == NO_IRQ) continue; - msi_data = get_irq_chip_data(entry->irq); + msi_data = get_irq_data(entry->irq); set_irq_msi(entry->irq, NULL); msi_bitmap_free_hwirqs(&msi_data->bitmap, virq_to_hw(entry->irq), 1); @@ -133,7 +138,7 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq, static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { - int rc, hwirq; + int rc, hwirq = NO_IRQ; unsigned int virq; struct msi_desc *entry; struct msi_msg msg; @@ -159,6 +164,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) rc = -ENOSPC; goto out_free; } + set_irq_data(virq, msi_data); set_irq_msi(virq, entry); fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data); @@ -173,11 +179,15 @@ out_free: static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) { unsigned int cascade_irq; - struct fsl_msi *msi_data = get_irq_chip_data(irq); + struct fsl_msi *msi_data; int msir_index = -1; u32 msir_value = 0; u32 intr_index; u32 have_shift = 0; + struct fsl_msi_cascade_data *cascade_data; + + cascade_data = (struct fsl_msi_cascade_data *)get_irq_data(irq); + msi_data = cascade_data->msi_data; raw_spin_lock(&desc->lock); if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) { @@ -192,7 +202,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) if (unlikely(desc->status & IRQ_INPROGRESS)) goto unlock; - msir_index = (int)desc->handler_data; + msir_index = cascade_data->index; if (msir_index >= NR_MSI_REG) cascade_irq = NO_IRQ; @@ -244,6 +254,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, int virt_msir; const u32 *p; struct fsl_msi_feature *features = match->data; + struct fsl_msi_cascade_data *cascade_data = NULL; printk(KERN_DEBUG "Setting up Freescale MSI support\n"); @@ -310,9 +321,19 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, break; virt_msir = irq_of_parse_and_map(dev->node, i); if (virt_msir != NO_IRQ) { - set_irq_data(virt_msir, (void *)i); + cascade_data = kzalloc( + sizeof(struct fsl_msi_cascade_data), + GFP_KERNEL); + if (!cascade_data) { + dev_err(&dev->dev, + "No memory for MSI cascade data\n"); + err = -ENOMEM; + goto error_out; + } + cascade_data->index = i; + cascade_data->msi_data = msi; + set_irq_data(virt_msir, (void *)cascade_data); set_irq_chained_handler(virt_msir, fsl_msi_cascade); - set_irq_chip_data(virt_msir, msi); } } -- GitLab From 694a7a3611a1c0e28d99b4955151c6ce68e89752 Mon Sep 17 00:00:00 2001 From: Li Yang <leoli@freescale.com> Date: Thu, 22 Apr 2010 16:31:36 +0800 Subject: [PATCH 184/842] powerpc/fsl_msi: enable msi allocation in all banks Put all fsl_msi banks in a linked list. The list of banks then can be traversed when allocating new msi interrupts. Also fix failing path of fsl_setup_msi_irqs(). Signed-off-by: Zhao Chenhui <b26998@freescale.com> Signed-off-by: Li Yang <leoli@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/sysdev/fsl_msi.c | 14 +++++++++++--- arch/powerpc/sysdev/fsl_msi.h | 2 ++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index b769982612a0..efffcbd190a1 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -25,6 +25,8 @@ #include <asm/mpic.h> #include "fsl_msi.h" +LIST_HEAD(msi_head); + struct fsl_msi_feature { u32 fsl_pic_ip; u32 msiir_offset; @@ -138,16 +140,19 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq, static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { - int rc, hwirq = NO_IRQ; + int rc, hwirq = -ENOMEM; unsigned int virq; struct msi_desc *entry; struct msi_msg msg; struct fsl_msi *msi_data; list_for_each_entry(entry, &pdev->msi_list, list) { - msi_data = get_irq_chip_data(entry->irq); + list_for_each_entry(msi_data, &msi_head, list) { + hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); + if (hwirq >= 0) + break; + } - hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); if (hwirq < 0) { rc = hwirq; pr_debug("%s: fail allocating msi interrupt\n", @@ -173,6 +178,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) return 0; out_free: + /* free by the caller of this function */ return rc; } @@ -337,6 +343,8 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, } } + list_add_tail(&msi->list, &msi_head); + /* The multiple setting ppc_md.setup_msi_irqs will not harm things */ if (!ppc_md.setup_msi_irqs) { ppc_md.setup_msi_irqs = fsl_setup_msi_irqs; diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index 331c7e7025b7..8fc5523d6ee3 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -34,6 +34,8 @@ struct fsl_msi { u32 feature; struct msi_bitmap bitmap; + + struct list_head list; /* support multiple MSI banks */ }; #endif /* _POWERPC_SYSDEV_FSL_MSI_H */ -- GitLab From 061ca4adfb2e3c986a182fd30f7e939a1ff8d29d Mon Sep 17 00:00:00 2001 From: Li Yang <leoli@freescale.com> Date: Thu, 22 Apr 2010 16:31:37 +0800 Subject: [PATCH 185/842] powerpc/fsl_msi: enable msi sharing through AMP OSes Make a single PCIe MSI bank shareable through CAMP OSes. The number of MSI used by each core can be configured by dts file. Signed-off-by: Zhao Chenhui <b26998@freescale.com> Signed-off-by: Li Yang <leoli@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/sysdev/fsl_msi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index efffcbd190a1..1ab703915972 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -261,6 +261,8 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, const u32 *p; struct fsl_msi_feature *features = match->data; struct fsl_msi_cascade_data *cascade_data = NULL; + int len; + u32 offset; printk(KERN_DEBUG "Setting up Freescale MSI support\n"); @@ -320,6 +322,10 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, err = -EINVAL; goto error_out; } + offset = 0; + p = of_get_property(dev->node, "msi-available-ranges", &len); + if (p) + offset = *p / IRQS_PER_MSI_REG; count /= sizeof(u32); for (i = 0; i < count / 2; i++) { @@ -336,7 +342,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, err = -ENOMEM; goto error_out; } - cascade_data->index = i; + cascade_data->index = i + offset; cascade_data->msi_data = msi; set_irq_data(virt_msir, (void *)cascade_data); set_irq_chained_handler(virt_msir, fsl_msi_cascade); -- GitLab From 480599933a69a8a8dc1390c2164e49e20a1593b9 Mon Sep 17 00:00:00 2001 From: Li Yang <leoli@freescale.com> Date: Thu, 22 Apr 2010 16:31:39 +0800 Subject: [PATCH 186/842] powerpc/fsl_msi: add removal path and probe failing path Also cleanup the probe function. Signed-off-by: Li Yang <leoli@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/sysdev/fsl_msi.c | 36 +++++++++++++++++++++++++++++------ arch/powerpc/sysdev/fsl_msi.h | 1 + 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 1ab703915972..f7ca9e6fa5f0 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -250,6 +250,30 @@ unlock: raw_spin_unlock(&desc->lock); } +static int fsl_of_msi_remove(struct of_device *ofdev) +{ + struct fsl_msi *msi = ofdev->dev.platform_data; + int virq, i; + struct fsl_msi_cascade_data *cascade_data; + + if (msi->list.prev != NULL) + list_del(&msi->list); + for (i = 0; i < NR_MSI_REG; i++) { + virq = msi->msi_virqs[i]; + if (virq != NO_IRQ) { + cascade_data = get_irq_data(virq); + kfree(cascade_data); + irq_dispose_mapping(virq); + } + } + if (msi->bitmap.bitmap) + msi_bitmap_free(&msi->bitmap); + iounmap(msi->msi_regs); + kfree(msi); + + return 0; +} + static int __devinit fsl_of_msi_probe(struct of_device *dev, const struct of_device_id *match) { @@ -269,9 +293,9 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL); if (!msi) { dev_err(&dev->dev, "No memory for MSI structure\n"); - err = -ENOMEM; - goto error_out; + return -ENOMEM; } + dev->dev.platform_data = msi; msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR, NR_MSI_IRQS, &fsl_msi_host_ops, 0); @@ -328,9 +352,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, offset = *p / IRQS_PER_MSI_REG; count /= sizeof(u32); - for (i = 0; i < count / 2; i++) { - if (i > NR_MSI_REG) - break; + for (i = 0; i < min(count / 2, NR_MSI_REG); i++) { virt_msir = irq_of_parse_and_map(dev->node, i); if (virt_msir != NO_IRQ) { cascade_data = kzalloc( @@ -342,6 +364,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, err = -ENOMEM; goto error_out; } + msi->msi_virqs[i] = virt_msir; cascade_data->index = i + offset; cascade_data->msi_data = msi; set_irq_data(virt_msir, (void *)cascade_data); @@ -363,7 +386,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, } return 0; error_out: - kfree(msi); + fsl_of_msi_remove(dev); return err; } @@ -393,6 +416,7 @@ static struct of_platform_driver fsl_of_msi_driver = { .name = "fsl-msi", .match_table = fsl_of_msi_ids, .probe = fsl_of_msi_probe, + .remove = fsl_of_msi_remove, }; static __init int fsl_of_msi_init(void) diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index 8fc5523d6ee3..624580c252d7 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -32,6 +32,7 @@ struct fsl_msi { u32 msi_addr_hi; void __iomem *msi_regs; u32 feature; + int msi_virqs[NR_MSI_REG]; struct msi_bitmap bitmap; -- GitLab From 710e33832653cccf7fc432023e7dbe8c49a1902f Mon Sep 17 00:00:00 2001 From: Li Yang <leoli@freescale.com> Date: Thu, 22 Apr 2010 16:31:38 +0800 Subject: [PATCH 187/842] powerpc/85xx: Change MPC8572DS camp dtses for MSI sharing Enable the sharing of MSI interrupt through AMP OSes in the mpc8572ds dtses. Signed-off-by: Zhao Chenhui <b26998@freescale.com> Signed-off-by: Li Yang <leoli@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts | 15 +++++++++++++-- arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts | 7 ++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts b/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts index 5bd1011fde96..3375c2ab0c32 100644 --- a/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts +++ b/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts @@ -215,6 +215,18 @@ clock-frequency = <0>; }; + msi@41600 { + compatible = "fsl,mpc8572-msi", "fsl,mpic-msi"; + reg = <0x41600 0x80>; + msi-available-ranges = <0 0x80>; + interrupts = < + 0xe0 0 + 0xe1 0 + 0xe2 0 + 0xe3 0>; + interrupt-parent = <&mpic>; + }; + global-utilities@e0000 { //global utilities block compatible = "fsl,mpc8572-guts"; reg = <0xe0000 0x1000>; @@ -243,8 +255,7 @@ protected-sources = < 31 32 33 37 38 39 /* enet2 enet3 */ 76 77 78 79 26 42 /* dma2 pci2 serial*/ - 0xe0 0xe1 0xe2 0xe3 /* msi */ - 0xe4 0xe5 0xe6 0xe7 + 0xe4 0xe5 0xe6 0xe7 /* msi */ >; }; }; diff --git a/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts b/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts index 0efc3456e297..e7b477f6a3fe 100644 --- a/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts +++ b/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts @@ -154,12 +154,8 @@ msi@41600 { compatible = "fsl,mpc8572-msi", "fsl,mpic-msi"; reg = <0x41600 0x80>; - msi-available-ranges = <0 0x100>; + msi-available-ranges = <0x80 0x80>; interrupts = < - 0xe0 0 - 0xe1 0 - 0xe2 0 - 0xe3 0 0xe4 0 0xe5 0 0xe6 0 @@ -190,6 +186,7 @@ 0x1 0x2 0x3 0x4 /* pci slot */ 0x9 0xa 0xb 0xc /* usb */ 0x6 0x7 0xe 0x5 /* Audio elgacy SATA */ + 0xe0 0xe1 0xe2 0xe3 /* msi */ >; }; }; -- GitLab From 48936a08b85518c22a9467a8eaac35d43af54ab4 Mon Sep 17 00:00:00 2001 From: Haiying Wang <Haiying.Wang@freescale.com> Date: Fri, 21 May 2010 10:16:12 -0400 Subject: [PATCH 188/842] powerpc/85xx: Add P1021MDS board support P1021 is a dual e500v2 core based SOC with: * 3 eTSECs (eTSEC1/3 RGMII, eTSEC2 SGMII on this board) * 2 PCIe Controller * 1 USB2.0 controller * eSDHC, eSPI, I2C, DUART * eLBC (NAND, BCSR, PMC0/1) * Security Engine (SEC 3.3.2) * Quicc Engine (QE) Signed-off-by: Haiying Wang <Haiying.Wang@freescale.com> Signed-off-by: Yu Liu <Yu.Liu@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org> --- arch/powerpc/boot/dts/p1021mds.dts | 698 ++++++++++++++++++++++ arch/powerpc/platforms/85xx/mpc85xx_mds.c | 102 +++- 2 files changed, 797 insertions(+), 3 deletions(-) create mode 100644 arch/powerpc/boot/dts/p1021mds.dts diff --git a/arch/powerpc/boot/dts/p1021mds.dts b/arch/powerpc/boot/dts/p1021mds.dts new file mode 100644 index 000000000000..7fad2df25981 --- /dev/null +++ b/arch/powerpc/boot/dts/p1021mds.dts @@ -0,0 +1,698 @@ +/* + * P1021 MDS Device Tree Source + * + * Copyright 2010 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/dts-v1/; +/ { + model = "fsl,P1021"; + compatible = "fsl,P1021MDS"; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &serial0; + serial1 = &serial1; + ethernet0 = &enet0; + ethernet1 = &enet1; + ethernet2 = &enet2; + ethernet3 = &enet3; + ethernet4 = &enet4; + pci0 = &pci0; + pci1 = &pci1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,P1021@0 { + device_type = "cpu"; + reg = <0x0>; + next-level-cache = <&L2>; + }; + + PowerPC,P1021@1 { + device_type = "cpu"; + reg = <0x1>; + next-level-cache = <&L2>; + }; + }; + + memory { + device_type = "memory"; + }; + + localbus@ffe05000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "fsl,p1021-elbc", "fsl,elbc", "simple-bus"; + reg = <0 0xffe05000 0 0x1000>; + interrupts = <19 2>; + interrupt-parent = <&mpic>; + + /* NAND Flash, BCSR, PMC0/1*/ + ranges = <0x0 0x0 0x0 0xfc000000 0x02000000 + 0x1 0x0 0x0 0xf8000000 0x00008000 + 0x2 0x0 0x0 0xf8010000 0x00020000 + 0x3 0x0 0x0 0xf8020000 0x00020000>; + + nand@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p1021-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x0 0x0 0x40000>; + + partition@0 { + /* This location must not be altered */ + /* 1MB for u-boot Bootloader Image */ + reg = <0x0 0x00100000>; + label = "NAND (RO) U-Boot Image"; + read-only; + }; + + partition@100000 { + /* 1MB for DTB Image */ + reg = <0x00100000 0x00100000>; + label = "NAND (RO) DTB Image"; + read-only; + }; + + partition@200000 { + /* 4MB for Linux Kernel Image */ + reg = <0x00200000 0x00400000>; + label = "NAND (RO) Linux Kernel Image"; + read-only; + }; + + partition@600000 { + /* 5MB for Compressed Root file System Image */ + reg = <0x00600000 0x00500000>; + label = "NAND (RO) Compressed RFS Image"; + read-only; + }; + + partition@b00000 { + /* 6MB for JFFS2 based Root file System */ + reg = <0x00a00000 0x00600000>; + label = "NAND (RW) JFFS2 Root File System"; + }; + + partition@1100000 { + /* 14MB for JFFS2 based Root file System */ + reg = <0x01100000 0x00e00000>; + label = "NAND (RW) Writable User area"; + }; + + partition@1f00000 { + /* 1MB for microcode */ + reg = <0x01f00000 0x00100000>; + label = "NAND (RO) QE Ucode"; + read-only; + }; + }; + + bcsr@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p1021mds-bcsr"; + reg = <1 0 0x8000>; + ranges = <0 1 0 0x8000>; + }; + + pib@2,0 { + compatible = "fsl,p1021mds-pib"; + reg = <2 0 0x10000>; + }; + + pib@3,0 { + compatible = "fsl,p1021mds-pib"; + reg = <3 0 0x10000>; + }; + }; + + soc@ffe00000 { + + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "fsl,p1021-immr", "simple-bus"; + ranges = <0x0 0x0 0xffe00000 0x100000>; + bus-frequency = <0>; // Filled out by uboot. + + ecm-law@0 { + compatible = "fsl,ecm-law"; + reg = <0x0 0x1000>; + fsl,num-laws = <12>; + }; + + ecm@1000 { + compatible = "fsl,p1021-ecm", "fsl,ecm"; + reg = <0x1000 0x1000>; + interrupts = <16 2>; + interrupt-parent = <&mpic>; + }; + + memory-controller@2000 { + compatible = "fsl,p1021-memory-controller"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + i2c@3000 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + compatible = "fsl-i2c"; + reg = <0x3000 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + rtc@68 { + compatible = "dallas,ds1374"; + reg = <0x68>; + }; + }; + + i2c@3100 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <1>; + compatible = "fsl-i2c"; + reg = <0x3100 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + serial0: serial@4500 { + cell-index = <0>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4500 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + serial1: serial@4600 { + cell-index = <1>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4600 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + spi@7000 { + cell-index = <0>; + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,espi"; + reg = <0x7000 0x1000>; + interrupts = <59 0x2>; + interrupt-parent = <&mpic>; + espi,num-ss-bits = <4>; + mode = "cpu"; + + fsl_m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,espi-flash"; + reg = <0>; + linux,modalias = "fsl_m25p80"; + spi-max-frequency = <40000000>; /* input clock */ + partition@u-boot { + label = "u-boot-spi"; + reg = <0x00000000 0x00100000>; + read-only; + }; + partition@kernel { + label = "kernel-spi"; + reg = <0x00100000 0x00500000>; + read-only; + }; + partition@dtb { + label = "dtb-spi"; + reg = <0x00600000 0x00100000>; + read-only; + }; + partition@fs { + label = "file system-spi"; + reg = <0x00700000 0x00900000>; + }; + }; + }; + + gpio: gpio-controller@f000 { + #gpio-cells = <2>; + compatible = "fsl,mpc8572-gpio"; + reg = <0xf000 0x100>; + interrupts = <47 0x2>; + interrupt-parent = <&mpic>; + gpio-controller; + }; + + L2: l2-cache-controller@20000 { + compatible = "fsl,p1021-l2-cache-controller"; + reg = <0x20000 0x1000>; + cache-line-size = <32>; // 32 bytes + cache-size = <0x40000>; // L2,256K + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + dma@21300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,eloplus-dma"; + reg = <0x21300 0x4>; + ranges = <0x0 0x21100 0x200>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <20 2>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <21 2>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <22 2>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <23 2>; + }; + }; + + usb@22000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl-usb2-dr"; + reg = <0x22000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <28 0x2>; + phy_type = "ulpi"; + }; + + mdio@24000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,etsec2-mdio"; + reg = <0x24000 0x1000 0xb0030 0x4>; + + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <1 1>; + reg = <0x0>; + }; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <2 1>; + reg = <0x1>; + }; + phy4: ethernet-phy@4 { + interrupt-parent = <&mpic>; + reg = <0x4>; + }; + }; + + mdio@25000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,etsec2-tbi"; + reg = <0x25000 0x1000 0xb1030 0x4>; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@B0000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; + queue-group@0{ + #address-cells = <1>; + #size-cells = <1>; + reg = <0xB0000 0x1000>; + interrupts = <29 2 30 2 34 2>; + }; + queue-group@1{ + #address-cells = <1>; + #size-cells = <1>; + reg = <0xB4000 0x1000>; + interrupts = <17 2 18 2 24 2>; + }; + }; + + enet1: ethernet@B1000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + phy-handle = <&phy4>; + tbi-handle = <&tbi0>; + phy-connection-type = "sgmii"; + queue-group@0{ + #address-cells = <1>; + #size-cells = <1>; + reg = <0xB1000 0x1000>; + interrupts = <35 2 36 2 40 2>; + }; + queue-group@1{ + #address-cells = <1>; + #size-cells = <1>; + reg = <0xB5000 0x1000>; + interrupts = <51 2 52 2 67 2>; + }; + }; + + enet2: ethernet@B2000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + queue-group@0{ + #address-cells = <1>; + #size-cells = <1>; + reg = <0xB2000 0x1000>; + interrupts = <31 2 32 2 33 2>; + }; + queue-group@1{ + #address-cells = <1>; + #size-cells = <1>; + reg = <0xB6000 0x1000>; + interrupts = <25 2 26 2 27 2>; + }; + }; + + sdhci@2e000 { + compatible = "fsl,p1021-esdhc", "fsl,esdhc"; + reg = <0x2e000 0x1000>; + interrupts = <72 0x2>; + interrupt-parent = <&mpic>; + /* Filled in by U-Boot */ + clock-frequency = <0>; + }; + + crypto@30000 { + compatible = "fsl,sec3.3", "fsl,sec3.1", + "fsl,sec3.0", "fsl,sec2.4", + "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; + reg = <0x30000 0x10000>; + interrupts = <45 2 58 2>; + interrupt-parent = <&mpic>; + fsl,num-channels = <4>; + fsl,channel-fifo-len = <24>; + fsl,exec-units-mask = <0x97c>; + fsl,descriptor-types-mask = <0x3a30abf>; + }; + + mpic: pic@40000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x40000 0x40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + }; + + msi@41600 { + compatible = "fsl,p1021-msi", "fsl,mpic-msi"; + reg = <0x41600 0x80>; + msi-available-ranges = <0 0x100>; + interrupts = < + 0xe0 0 + 0xe1 0 + 0xe2 0 + 0xe3 0 + 0xe4 0 + 0xe5 0 + 0xe6 0 + 0xe7 0>; + interrupt-parent = <&mpic>; + }; + + global-utilities@e0000 { //global utilities block + compatible = "fsl,p1021-guts"; + reg = <0xe0000 0x1000>; + fsl,has-rstcr; + }; + + par_io@e0100 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xe0100 0x60>; + ranges = <0x0 0xe0100 0x60>; + device_type = "par_io"; + num-ports = <3>; + pio1: ucc_pin@01 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ + 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ + 0x0 0x17 0x2 0x0 0x2 0x0 /* CLK12 */ + 0x0 0x18 0x2 0x0 0x1 0x0 /* CLK9 +*/ + 0x0 0x7 0x1 0x0 0x2 0x0 /* ENET1_TXD0_SER1_TXD0 */ + 0x0 0x9 0x1 0x0 0x2 0x0 /* ENET1_TXD1_SER1_TXD1 */ + 0x0 0xb 0x1 0x0 0x2 0x0 /* ENET1_TXD2_SER1_TXD2 */ + 0x0 0xc 0x1 0x0 0x2 0x0 /* ENET1_TXD3_SER1_TXD3 */ + 0x0 0x6 0x2 0x0 0x2 0x0 /* ENET1_RXD0_SER1_RXD0 */ + 0x0 0xa 0x2 0x0 0x2 0x0 /* ENET1_RXD1_SER1_RXD1 */ + 0x0 0xe 0x2 0x0 0x2 0x0 /* ENET1_RXD2_SER1_RXD2 */ + 0x0 0xf 0x2 0x0 0x2 0x0 /* ENET1_RXD3_SER1_RXD3 */ + 0x0 0x5 0x1 0x0 0x2 0x0 /* ENET1_TX_EN_SER1_RTS_B */ + 0x0 0xd 0x1 0x0 0x2 0x0 /* ENET1_TX_ER */ + 0x0 0x4 0x2 0x0 0x2 0x0 /* ENET1_RX_DV_SER1_CTS_B */ + 0x0 0x8 0x2 0x0 0x2 0x0 /* ENET1_RX_ER_SER1_CD_B */ + 0x0 0x11 0x2 0x0 0x2 0x0 /* ENET1_CRS */ + 0x0 0x10 0x2 0x0 0x2 0x0>; /* ENET1_COL */ + }; + + pio2: ucc_pin@02 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ + 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ + 0x1 0xb 0x2 0x0 0x1 0x0 /* CLK13 */ + 0x1 0x7 0x1 0x0 0x2 0x0 /* ENET5_TXD0_SER5_TXD0 */ + 0x1 0xa 0x1 0x0 0x2 0x0 /* ENET5_TXD1_SER5_TXD1 */ + 0x1 0x6 0x2 0x0 0x2 0x0 /* ENET5_RXD0_SER5_RXD0 */ + 0x1 0x9 0x2 0x0 0x2 0x0 /* ENET5_RXD1_SER5_RXD1 */ + 0x1 0x5 0x1 0x0 0x2 0x0 /* ENET5_TX_EN_SER5_RTS_B */ + 0x1 0x4 0x2 0x0 0x2 0x0 /* ENET5_RX_DV_SER5_CTS_B */ + 0x1 0x8 0x2 0x0 0x2 0x0>; /* ENET5_RX_ER_SER5_CD_B */ + }; + }; + }; + + pci0: pcie@ffe09000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe09000 0 0x1000>; + bus-range = <0 255>; + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <16 2>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 4 1 + 0000 0 0 2 &mpic 5 1 + 0000 0 0 3 &mpic 6 1 + 0000 0 0 4 &mpic 7 1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@ffe0a000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe0a000 0 0x1000>; + bus-range = <0 255>; + ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <16 2>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 0 1 + 0000 0 0 2 &mpic 1 1 + 0000 0 0 3 &mpic 2 1 + 0000 0 0 4 &mpic 3 1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0xc0000000 + 0x2000000 0x0 0xc0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + qe@ffe80000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "qe"; + compatible = "fsl,qe"; + ranges = <0x0 0x0 0xffe80000 0x40000>; + reg = <0 0xffe80000 0 0x480>; + brg-frequency = <0>; + bus-frequency = <0>; + fsl,qe-num-riscs = <1>; + fsl,qe-num-snums = <28>; + + qeic: interrupt-controller@80 { + interrupt-controller; + compatible = "fsl,qe-ic"; + #address-cells = <0>; + #interrupt-cells = <1>; + reg = <0x80 0x80>; + interrupts = <63 2 60 2>; //high:47 low:44 + interrupt-parent = <&mpic>; + }; + + enet3: ucc@2000 { + device_type = "network"; + compatible = "ucc_geth"; + cell-index = <1>; + reg = <0x2000 0x200>; + interrupts = <32>; + interrupt-parent = <&qeic>; + local-mac-address = [ 00 00 00 00 00 00 ]; + rx-clock-name = "clk12"; + tx-clock-name = "clk9"; + pio-handle = <&pio1>; + phy-handle = <&qe_phy0>; + phy-connection-type = "mii"; + }; + + mdio@2120 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2120 0x18>; + compatible = "fsl,ucc-mdio"; + + qe_phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <4 1>; + reg = <0x0>; + device_type = "ethernet-phy"; + }; + qe_phy1: ethernet-phy@03 { + interrupt-parent = <&mpic>; + interrupts = <5 1>; + reg = <0x3>; + device_type = "ethernet-phy"; + }; + tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet4: ucc@2400 { + device_type = "network"; + compatible = "ucc_geth"; + cell-index = <5>; + reg = <0x2400 0x200>; + interrupts = <40>; + interrupt-parent = <&qeic>; + local-mac-address = [ 00 00 00 00 00 00 ]; + rx-clock-name = "none"; + tx-clock-name = "clk13"; + pio-handle = <&pio2>; + phy-handle = <&qe_phy1>; + phy-connection-type = "rmii"; + }; + + muram@10000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,qe-muram", "fsl,cpm-muram"; + ranges = <0x0 0x10000 0x6000>; + + data-only@0 { + compatible = "fsl,qe-muram-data", + "fsl,cpm-muram-data"; + reg = <0x0 0x6000>; + }; + }; + }; +}; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index f0684c8ac960..8fe87fc61485 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) Freescale Semicondutor, Inc. 2006-2007. All rights reserved. + * Copyright (C) Freescale Semicondutor, Inc. 2006-2010. All rights reserved. * * Author: Andy Fleming <afleming@freescale.com> * @@ -154,6 +154,10 @@ static int mpc8568_mds_phy_fixups(struct phy_device *phydev) * Setup the architecture * */ +#ifdef CONFIG_SMP +extern void __init mpc85xx_smp_init(void); +#endif + static void __init mpc85xx_mds_setup_arch(void) { struct device_node *np; @@ -194,6 +198,10 @@ static void __init mpc85xx_mds_setup_arch(void) } #endif +#ifdef CONFIG_SMP + mpc85xx_smp_init(); +#endif + #ifdef CONFIG_QUICC_ENGINE np = of_find_compatible_node(NULL, NULL, "fsl,qe"); if (!np) { @@ -271,9 +279,49 @@ static void __init mpc85xx_mds_setup_arch(void) BCSR_UCC_RGMII, BCSR_UCC_RTBI); } + } else if (machine_is(p1021_mds)) { +#define BCSR11_ENET_MICRST (0x1 << 5) + /* Reset Micrel PHY */ + clrbits8(&bcsr_regs[11], BCSR11_ENET_MICRST); + setbits8(&bcsr_regs[11], BCSR11_ENET_MICRST); } + iounmap(bcsr_regs); } + + if (machine_is(p1021_mds)) { +#define MPC85xx_PMUXCR_OFFSET 0x60 +#define MPC85xx_PMUXCR_QE0 0x00008000 +#define MPC85xx_PMUXCR_QE3 0x00001000 +#define MPC85xx_PMUXCR_QE9 0x00000040 +#define MPC85xx_PMUXCR_QE12 0x00000008 + static __be32 __iomem *pmuxcr; + + np = of_find_node_by_name(NULL, "global-utilities"); + + if (np) { + pmuxcr = of_iomap(np, 0) + MPC85xx_PMUXCR_OFFSET; + + if (!pmuxcr) + printk(KERN_EMERG "Error: Alternate function" + " signal multiplex control register not" + " mapped!\n"); + else + /* P1021 has pins muxed for QE and other functions. To + * enable QE UEC mode, we need to set bit QE0 for UCC1 + * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 + * and QE12 for QE MII management singals in PMUXCR + * register. + */ + setbits32(pmuxcr, MPC85xx_PMUXCR_QE0 | + MPC85xx_PMUXCR_QE3 | + MPC85xx_PMUXCR_QE9 | + MPC85xx_PMUXCR_QE12); + + of_node_put(np); + } + + } #endif /* CONFIG_QUICC_ENGINE */ #ifdef CONFIG_SWIOTLB @@ -330,6 +378,16 @@ static struct of_device_id mpc85xx_ids[] = { {}, }; +static struct of_device_id p1021_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + { .compatible = "simple-bus", }, + { .type = "qe", }, + { .compatible = "fsl,qe", }, + { .compatible = "gianfar", }, + {}, +}; + static int __init mpc85xx_publish_devices(void) { if (machine_is(mpc8568_mds)) @@ -342,11 +400,22 @@ static int __init mpc85xx_publish_devices(void) return 0; } + +static int __init p1021_publish_devices(void) +{ + /* Publish the QE devices */ + of_platform_bus_probe(NULL, p1021_ids, NULL); + + return 0; +} + machine_device_initcall(mpc8568_mds, mpc85xx_publish_devices); machine_device_initcall(mpc8569_mds, mpc85xx_publish_devices); +machine_device_initcall(p1021_mds, p1021_publish_devices); machine_arch_initcall(mpc8568_mds, swiotlb_setup_bus_notifier); machine_arch_initcall(mpc8569_mds, swiotlb_setup_bus_notifier); +machine_arch_initcall(p1021_mds, swiotlb_setup_bus_notifier); static void __init mpc85xx_mds_pic_init(void) { @@ -366,7 +435,7 @@ static void __init mpc85xx_mds_pic_init(void) mpic = mpic_alloc(np, r.start, MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | - MPIC_BROKEN_FRR_NIRQS, + MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); of_node_put(np); @@ -380,7 +449,11 @@ static void __init mpc85xx_mds_pic_init(void) if (!np) return; } - qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL); + if (machine_is(p1021_mds)) + qe_ic_init(np, 0, qe_ic_cascade_low_mpic, + qe_ic_cascade_high_mpic); + else + qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL); of_node_put(np); #endif /* CONFIG_QUICC_ENGINE */ } @@ -426,3 +499,26 @@ define_machine(mpc8569_mds) { .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #endif }; + +static int __init p1021_mds_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,P1021MDS"); + +} + +define_machine(p1021_mds) { + .name = "P1021 MDS", + .probe = p1021_mds_probe, + .setup_arch = mpc85xx_mds_setup_arch, + .init_IRQ = mpc85xx_mds_pic_init, + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif +}; + -- GitLab From 14baf9d7f275f0bbf42c1216ff1eef1109ca42ba Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Mon, 24 May 2010 16:31:08 +0900 Subject: [PATCH 189/842] serial: sh-sci: fix up serial DMA build. asm/dmaengine.h no longer exists, update for the shared linux/sh_dma.h header. Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- include/linux/serial_sci.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index f5364a1de68b..baed2122c5a6 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -2,9 +2,7 @@ #define __LINUX_SERIAL_SCI_H #include <linux/serial_core.h> -#ifdef CONFIG_SERIAL_SH_SCI_DMA -#include <asm/dmaengine.h> -#endif +#include <linux/sh_dma.h> /* * Generic header for SuperH SCI(F) (used by sh/sh64/h8300 and related parts) -- GitLab From e1f42ff4f06e5feaa57a22556ad977ef62164e14 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Date: Mon, 24 May 2010 07:53:24 +0000 Subject: [PATCH 190/842] fbdev: fix erroneous index in drivers/video/sh_mobile_lcdcfb.c Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- drivers/video/sh_mobile_lcdcfb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index e8c769944812..12c451a711e9 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -991,13 +991,13 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) priv->ch[j].lcdc = priv; memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); - error = sh_mobile_lcdc_check_interface(&priv->ch[i]); + error = sh_mobile_lcdc_check_interface(&priv->ch[j]); if (error) { dev_err(&pdev->dev, "unsupported interface type\n"); goto err1; } - init_waitqueue_head(&priv->ch[i].frame_end_wait); - init_completion(&priv->ch[i].vsync_completion); + init_waitqueue_head(&priv->ch[j].frame_end_wait); + init_completion(&priv->ch[j].vsync_completion); priv->ch[j].pan_offset = 0; switch (pdata->ch[i].chan) { -- GitLab From 8a37f520523df971bd3f926d8bd45ead37e857e8 Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Tue, 25 May 2010 16:16:40 +0900 Subject: [PATCH 191/842] sh: handle early calls to return_address() when using dwarf unwinder. The dwarf unwinder ties in to an early initcall, but it's possible that return_address() calls will be made prior to that. This implements some additional error handling in to the dwarf unwinder as well as an exit path in the return_address() case to bail out if the unwinder hasn't come up yet. This fixes a NULL pointer deref in early boot when mempool_alloc() blows up on the not-yet-ready mempool via dwarf_unwind_stack(). Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/kernel/dwarf.c | 19 +++++++++++++++++-- arch/sh/kernel/return_address.c | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index 886d7d83ace3..49c09c7d5b77 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c @@ -49,6 +49,8 @@ static DEFINE_SPINLOCK(dwarf_fde_lock); static struct dwarf_cie *cached_cie; +static unsigned int dwarf_unwinder_ready; + /** * dwarf_frame_alloc_reg - allocate memory for a DWARF register * @frame: the DWARF frame whose list of registers we insert on @@ -581,6 +583,13 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc, struct dwarf_reg *reg; unsigned long addr; + /* + * If we've been called in to before initialization has + * completed, bail out immediately. + */ + if (!dwarf_unwinder_ready) + return NULL; + /* * If we're starting at the top of the stack we need get the * contents of a physical register to get the CFA in order to @@ -1167,7 +1176,7 @@ void module_dwarf_cleanup(struct module *mod) */ static int __init dwarf_unwinder_init(void) { - int err; + int err = -ENOMEM; dwarf_frame_cachep = kmem_cache_create("dwarf_frames", sizeof(struct dwarf_frame), 0, @@ -1181,11 +1190,15 @@ static int __init dwarf_unwinder_init(void) mempool_alloc_slab, mempool_free_slab, dwarf_frame_cachep); + if (!dwarf_frame_pool) + goto out; dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ, mempool_alloc_slab, mempool_free_slab, dwarf_reg_cachep); + if (!dwarf_reg_pool) + goto out; err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL); if (err) @@ -1195,11 +1208,13 @@ static int __init dwarf_unwinder_init(void) if (err) goto out; + dwarf_unwinder_ready = 1; + return 0; out: printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err); dwarf_unwinder_cleanup(); - return -EINVAL; + return err; } early_initcall(dwarf_unwinder_init); diff --git a/arch/sh/kernel/return_address.c b/arch/sh/kernel/return_address.c index cbf1dd5372b2..5124aeb28c3f 100644 --- a/arch/sh/kernel/return_address.c +++ b/arch/sh/kernel/return_address.c @@ -24,6 +24,8 @@ void *return_address(unsigned int depth) struct dwarf_frame *tmp; tmp = dwarf_unwind_stack(ra, frame); + if (!tmp) + return NULL; if (frame) dwarf_free_frame(frame); -- GitLab From d02a2c077fb81f3224c770be62a318165b23b486 Mon Sep 17 00:00:00 2001 From: Shaohua Li <shaohua.li@intel.com> Date: Tue, 25 May 2010 10:16:53 +0200 Subject: [PATCH 192/842] cfq-iosched: fix an oops caused by slab leak I got below oops when unloading cfq-iosched. Considering scenario: queue A merge to B, C merge to D and B will be merged to D. Before B is merged to D, we do split B. We should put B's reference for D. [ 807.768536] ============================================================================= [ 807.768539] BUG cfq_queue: Objects remaining on kmem_cache_close() [ 807.768541] ----------------------------------------------------------------------------- [ 807.768543] [ 807.768546] INFO: Slab 0xffffea0003e6b4e0 objects=26 used=1 fp=0xffff88011d584fd8 flags=0x200000000004082 [ 807.768550] Pid: 5946, comm: rmmod Tainted: G W 2.6.34-07097-gf4b87de-dirty #724 [ 807.768552] Call Trace: [ 807.768560] [<ffffffff81104e8d>] slab_err+0x8f/0x9d [ 807.768564] [<ffffffff811059e1>] ? flush_cpu_slab+0x0/0x93 [ 807.768569] [<ffffffff8164be52>] ? add_preempt_count+0xe/0xca [ 807.768572] [<ffffffff8164bd9c>] ? sub_preempt_count+0xe/0xb6 [ 807.768577] [<ffffffff81648871>] ? _raw_spin_unlock+0x15/0x30 [ 807.768580] [<ffffffff8164bd9c>] ? sub_preempt_count+0xe/0xb6 [ 807.768584] [<ffffffff811061bc>] list_slab_objects+0x9b/0x19f [ 807.768588] [<ffffffff8164bf0a>] ? add_preempt_count+0xc6/0xca [ 807.768591] [<ffffffff81109e27>] kmem_cache_destroy+0x13f/0x21d [ 807.768597] [<ffffffffa000ff13>] cfq_slab_kill+0x1a/0x43 [cfq_iosched] [ 807.768601] [<ffffffffa000ffcf>] cfq_exit+0x93/0x9e [cfq_iosched] [ 807.768606] [<ffffffff810973a2>] sys_delete_module+0x1b1/0x219 [ 807.768612] [<ffffffff8102fb5b>] system_call_fastpath+0x16/0x1b [ 807.768618] INFO: Object 0xffff88011d584618 @offset=1560 [ 807.768622] INFO: Allocated in cfq_get_queue+0x11e/0x274 [cfq_iosched] age=7173 cpu=1 pid=5496 [ 807.768626] ============================================================================= Cc: stable@kernel.org Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com> --- block/cfq-iosched.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index c72e5acc573d..5ff4f4850e71 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -2560,15 +2560,10 @@ static void cfq_free_io_context(struct io_context *ioc) __call_for_each_cic(ioc, cic_free_func); } -static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) +static void cfq_put_cooperator(struct cfq_queue *cfqq) { struct cfq_queue *__cfqq, *next; - if (unlikely(cfqq == cfqd->active_queue)) { - __cfq_slice_expired(cfqd, cfqq, 0); - cfq_schedule_dispatch(cfqd); - } - /* * If this queue was scheduled to merge with another queue, be * sure to drop the reference taken on that queue (and others in @@ -2584,6 +2579,16 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) cfq_put_queue(__cfqq); __cfqq = next; } +} + +static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) +{ + if (unlikely(cfqq == cfqd->active_queue)) { + __cfq_slice_expired(cfqd, cfqq, 0); + cfq_schedule_dispatch(cfqd); + } + + cfq_put_cooperator(cfqq); cfq_put_queue(cfqq); } @@ -3536,6 +3541,9 @@ split_cfqq(struct cfq_io_context *cic, struct cfq_queue *cfqq) } cic_set_cfqq(cic, NULL, 1); + + cfq_put_cooperator(cfqq); + cfq_put_queue(cfqq); return NULL; } -- GitLab From 0ae0b5d0557264bad65e22f1e2da4b83a02c4535 Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Tue, 25 May 2010 10:25:26 +0200 Subject: [PATCH 193/842] fs/splice.c: fix mapping_gfp_mask usage mapping_gfp_mask() is not supposed to store allocation contex details, only page location details. So mapping_gfp_mask should be applied to the pagecache page allocation, wheras normal (kernel mapped) memory should be used for surrounding allocations such as radix-tree nodes allocated by add_to_page_cache. Context modifiers should be applied on a per-callsite basis. So change splice to follow this convention (which is followed in similar code patterns in core code). Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jens Axboe <jens.axboe@oracle.com> --- fs/splice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/splice.c b/fs/splice.c index ac22b00d86c3..740e6b9faf7a 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -354,7 +354,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, break; error = add_to_page_cache_lru(page, mapping, index, - mapping_gfp_mask(mapping)); + GFP_KERNEL); if (unlikely(error)) { page_cache_release(page); if (error == -EEXIST) -- GitLab From 4b3fb4e79cc3e40ec033a77f1b3d81e7851a6cf5 Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Tue, 25 May 2010 19:47:12 +0900 Subject: [PATCH 194/842] input: serio: disable i8042 for non-cayman sh platforms. The sh64 cayman platform is the only sh board that ships with an i8042, so we just hide it for all of the others. Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- drivers/input/serio/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index f34f1dbeb577..3bfe8fafc6ad 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -21,7 +21,8 @@ if SERIO config SERIO_I8042 tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86 default y - depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K && !BLACKFIN + depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \ + (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN help i8042 is the chip over which the standard AT keyboard and PS/2 mouse are connected to the computer. If you use these devices, -- GitLab From f06d8b694c9c96d460990888561b3ab3a5f8192f Mon Sep 17 00:00:00 2001 From: Jesper Nilsson <jesper.nilsson@axis.com> Date: Tue, 25 May 2010 13:33:51 +0200 Subject: [PATCH 195/842] CRISv32: Remove duplicated Kconfig items. The items were duplicated when they should have been moved. Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com> --- arch/cris/arch-v32/drivers/Kconfig | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index b9e328e688be..fdf3faafca99 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig @@ -364,20 +364,6 @@ config ETRAX_SER3_CD_BIT string "Ser 4 CD bit (empty = not used)" depends on ETRAX_SERIAL_PORT4 -config ETRAX_RS485 - bool "RS-485 support" - depends on ETRAXFS_SERIAL - help - Enables support for RS-485 serial communication. For a primer on - RS-485, see <http://www.hw.cz/english/docs/rs485/rs485.html>. - -config ETRAX_RS485_DISABLE_RECEIVER - bool "Disable serial receiver" - depends on ETRAX_RS485 - help - It is necessary to disable the serial receiver to avoid serial - loopback. Not all products are able to do this in software only. - config ETRAX_SYNCHRONOUS_SERIAL bool "Synchronous serial-port support" depends on ETRAX_ARCH_V32 -- GitLab From d708b41c96f404b8bb572f39973bbdf6d99d5f4b Mon Sep 17 00:00:00 2001 From: Jesper Nilsson <jesper.nilsson@axis.com> Date: Tue, 25 May 2010 13:35:31 +0200 Subject: [PATCH 196/842] CRISv32: Fix RS485 port 4 CD Kconfig item. The Kconfig item for port 4 CD was controlled by the same Kconfig item as for port 3. Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com> --- arch/cris/arch-v32/drivers/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index fdf3faafca99..a2dd740c5907 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig @@ -360,7 +360,7 @@ config ETRAX_SER4_DSR_BIT string "Ser 4 DSR bit (empty = not used)" depends on ETRAX_SERIAL_PORT4 -config ETRAX_SER3_CD_BIT +config ETRAX_SER4_CD_BIT string "Ser 4 CD bit (empty = not used)" depends on ETRAX_SERIAL_PORT4 -- GitLab From 2f941a1be362cc2966ccb63cf15ccdfdb12a5a69 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson <jesper.nilsson@axis.com> Date: Tue, 25 May 2010 14:55:54 +0200 Subject: [PATCH 197/842] CRISv10: Trivial fixes. - Removed CVS id tag. - Formatting fixes Signed-off-by: Andrea Gelmini <andrea.gelmini@gelma.net> Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com> --- arch/cris/arch-v10/lib/dmacopy.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/cris/arch-v10/lib/dmacopy.c b/arch/cris/arch-v10/lib/dmacopy.c index e5fb44f505c5..49f5b8ca5b47 100644 --- a/arch/cris/arch-v10/lib/dmacopy.c +++ b/arch/cris/arch-v10/lib/dmacopy.c @@ -1,5 +1,4 @@ -/* $Id: dmacopy.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ - * +/* * memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax */ @@ -13,11 +12,11 @@ void *dma_memcpy(void *pdst, unsigned int pn) { static etrax_dma_descr indma, outdma; - - D(printk("dma_memcpy %d bytes... ", pn)); + + D(printk(KERN_DEBUG "dma_memcpy %d bytes... ", pn)); #if 0 - *R_GEN_CONFIG = genconfig_shadow = + *R_GEN_CONFIG = genconfig_shadow = (genconfig_shadow & ~0x3c0000) | IO_STATE(R_GEN_CONFIG, dma6, intdma7) | IO_STATE(R_GEN_CONFIG, dma7, intdma6); @@ -32,11 +31,11 @@ void *dma_memcpy(void *pdst, *R_DMA_CH7_FIRST = &outdma; *R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, start); *R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, start); - - while(*R_DMA_CH7_CMD == 1) /* wait for completion */ ; - D(printk("done\n")); + while (*R_DMA_CH7_CMD == 1) + /* wait for completion */; + D(printk(KERN_DEBUG "done\n")); } -- GitLab From 6b9c88e2a3961346db1a23d967585af16ff33f05 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson <jesper.nilsson@axis.com> Date: Tue, 25 May 2010 15:04:06 +0200 Subject: [PATCH 198/842] CRISv10: Whitespace fixes for hw_settings.S Remove trailing whitespace. Signed-off-by: Andrea Gelmini <andrea.gelmini@gelma.net> Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com> --- arch/cris/arch-v10/lib/hw_settings.S | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/arch/cris/arch-v10/lib/hw_settings.S b/arch/cris/arch-v10/lib/hw_settings.S index 56905aaa7b6e..c09f19f478a5 100644 --- a/arch/cris/arch-v10/lib/hw_settings.S +++ b/arch/cris/arch-v10/lib/hw_settings.S @@ -1,13 +1,11 @@ /* - * $Id: hw_settings.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ - * * This table is used by some tools to extract hardware parameters. * The table should be included in the kernel and the decompressor. * Don't forget to update the tools if you change this table. * * Copyright (C) 2001 Axis Communications AB * - * Authors: Mikael Starvik (starvik@axis.com) + * Authors: Mikael Starvik (starvik@axis.com) */ #define PA_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PA_DIR << 8) | \ @@ -15,13 +13,13 @@ #define PB_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG << 16) | \ (CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \ (CONFIG_ETRAX_DEF_R_PORT_PB_DATA)) - + .ascii "HW_PARAM_MAGIC" ; Magic number .dword 0xc0004000 ; Kernel start address ; Debug port #ifdef CONFIG_ETRAX_DEBUG_PORT0 - .dword 0 + .dword 0 #elif defined(CONFIG_ETRAX_DEBUG_PORT1) .dword 1 #elif defined(CONFIG_ETRAX_DEBUG_PORT2) @@ -30,7 +28,7 @@ .dword 3 #else .dword 4 ; No debug -#endif +#endif ; SDRAM or EDO DRAM? #ifdef CONFIG_ETRAX_SDRAM @@ -39,7 +37,7 @@ .dword 0 #endif - ; Register values + ; Register values .dword R_WAITSTATES .dword CONFIG_ETRAX_DEF_R_WAITSTATES .dword R_BUS_CONFIG @@ -56,7 +54,7 @@ .dword CONFIG_ETRAX_DEF_R_DRAM_TIMING #endif .dword R_PORT_PA_SET - .dword PA_SET_VALUE + .dword PA_SET_VALUE .dword R_PORT_PB_SET .dword PB_SET_VALUE .dword 0 ; No more register values -- GitLab From 392ed655262446a7d9bc678394600a1d81614313 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson <jesper.nilsson@axis.com> Date: Tue, 25 May 2010 16:50:04 +0200 Subject: [PATCH 199/842] CRIS: Simplify param.h by simply including <asm-generic/param.h> Signed-off-by: Robert P. J. Day <rpjday@crashcourse.ca> Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com> --- arch/cris/include/asm/param.h | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/arch/cris/include/asm/param.h b/arch/cris/include/asm/param.h index 0e47994e40be..484fcf8667c0 100644 --- a/arch/cris/include/asm/param.h +++ b/arch/cris/include/asm/param.h @@ -2,22 +2,9 @@ #define _ASMCRIS_PARAM_H /* Currently we assume that HZ=100 is good for CRIS. */ -#ifdef __KERNEL__ -# define HZ CONFIG_HZ /* Internal kernel timer frequency */ -# define USER_HZ 100 /* .. some user interfaces are in "ticks" */ -# define CLOCKS_PER_SEC (USER_HZ) /* like times() */ -#endif - -#ifndef HZ -#define HZ 100 -#endif #define EXEC_PAGESIZE 8192 -#ifndef NOGROUP -#define NOGROUP (-1) -#endif - -#define MAXHOSTNAMELEN 64 /* max length of hostname */ +#include <asm-generic/param.h> -#endif +#endif /* _ASMCRIS_PARAM_H */ -- GitLab From 4150764fbba03ce4675b02b10872c665bb05a8aa Mon Sep 17 00:00:00 2001 From: Jesper Nilsson <jesper.nilsson@axis.com> Date: Tue, 25 May 2010 17:48:14 +0200 Subject: [PATCH 200/842] CRIS: Don't use mask_irq as symbol name kernel/irq/chip.c now uses these, which lead to compile error for CRISv32. Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com> --- arch/cris/arch-v10/kernel/irq.c | 8 ++++---- arch/cris/arch-v32/kernel/crisksyms.c | 4 ++-- arch/cris/arch-v32/kernel/irq.c | 14 ++++++-------- arch/cris/arch-v32/kernel/smp.c | 4 ++-- arch/cris/include/arch-v10/arch/irq.h | 9 +++++---- arch/cris/include/arch-v32/arch/irq.h | 4 ++-- 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c index 1a61efc13982..a0c0df8be9c8 100644 --- a/arch/cris/arch-v10/kernel/irq.c +++ b/arch/cris/arch-v10/kernel/irq.c @@ -17,8 +17,8 @@ #include <linux/kernel.h> #include <linux/init.h> -#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr)); -#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr)); +#define crisv10_mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr)); +#define crisv10_unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr)); /* don't use set_int_vector, it bypasses the linux interrupt handlers. it is * global just so that the kernel gdb can use it. @@ -116,12 +116,12 @@ static unsigned int startup_crisv10_irq(unsigned int irq) static void enable_crisv10_irq(unsigned int irq) { - unmask_irq(irq); + crisv10_unmask_irq(irq); } static void disable_crisv10_irq(unsigned int irq) { - mask_irq(irq); + crisv10_mask_irq(irq); } static void ack_crisv10_irq(unsigned int irq) diff --git a/arch/cris/arch-v32/kernel/crisksyms.c b/arch/cris/arch-v32/kernel/crisksyms.c index 64933e2c0f5b..bde8d1a10cad 100644 --- a/arch/cris/arch-v32/kernel/crisksyms.c +++ b/arch/cris/arch-v32/kernel/crisksyms.c @@ -24,5 +24,5 @@ EXPORT_SYMBOL(crisv32_io_get_name); EXPORT_SYMBOL(crisv32_io_get); /* Functions masking/unmasking interrupts */ -EXPORT_SYMBOL(mask_irq); -EXPORT_SYMBOL(unmask_irq); +EXPORT_SYMBOL(crisv32_mask_irq); +EXPORT_SYMBOL(crisv32_unmask_irq); diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c index b6241198fb98..0b1febe44aa3 100644 --- a/arch/cris/arch-v32/kernel/irq.c +++ b/arch/cris/arch-v32/kernel/irq.c @@ -280,8 +280,7 @@ out: return cpu; } -void -mask_irq(int irq) +void crisv32_mask_irq(int irq) { int cpu; @@ -289,8 +288,7 @@ mask_irq(int irq) block_irq(irq, cpu); } -void -unmask_irq(int irq) +void crisv32_unmask_irq(int irq) { unblock_irq(irq, irq_cpu(irq)); } @@ -298,23 +296,23 @@ unmask_irq(int irq) static unsigned int startup_crisv32_irq(unsigned int irq) { - unmask_irq(irq); + crisv32_unmask_irq(irq); return 0; } static void shutdown_crisv32_irq(unsigned int irq) { - mask_irq(irq); + crisv32_mask_irq(irq); } static void enable_crisv32_irq(unsigned int irq) { - unmask_irq(irq); + crisv32_unmask_irq(irq); } static void disable_crisv32_irq(unsigned int irq) { - mask_irq(irq); + crisv32_mask_irq(irq); } static void ack_crisv32_irq(unsigned int irq) diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c index 058adddf4e4b..84fed3b4b079 100644 --- a/arch/cris/arch-v32/kernel/smp.c +++ b/arch/cris/arch-v32/kernel/smp.c @@ -168,8 +168,8 @@ void __init smp_callin(void) /* Enable IRQ and idle */ REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask); - unmask_irq(IPI_INTR_VECT); - unmask_irq(TIMER0_INTR_VECT); + crisv32_unmask_irq(IPI_INTR_VECT); + crisv32_unmask_irq(TIMER0_INTR_VECT); preempt_disable(); notify_cpu_starting(cpu); local_irq_enable(); diff --git a/arch/cris/include/arch-v10/arch/irq.h b/arch/cris/include/arch-v10/arch/irq.h index 6248004eca1c..7d345947b3ee 100644 --- a/arch/cris/include/arch-v10/arch/irq.h +++ b/arch/cris/include/arch-v10/arch/irq.h @@ -93,15 +93,16 @@ void set_break_vector(int n, irqvectptr addr); "push $r10\n\t" /* push orig_r10 */ \ "clear.d [$sp=$sp-4]\n\t" /* frametype - this is a normal stackframe */ - /* BLOCK_IRQ and UNBLOCK_IRQ do the same as mask_irq and unmask_irq */ +/* BLOCK_IRQ and UNBLOCK_IRQ do the same as + * crisv10_mask_irq and crisv10_unmask_irq */ #define BLOCK_IRQ(mask,nr) \ "move.d " #mask ",$r0\n\t" \ - "move.d $r0,[0xb00000d8]\n\t" - + "move.d $r0,[0xb00000d8]\n\t" + #define UNBLOCK_IRQ(mask) \ "move.d " #mask ",$r0\n\t" \ - "move.d $r0,[0xb00000dc]\n\t" + "move.d $r0,[0xb00000dc]\n\t" #define IRQ_NAME2(nr) nr##_interrupt(void) #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) diff --git a/arch/cris/include/arch-v32/arch/irq.h b/arch/cris/include/arch-v32/arch/irq.h index 9e4c9fbdfddf..b31e9984f849 100644 --- a/arch/cris/include/arch-v32/arch/irq.h +++ b/arch/cris/include/arch-v32/arch/irq.h @@ -23,8 +23,8 @@ struct etrax_interrupt_vector { extern struct etrax_interrupt_vector *etrax_irv; /* head.S */ -void mask_irq(int irq); -void unmask_irq(int irq); +void crisv32_mask_irq(int irq); +void crisv32_unmask_irq(int irq); void set_exception_vector(int n, irqvectptr addr); -- GitLab From ff6c7341e0bc486c3e1b369ab7f3b325b98600d3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" <davem@davemloft.net> Date: Tue, 25 May 2010 17:37:08 -0700 Subject: [PATCH 201/842] n2_crypto: Fix build after of_device/of_platform_driver changes. Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/crypto/n2_core.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 8566be832f51..1a5b1e709d67 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1398,7 +1398,7 @@ static int find_devino_index(struct of_device *dev, struct spu_mdesc_info *ip, intr = ip->ino_table[i].intr; - dev_intrs = of_get_property(dev->node, "interrupts", NULL); + dev_intrs = of_get_property(dev->dev.of_node, "interrupts", NULL); if (!dev_intrs) return -ENODEV; @@ -1574,7 +1574,7 @@ static int spu_mdesc_walk_arcs(struct mdesc_handle *mdesc, id = mdesc_get_property(mdesc, tgt, "id", NULL); if (table[*id] != NULL) { dev_err(&dev->dev, "%s: SPU cpu slot already set.\n", - dev->node->full_name); + dev->dev.of_node->full_name); return -EINVAL; } cpu_set(*id, p->sharing); @@ -1595,7 +1595,7 @@ static int handle_exec_unit(struct spu_mdesc_info *ip, struct list_head *list, p = kzalloc(sizeof(struct spu_queue), GFP_KERNEL); if (!p) { dev_err(&dev->dev, "%s: Could not allocate SPU queue.\n", - dev->node->full_name); + dev->dev.of_node->full_name); return -ENOMEM; } @@ -1684,7 +1684,7 @@ static int __devinit grab_mdesc_irq_props(struct mdesc_handle *mdesc, const unsigned int *reg; u64 node; - reg = of_get_property(dev->node, "reg", NULL); + reg = of_get_property(dev->dev.of_node, "reg", NULL); if (!reg) return -ENODEV; @@ -1836,7 +1836,7 @@ static int __devinit n2_crypto_probe(struct of_device *dev, n2_spu_driver_version(); - full_name = dev->node->full_name; + full_name = dev->dev.of_node->full_name; pr_info("Found N2CP at %s\n", full_name); np = alloc_n2cp(); @@ -1948,7 +1948,7 @@ static int __devinit n2_mau_probe(struct of_device *dev, n2_spu_driver_version(); - full_name = dev->node->full_name; + full_name = dev->dev.of_node->full_name; pr_info("Found NCP at %s\n", full_name); mp = alloc_ncp(); @@ -2034,8 +2034,11 @@ static struct of_device_id n2_crypto_match[] = { MODULE_DEVICE_TABLE(of, n2_crypto_match); static struct of_platform_driver n2_crypto_driver = { - .name = "n2cp", - .match_table = n2_crypto_match, + .driver = { + .name = "n2cp", + .owner = THIS_MODULE, + .of_match_table = n2_crypto_match, + }, .probe = n2_crypto_probe, .remove = __devexit_p(n2_crypto_remove), }; @@ -2055,8 +2058,11 @@ static struct of_device_id n2_mau_match[] = { MODULE_DEVICE_TABLE(of, n2_mau_match); static struct of_platform_driver n2_mau_driver = { - .name = "ncp", - .match_table = n2_mau_match, + .driver = { + .name = "ncp", + .owner = THIS_MODULE, + .of_match_table = n2_mau_match, + }, .probe = n2_mau_probe, .remove = __devexit_p(n2_mau_remove), }; -- GitLab From 527b9525256f97ad8d092bbfc8fdc3c5409f4a4d Mon Sep 17 00:00:00 2001 From: "David S. Miller" <davem@davemloft.net> Date: Sat, 22 May 2010 00:50:12 -0700 Subject: [PATCH 202/842] n2_crypto: Fix MAU kmem_cache name. Both the CWQ and MAU caches unintentionally had that same name. Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/crypto/n2_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 1a5b1e709d67..5613b8affe11 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1449,7 +1449,7 @@ static int queue_cache_init(void) { if (!queue_cache[HV_NCS_QTYPE_MAU - 1]) queue_cache[HV_NCS_QTYPE_MAU - 1] = - kmem_cache_create("cwq_queue", + kmem_cache_create("mau_queue", (MAU_NUM_ENTRIES * MAU_ENTRY_SIZE), MAU_ENTRY_SIZE, 0, NULL); -- GitLab From c9aa55e5271a53d28e93fa58759d318b403c15ba Mon Sep 17 00:00:00 2001 From: "David S. Miller" <davem@davemloft.net> Date: Sat, 22 May 2010 01:09:04 -0700 Subject: [PATCH 203/842] n2_crypto: Plumb fallback ahash requests properly. Do this by putting the async fallback request at the end of an n2 specific ahash request context, then properly adjusting the request private size in our ahash ->cra_init(). We also need to put the writable state bits into the n2 request private instead of the n2 cra_ctx. With help from Herbert Xu. Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/crypto/n2_core.c | 95 ++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 5613b8affe11..23163fda5035 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -251,16 +251,10 @@ static void n2_base_ctx_init(struct n2_base_ctx *ctx) struct n2_hash_ctx { struct n2_base_ctx base; - struct crypto_ahash *fallback; + struct crypto_ahash *fallback_tfm; +}; - /* These next three members must match the layout created by - * crypto_init_shash_ops_async. This allows us to properly - * plumb requests we can't do in hardware down to the fallback - * operation, providing all of the data structures and layouts - * expected by those paths. - */ - struct ahash_request fallback_req; - struct shash_desc fallback_desc; +struct n2_hash_req_ctx { union { struct md5_state md5; struct sha1_state sha1; @@ -269,56 +263,62 @@ struct n2_hash_ctx { unsigned char hash_key[64]; unsigned char keyed_zero_hash[32]; + + struct ahash_request fallback_req; }; static int n2_hash_async_init(struct ahash_request *req) { + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback); - ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; - return crypto_ahash_init(&ctx->fallback_req); + return crypto_ahash_init(&rctx->fallback_req); } static int n2_hash_async_update(struct ahash_request *req) { + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback); - ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; - ctx->fallback_req.nbytes = req->nbytes; - ctx->fallback_req.src = req->src; + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + rctx->fallback_req.nbytes = req->nbytes; + rctx->fallback_req.src = req->src; - return crypto_ahash_update(&ctx->fallback_req); + return crypto_ahash_update(&rctx->fallback_req); } static int n2_hash_async_final(struct ahash_request *req) { + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback); - ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; - ctx->fallback_req.result = req->result; + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + rctx->fallback_req.result = req->result; - return crypto_ahash_final(&ctx->fallback_req); + return crypto_ahash_final(&rctx->fallback_req); } static int n2_hash_async_finup(struct ahash_request *req) { + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback); - ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; - ctx->fallback_req.nbytes = req->nbytes; - ctx->fallback_req.src = req->src; - ctx->fallback_req.result = req->result; + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + rctx->fallback_req.nbytes = req->nbytes; + rctx->fallback_req.src = req->src; + rctx->fallback_req.result = req->result; - return crypto_ahash_finup(&ctx->fallback_req); + return crypto_ahash_finup(&rctx->fallback_req); } static int n2_hash_cra_init(struct crypto_tfm *tfm) @@ -338,7 +338,10 @@ static int n2_hash_cra_init(struct crypto_tfm *tfm) goto out; } - ctx->fallback = fallback_tfm; + crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) + + crypto_ahash_reqsize(fallback_tfm))); + + ctx->fallback_tfm = fallback_tfm; return 0; out: @@ -350,7 +353,7 @@ static void n2_hash_cra_exit(struct crypto_tfm *tfm) struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); struct n2_hash_ctx *ctx = crypto_ahash_ctx(ahash); - crypto_free_ahash(ctx->fallback); + crypto_free_ahash(ctx->fallback_tfm); } static unsigned long wait_for_tail(struct spu_queue *qp) @@ -399,14 +402,16 @@ static int n2_hash_async_digest(struct ahash_request *req, * exceed 2^16. */ if (unlikely(req->nbytes > (1 << 16))) { - ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback); - ctx->fallback_req.base.flags = + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + + ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; - ctx->fallback_req.nbytes = req->nbytes; - ctx->fallback_req.src = req->src; - ctx->fallback_req.result = req->result; + rctx->fallback_req.nbytes = req->nbytes; + rctx->fallback_req.src = req->src; + rctx->fallback_req.result = req->result; - return crypto_ahash_digest(&ctx->fallback_req); + return crypto_ahash_digest(&rctx->fallback_req); } n2_base_ctx_init(&ctx->base); @@ -472,9 +477,8 @@ out: static int n2_md5_async_digest(struct ahash_request *req) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct md5_state *m = &ctx->u.md5; + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct md5_state *m = &rctx->u.md5; if (unlikely(req->nbytes == 0)) { static const char md5_zero[MD5_DIGEST_SIZE] = { @@ -497,9 +501,8 @@ static int n2_md5_async_digest(struct ahash_request *req) static int n2_sha1_async_digest(struct ahash_request *req) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct sha1_state *s = &ctx->u.sha1; + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct sha1_state *s = &rctx->u.sha1; if (unlikely(req->nbytes == 0)) { static const char sha1_zero[SHA1_DIGEST_SIZE] = { @@ -524,9 +527,8 @@ static int n2_sha1_async_digest(struct ahash_request *req) static int n2_sha256_async_digest(struct ahash_request *req) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct sha256_state *s = &ctx->u.sha256; + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct sha256_state *s = &rctx->u.sha256; if (req->nbytes == 0) { static const char sha256_zero[SHA256_DIGEST_SIZE] = { @@ -555,9 +557,8 @@ static int n2_sha256_async_digest(struct ahash_request *req) static int n2_sha224_async_digest(struct ahash_request *req) { - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct sha256_state *s = &ctx->u.sha256; + struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); + struct sha256_state *s = &rctx->u.sha256; if (req->nbytes == 0) { static const char sha224_zero[SHA224_DIGEST_SIZE] = { -- GitLab From a41a7b91772da2c77ac0da74285fd8ebd86a85ba Mon Sep 17 00:00:00 2001 From: Huang Weiyi <weiyi.huang@gmail.com> Date: Tue, 25 May 2010 14:07:25 +0000 Subject: [PATCH 204/842] sh: remove duplicated #include Remove duplicated #include('s) in arch/sh/boards/mach-ecovec24/setup.c Signed-off-by: Huang Weiyi <weiyi.huang@gmail.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/boards/mach-ecovec24/setup.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 49714258732e..3845258242ac 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -26,7 +26,6 @@ #include <linux/mmc/host.h> #include <linux/input.h> #include <linux/input/sh_keysc.h> -#include <linux/mfd/sh_mobile_sdhi.h> #include <video/sh_mobile_lcdc.h> #include <sound/sh_fsi.h> #include <media/sh_mobile_ceu.h> -- GitLab From 895443c1c98a21198a0a5265041dc7ad14936d63 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Wed, 26 May 2010 00:36:30 +0000 Subject: [PATCH 205/842] powerpc/44x: icon: select SM502 and frame buffer console support Enables SM502 frame buffer and framebuffer console in the default config file Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com> --- arch/powerpc/configs/44x/icon_defconfig | 149 ++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig index 40a755b65939..277f88c2750f 100644 --- a/arch/powerpc/configs/44x/icon_defconfig +++ b/arch/powerpc/configs/44x/icon_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.34-rc5 -# Mon Apr 26 16:44:40 2010 +# Linux kernel version: 2.6.34-rc7 +# Fri May 21 17:40:22 2010 # # CONFIG_PPC64 is not set @@ -691,18 +691,74 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y # # Input device support # -# CONFIG_INPUT is not set +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=640 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +# CONFIG_MOUSE_PS2_ALPS is not set +# CONFIG_MOUSE_PS2_LOGIPS2PP is not set +# CONFIG_MOUSE_PS2_SYNAPTICS is not set +# CONFIG_MOUSE_PS2_TRACKPOINT is not set +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set # # Hardware I/O ports # -# CONFIG_SERIO is not set +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_XILINX_XPS_PS2 is not set +# CONFIG_SERIO_ALTERA_PS2 is not set # CONFIG_GAMEPORT is not set # # Character devices # -# CONFIG_VT is not set +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set CONFIG_DEVKMEM=y # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_NOZOMI is not set @@ -826,7 +882,7 @@ CONFIG_SSB_POSSIBLE=y # # CONFIG_MFD_CORE is not set # CONFIG_MFD_88PM860X is not set -# CONFIG_MFD_SM501 is not set +CONFIG_MFD_SM501=y # CONFIG_HTC_PASIC3 is not set # CONFIG_TWL4030_CORE is not set # CONFIG_MFD_TMIO is not set @@ -852,14 +908,93 @@ CONFIG_VGA_ARB_MAX_GPUS=16 # CONFIG_DRM is not set # CONFIG_VGASTATE is not set CONFIG_VIDEO_OUTPUT_CONTROL=m -# CONFIG_FB is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_CT65550 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +CONFIG_FB_SM501=y +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Display device support # # CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y # CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HIDRAW is not set +# CONFIG_HID_PID is not set + +# +# Special HID drivers +# # CONFIG_USB_SUPPORT is not set # CONFIG_UWB is not set # CONFIG_MMC is not set -- GitLab From b578bb490fb605c23c20b63995f26d3ab2cfb6e0 Mon Sep 17 00:00:00 2001 From: "John W. Linville" <linville@tuxdriver.com> Date: Wed, 26 May 2010 14:40:32 -0400 Subject: [PATCH 206/842] Revert "rt2x00: Fix rt2800usb TX descriptor writing." This reverts commit 663cb47cc2c5acd32850f67d051e47d62ed199c9. This patch was merged out of the proper order, so instead of fixing a problem with a prior (unmerged) patch, it creates one. Ooops! Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 699161327d65..0f8b84b7224c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -413,7 +413,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, */ rt2x00_desc_read(txi, 0, &word); rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN, - skb->len - TXINFO_DESC_SIZE); + skb->len + TXWI_DESC_SIZE); rt2x00_set_field32(&word, TXINFO_W0_WIV, !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2); -- GitLab From 5001960016bb53a1075bd9d62d7c067cd38c5a68 Mon Sep 17 00:00:00 2001 From: Christian Lamparter <chunkeey@googlemail.com> Date: Tue, 25 May 2010 23:58:47 +0200 Subject: [PATCH 207/842] ar9170usb: fix read from freed driver context Commit "ar9170: wait for asynchronous firmware loading" introduced a bug, which is triggered by fatal errors while the driver is initializing the device. BUG: unable to handle kernel paging request at 6b6b6bf7 IP: [<c117b567>] kobject_put+0x7/0x70 *pde = 00000000 Oops: 0000 [#1] PREEMPT last sysfs file: /sys/devices/platform/hdaps/position Modules linked in: ar9170usb [...] Pid: 6246, comm: firmware/ar9170 Not tainted 2.6.34-wl #54 EIP: 0060:[<c117b567>] EFLAGS: 00010206 CPU: 0 EIP is at kobject_put+0x7/0x70 EAX: 6b6b6bd7 EBX: f4d3d0e0 ECX: f5ba9124 EDX: f6af2a7c ESI: 00000000 EDI: f4d3d0e0 EBP: 00000000 ESP: f5e98f9c DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 Process firmware/ar9170 (pid: 6246) Stack: c12532ed 00000246 f5bfaa70 f8487353 f4d3d0e0 Call Trace: [<c12532ed>] ? device_release_driver+0x1d/0x30 [<f8487353>] ? ar9170_usb_firmware_failed+0x43/0x70 [ar9170usb] [<c125983c>] ? request_firmware_work_func+0x2c/0x70 [<c1259810>] ? request_firmware_work_func+0x0/0x70 [<c10413f4>] ? kthread+0x74/0x80 [<c1041380>] ? kthread+0x0/0x80 [<c1003136>] ? kernel_thread_helper+0x6/0x10 Code: 40 d3 f2 ff 85 c0 89 c3 74 0a ba 44 86 4c c1 e8 [...] EIP: [<c117b567>] kobject_put+0x7/0x70 SS:ESP 0068:f5e98f9c CR2: 000000006b6b6bf7 ---[ end trace e81abb992434b410 ]--- Signed-off-by: Christian Lamparter <chunkeey@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/ath/ar9170/usb.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 82ab532a4923..a93dc18a45c3 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -739,17 +739,27 @@ err_out: static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) { struct device *parent = aru->udev->dev.parent; + struct usb_device *udev; + + /* + * Store a copy of the usb_device pointer locally. + * This is because device_release_driver initiates + * ar9170_usb_disconnect, which in turn frees our + * driver context (aru). + */ + udev = aru->udev; complete(&aru->firmware_loading_complete); /* unbind anything failed */ if (parent) device_lock(parent); - device_release_driver(&aru->udev->dev); + + device_release_driver(&udev->dev); if (parent) device_unlock(parent); - usb_put_dev(aru->udev); + usb_put_dev(udev); } static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) -- GitLab From 79a78dd6266a4f3e31c800e941ec62e250770a7d Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 17 May 2010 09:23:54 +0100 Subject: [PATCH 208/842] drm/i915: Fail to load driver if KMS request without GEM The i915's implementation of KMS requires GEM in order to manage the memory and execution domains of the framebuffer and associated resources. By the point at which we detect broken a BIOS and need to disable GEM, we have already registered ourselves as a KMS driver with several subsystems. Rather than introducing a fragile unwind and attempt to continue with UMS, spit out an error and unload the driver. References: [Bug 15754] IP: [<ffffffffa0207589>] drm_mm_search_free+0x49/0x90 [drm] BUG: unable to handle kernel NULL pointer dereference at (null) https://bugzilla.kernel.org/show_bug.cgi?id=15754 [drm:i915_driver_load] *ERROR* Detected broken video BIOS with 262140/262144kB of video memory stolen. [drm:i915_driver_load] *ERROR* Disabling GEM. (try reducing stolen memory or updating the BIOS to fix). i915 0000:00:02.0: irq 30 for MSI/MSI-X [drm] set up 255M of stolen space BUG: unable to handle kernel NULL pointer dereference at (null) IP: [<ffffffffa0207589>] drm_mm_search_free+0x49/0x90 [drm] PGD 69719067 PUD 69dda067 PMD 0 Oops: 0000 [#1] PREEMPT SMP last sysfs file: /sys/module/snd_seq_oss/initstate CPU 1 Pid: 867, comm: modprobe Not tainted 2.6.33-ARCH #1 G43Twins-FullHD/To Be Filled By O.E.M. RIP: 0010:[<ffffffffa0207589>] [<ffffffffa0207589>] drm_mm_search_free+0x49/0x90 [drm] RSP: 0018:ffff8800699f3af8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffffffffffffff RCX: 0000000000000000 RDX: 0000000000001000 RSI: 0000000000001000 RDI: ffff8800693d0f78 RBP: ffff8800699f3b18 R08: 0000000000001000 R09: 0000000000000000 R10: 2222222222222222 R11: 0000000000000000 R12: ffff880068de70c0 R13: 0000000000001000 R14: 0000000000000000 R15: ffff8800689cb000 FS: 00007fa93f4e5700(0000) GS:ffff880001880000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 00000000695a0000 CR4: 00000000000406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process modprobe (pid: 867, threadinfo ffff8800699f2000, task ffff8800694f4740) Stack: ffff880068de73c0 ffff880068de70c0 ffff8800689cb000 0000000000001000 <0> ffff8800699f3b68 ffffffffa0299f63 ffff8800693d0f78 0000120068de70c0 <0> ffff8800689cb000 ffff880068de73c0 ffff880068de70c0 ffff8800689cb000 Call Trace: [<ffffffffa0299f63>] i915_gem_object_bind_to_gtt+0x83/0x360 [i915] [<ffffffffa029a2e5>] i915_gem_object_pin+0xa5/0xb0 [i915] [<ffffffffa029a3c5>] i915_gem_init_ringbuffer+0xd5/0x510 [i915] [<ffffffffa028dbee>] i915_driver_load+0x4ce/0xd00 [i915] [<ffffffffa0205d37>] ? drm_sysfs_device_add+0x87/0xb0 [drm] [<ffffffffa0203363>] ? drm_get_minor+0x1d3/0x330 [drm] [<ffffffffa02037e6>] drm_get_dev+0x326/0x580 [drm] [<ffffffffa02bc0a5>] i915_pci_probe+0x10/0xd0 [i915] [<ffffffff811e98a2>] local_pci_probe+0x12/0x20 [<ffffffff811ea8e0>] pci_device_probe+0x80/0xb0 [<ffffffff8127b12a>] ? driver_sysfs_add+0x5a/0x90 [<ffffffff8127b273>] driver_probe_device+0x93/0x1a0 [<ffffffff8127b413>] __driver_attach+0x93/0xa0 [<ffffffff8127b380>] ? __driver_attach+0x0/0xa0 [<ffffffff8127a8f8>] bus_for_each_dev+0x68/0x90 [<ffffffff8127b0c9>] driver_attach+0x19/0x20 [<ffffffff8127a0ad>] bus_add_driver+0xcd/0x2d0 [<ffffffff8127b718>] driver_register+0x78/0x140 [<ffffffff811eab91>] __pci_register_driver+0x51/0xd0 [<ffffffffa02d6000>] ? i915_init+0x0/0x52 [i915] [<ffffffffa01fdc31>] drm_init+0x111/0x120 [drm] [<ffffffff810eb0cd>] ? register_shrinker+0x4d/0x60 [<ffffffffa02d6000>] ? i915_init+0x0/0x52 [i915] [<ffffffffa02d6050>] i915_init+0x50/0x52 [i915] [<ffffffff81002047>] do_one_initcall+0x37/0x1a0 [<ffffffff8108ed17>] sys_init_module+0xd7/0x250 [<ffffffff81009fc2>] system_call_fastpath+0x16/0x1b Code: eb 29 49 8b 41 28 31 d2 49 f7 f5 85 d2 74 39 44 89 c0 29 d0 48 89 c2 48 01 f2 49 39 d2 73 29 0f 1f 00 49 89 da 4c 89 d3 4d 89 d9 <4d> 8b 19 49 39 f9 41 0f 18 0b 74 2b 4d 8b 51 30 4d 89 cc 49 39 RIP [<ffffffffa0207589>] drm_mm_search_free+0x49/0x90 [drm] RSP <ffff8800699f3af8> CR2: 0000000000000000 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_dma.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2a6b5de5ae5d..22d7497e6fa6 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1672,6 +1672,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->has_gem = 0; } + if (dev_priv->has_gem == 0 && + drm_core_check_feature(dev, DRIVER_MODESET)) { + DRM_ERROR("kernel modesetting requires GEM, disabling driver.\n"); + ret = -ENODEV; + goto out_iomapfree; + } + dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) { -- GitLab From 62fdfeaf8b1f487060b6e160e7b5cd90287607c9 Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Fri, 21 May 2010 13:26:39 -0700 Subject: [PATCH 209/842] drm/i915: Move ringbuffer-related code to intel_ringbuffer.c. This is preparation for supporting multiple ringbuffers on Ironlake. The non-copy-and-paste changes are: - de-staticing functions - I915_GEM_GPU_DOMAINS moving to i915_drv.h to be used by both files. - i915_gem_add_request had only half its implementation copy-and-pasted out of the middle of it. --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_dma.c | 77 ---- drivers/gpu/drm/i915/i915_drv.h | 18 + drivers/gpu/drm/i915/i915_gem.c | 427 +----------------- drivers/gpu/drm/i915/i915_irq.c | 35 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 568 ++++++++++++++++++++++++ 6 files changed, 592 insertions(+), 534 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_ringbuffer.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 95639017bdbe..da78f2c0d909 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -22,6 +22,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ intel_fb.o \ intel_tv.o \ intel_dvo.o \ + intel_ringbuffer.o \ intel_overlay.o \ dvo_ch7xxx.o \ dvo_ch7017.o \ diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 22d7497e6fa6..a657e3315950 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -40,83 +40,6 @@ #include <linux/vga_switcheroo.h> #include <linux/slab.h> -/* Really want an OS-independent resettable timer. Would like to have - * this loop run for (eg) 3 sec, but have the timer reset every time - * the head pointer changes, so that EBUSY only happens if the ring - * actually stalls for (eg) 3 seconds. - */ -int i915_wait_ring(struct drm_device * dev, int n, const char *caller) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_ring_buffer_t *ring = &(dev_priv->ring); - u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; - u32 last_acthd = I915_READ(acthd_reg); - u32 acthd; - u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - int i; - - trace_i915_ring_wait_begin (dev); - - for (i = 0; i < 100000; i++) { - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - acthd = I915_READ(acthd_reg); - ring->space = ring->head - (ring->tail + 8); - if (ring->space < 0) - ring->space += ring->Size; - if (ring->space >= n) { - trace_i915_ring_wait_end (dev); - return 0; - } - - if (dev->primary->master) { - struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - if (master_priv->sarea_priv) - master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; - } - - - if (ring->head != last_head) - i = 0; - if (acthd != last_acthd) - i = 0; - - last_head = ring->head; - last_acthd = acthd; - msleep_interruptible(10); - - } - - trace_i915_ring_wait_end (dev); - return -EBUSY; -} - -/* As a ringbuffer is only allowed to wrap between instructions, fill - * the tail with NOOPs. - */ -int i915_wrap_ring(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - volatile unsigned int *virt; - int rem; - - rem = dev_priv->ring.Size - dev_priv->ring.tail; - if (dev_priv->ring.space < rem) { - int ret = i915_wait_ring(dev, rem, __func__); - if (ret) - return ret; - } - dev_priv->ring.space -= rem; - - virt = (unsigned int *) - (dev_priv->ring.virtual_start + dev_priv->ring.tail); - rem /= 4; - while (rem--) - *virt++ = MI_NOOP; - - dev_priv->ring.tail = 0; - - return 0; -} /** * Sets up the hardware status page for devices that need a physical address diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7f797ef1ab39..114653aa9ae2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -31,6 +31,7 @@ #define _I915_DRV_H_ #include "i915_reg.h" +#include "i915_drm.h" #include "intel_bios.h" #include <linux/io-mapping.h> @@ -55,6 +56,8 @@ enum plane { #define I915_NUM_PIPE 2 +#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) + /* Interface history: * * 1.1: Original. @@ -849,6 +852,9 @@ extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc); extern int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask); +extern void i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask); +void ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask); +void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask); void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); @@ -956,6 +962,8 @@ void i915_gem_object_flush_write_domain(struct drm_gem_object *obj); void i915_gem_shrinker_init(void); void i915_gem_shrinker_exit(void); +int i915_gem_init_pipe_control(struct drm_device *dev); +void i915_gem_cleanup_pipe_control(struct drm_device *dev); /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); @@ -1006,6 +1014,16 @@ static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; static inline void opregion_enable_asle(struct drm_device *dev) { return; } #endif +/* intel_ringbuffer.c */ +extern void i915_gem_flush(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains); +extern int i915_dispatch_gem_execbuffer(struct drm_device *dev, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset); +extern uint32_t i915_ring_add_request(struct drm_device *dev); + /* modesetting */ extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 112699f71fa4..4f2f5f8cdca2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -35,8 +35,6 @@ #include <linux/swap.h> #include <linux/pci.h> -#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) - static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); @@ -1592,22 +1590,6 @@ i915_gem_process_flushing_list(struct drm_device *dev, } } } - -#define PIPE_CONTROL_FLUSH(addr) \ - OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ - PIPE_CONTROL_DEPTH_STALL); \ - OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \ - OUT_RING(0); \ - OUT_RING(0); \ - -/** - * Creates a new sequence number, emitting a write of it to the status page - * plus an interrupt, which will trigger i915_user_interrupt_handler. - * - * Must be called with struct_lock held. - * - * Returned sequence numbers are nonzero on success. - */ uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, uint32_t flush_domains) @@ -1617,7 +1599,6 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, struct drm_i915_gem_request *request; uint32_t seqno; int was_empty; - RING_LOCALS; if (file_priv != NULL) i915_file_priv = file_priv->driver_priv; @@ -1626,55 +1607,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, if (request == NULL) return 0; - /* Grab the seqno we're going to make this request be, and bump the - * next (skipping 0 so it can be the reserved no-seqno value). - */ - seqno = dev_priv->mm.next_gem_seqno; - dev_priv->mm.next_gem_seqno++; - if (dev_priv->mm.next_gem_seqno == 0) - dev_priv->mm.next_gem_seqno++; - - if (HAS_PIPE_CONTROL(dev)) { - u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; - - /* - * Workaround qword write incoherence by flushing the - * PIPE_NOTIFY buffers out to memory before requesting - * an interrupt. - */ - BEGIN_LP_RING(32); - OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); - OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - OUT_RING(seqno); - OUT_RING(0); - PIPE_CONTROL_FLUSH(scratch_addr); - scratch_addr += 128; /* write to separate cachelines */ - PIPE_CONTROL_FLUSH(scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); - scratch_addr += 128; - PIPE_CONTROL_FLUSH(scratch_addr); - OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | - PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | - PIPE_CONTROL_NOTIFY); - OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); - OUT_RING(seqno); - OUT_RING(0); - ADVANCE_LP_RING(); - } else { - BEGIN_LP_RING(4); - OUT_RING(MI_STORE_DWORD_INDEX); - OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(seqno); - - OUT_RING(MI_USER_INTERRUPT); - ADVANCE_LP_RING(); - } + seqno = i915_ring_add_request(dev); DRM_DEBUG_DRIVER("%d\n", seqno); @@ -1933,78 +1866,6 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno) return i915_do_wait_request(dev, seqno, 1); } -static void -i915_gem_flush(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t cmd; - RING_LOCALS; - -#if WATCH_EXEC - DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, - invalidate_domains, flush_domains); -#endif - trace_i915_gem_request_flush(dev, dev_priv->mm.next_gem_seqno, - invalidate_domains, flush_domains); - - if (flush_domains & I915_GEM_DOMAIN_CPU) - drm_agp_chipset_flush(dev); - - if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { - /* - * read/write caches: - * - * I915_GEM_DOMAIN_RENDER is always invalidated, but is - * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is - * also flushed at 2d versus 3d pipeline switches. - * - * read-only caches: - * - * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if - * MI_READ_FLUSH is set, and is always flushed on 965. - * - * I915_GEM_DOMAIN_COMMAND may not exist? - * - * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is - * invalidated when MI_EXE_FLUSH is set. - * - * I915_GEM_DOMAIN_VERTEX, which exists on 965, is - * invalidated with every MI_FLUSH. - * - * TLBs: - * - * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND - * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and - * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER - * are flushed at any MI_FLUSH. - */ - - cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; - if ((invalidate_domains|flush_domains) & - I915_GEM_DOMAIN_RENDER) - cmd &= ~MI_NO_WRITE_FLUSH; - if (!IS_I965G(dev)) { - /* - * On the 965, the sampler cache always gets flushed - * and this bit is reserved. - */ - if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) - cmd |= MI_READ_FLUSH; - } - if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) - cmd |= MI_EXE_FLUSH; - -#if WATCH_EXEC - DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); -#endif - BEGIN_LP_RING(2); - OUT_RING(cmd); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); - } -} /** * Ensures that all rendering to the object has completed and the object is @@ -3545,62 +3406,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, return 0; } -/** Dispatch a batchbuffer to the ring - */ -static int -i915_dispatch_gem_execbuffer(struct drm_device *dev, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int nbox = exec->num_cliprects; - int i = 0, count; - uint32_t exec_start, exec_len; - RING_LOCALS; - - exec_start = (uint32_t) exec_offset + exec->batch_start_offset; - exec_len = (uint32_t) exec->batch_len; - - trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno + 1); - - count = nbox ? nbox : 1; - - for (i = 0; i < count; i++) { - if (i < nbox) { - int ret = i915_emit_box(dev, cliprects, i, - exec->DR1, exec->DR4); - if (ret) - return ret; - } - - if (IS_I830(dev) || IS_845G(dev)) { - BEGIN_LP_RING(4); - OUT_RING(MI_BATCH_BUFFER); - OUT_RING(exec_start | MI_BATCH_NON_SECURE); - OUT_RING(exec_start + exec_len - 4); - OUT_RING(0); - ADVANCE_LP_RING(); - } else { - BEGIN_LP_RING(2); - if (IS_I965G(dev)) { - OUT_RING(MI_BATCH_BUFFER_START | - (2 << 6) | - MI_BATCH_NON_SECURE_I965); - OUT_RING(exec_start); - } else { - OUT_RING(MI_BATCH_BUFFER_START | - (2 << 6)); - OUT_RING(exec_start | MI_BATCH_NON_SECURE); - } - ADVANCE_LP_RING(); - } - } - - /* XXX breadcrumb */ - return 0; -} - /* Throttle our rendering by waiting until the ring has completed our requests * emitted over 20 msec ago. * @@ -4615,7 +4420,7 @@ i915_gem_idle(struct drm_device *dev) * 965+ support PIPE_CONTROL commands, which provide finer grained control * over cache flushing. */ -static int +int i915_gem_init_pipe_control(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -4654,73 +4459,7 @@ err: return ret; } -static int -i915_gem_init_hws(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - int ret; - - /* If we need a physical address for the status page, it's already - * initialized at driver load time. - */ - if (!I915_NEED_GFX_HWS(dev)) - return 0; - - obj = i915_gem_alloc_object(dev, 4096); - if (obj == NULL) { - DRM_ERROR("Failed to allocate status page\n"); - ret = -ENOMEM; - goto err; - } - obj_priv = to_intel_bo(obj); - obj_priv->agp_type = AGP_USER_CACHED_MEMORY; - - ret = i915_gem_object_pin(obj, 4096); - if (ret != 0) { - drm_gem_object_unreference(obj); - goto err_unref; - } - - dev_priv->status_gfx_addr = obj_priv->gtt_offset; - - dev_priv->hw_status_page = kmap(obj_priv->pages[0]); - if (dev_priv->hw_status_page == NULL) { - DRM_ERROR("Failed to map status page.\n"); - memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); - ret = -EINVAL; - goto err_unpin; - } - - if (HAS_PIPE_CONTROL(dev)) { - ret = i915_gem_init_pipe_control(dev); - if (ret) - goto err_unpin; - } - - dev_priv->hws_obj = obj; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - if (IS_GEN6(dev)) { - I915_WRITE(HWS_PGA_GEN6, dev_priv->status_gfx_addr); - I915_READ(HWS_PGA_GEN6); /* posting read */ - } else { - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); - I915_READ(HWS_PGA); /* posting read */ - } - DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); - - return 0; - -err_unpin: - i915_gem_object_unpin(obj); -err_unref: - drm_gem_object_unreference(obj); -err: - return 0; -} - -static void +void i915_gem_cleanup_pipe_control(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -4737,166 +4476,6 @@ i915_gem_cleanup_pipe_control(struct drm_device *dev) dev_priv->seqno_page = NULL; } -static void -i915_gem_cleanup_hws(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - - if (dev_priv->hws_obj == NULL) - return; - - obj = dev_priv->hws_obj; - obj_priv = to_intel_bo(obj); - - kunmap(obj_priv->pages[0]); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - dev_priv->hws_obj = NULL; - - memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); - dev_priv->hw_status_page = NULL; - - if (HAS_PIPE_CONTROL(dev)) - i915_gem_cleanup_pipe_control(dev); - - /* Write high address into HWS_PGA when disabling. */ - I915_WRITE(HWS_PGA, 0x1ffff000); -} - -int -i915_gem_init_ringbuffer(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - drm_i915_ring_buffer_t *ring = &dev_priv->ring; - int ret; - u32 head; - - ret = i915_gem_init_hws(dev); - if (ret != 0) - return ret; - - obj = i915_gem_alloc_object(dev, 128 * 1024); - if (obj == NULL) { - DRM_ERROR("Failed to allocate ringbuffer\n"); - i915_gem_cleanup_hws(dev); - return -ENOMEM; - } - obj_priv = to_intel_bo(obj); - - ret = i915_gem_object_pin(obj, 4096); - if (ret != 0) { - drm_gem_object_unreference(obj); - i915_gem_cleanup_hws(dev); - return ret; - } - - /* Set up the kernel mapping for the ring. */ - ring->Size = obj->size; - - ring->map.offset = dev->agp->base + obj_priv->gtt_offset; - ring->map.size = obj->size; - ring->map.type = 0; - ring->map.flags = 0; - ring->map.mtrr = 0; - - drm_core_ioremap_wc(&ring->map, dev); - if (ring->map.handle == NULL) { - DRM_ERROR("Failed to map ringbuffer.\n"); - memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - i915_gem_cleanup_hws(dev); - return -EINVAL; - } - ring->ring_obj = obj; - ring->virtual_start = ring->map.handle; - - /* Stop the ring if it's running. */ - I915_WRITE(PRB0_CTL, 0); - I915_WRITE(PRB0_TAIL, 0); - I915_WRITE(PRB0_HEAD, 0); - - /* Initialize the ring. */ - I915_WRITE(PRB0_START, obj_priv->gtt_offset); - head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - - /* G45 ring initialization fails to reset head to zero */ - if (head != 0) { - DRM_ERROR("Ring head not reset to zero " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); - I915_WRITE(PRB0_HEAD, 0); - - DRM_ERROR("Ring head forced to zero " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); - } - - I915_WRITE(PRB0_CTL, - ((obj->size - 4096) & RING_NR_PAGES) | - RING_NO_REPORT | - RING_VALID); - - head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - - /* If the head is still not zero, the ring is dead */ - if (head != 0) { - DRM_ERROR("Ring initialization failed " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); - return -EIO; - } - - /* Update our cache of the ring state */ - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - i915_kernel_lost_context(dev); - else { - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; - ring->space = ring->head - (ring->tail + 8); - if (ring->space < 0) - ring->space += ring->Size; - } - - if (IS_I9XX(dev) && !IS_GEN3(dev)) { - I915_WRITE(MI_MODE, - (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH); - } - - return 0; -} - -void -i915_gem_cleanup_ringbuffer(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - if (dev_priv->ring.ring_obj == NULL) - return; - - drm_core_ioremapfree(&dev_priv->ring.map, dev); - - i915_gem_object_unpin(dev_priv->ring.ring_obj); - drm_gem_object_unreference(dev_priv->ring.ring_obj); - dev_priv->ring.ring_obj = NULL; - memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); - - i915_gem_cleanup_hws(dev); -} - int i915_gem_entervt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8c3f0802686d..896184bfeb12 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -74,7 +74,7 @@ ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) } } -static inline void +void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) { if ((dev_priv->gt_irq_mask_reg & mask) != mask) { @@ -115,7 +115,7 @@ i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) } } -static inline void +void i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) { if ((dev_priv->irq_mask_reg & mask) != mask) { @@ -1006,37 +1006,6 @@ static int i915_emit_irq(struct drm_device * dev) return dev_priv->counter; } -void i915_user_irq_get(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { - if (HAS_PCH_SPLIT(dev)) - ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); - else - i915_enable_irq(dev_priv, I915_USER_INTERRUPT); - } - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); -} - -void i915_user_irq_put(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); - if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - if (HAS_PCH_SPLIT(dev)) - ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); - else - i915_disable_irq(dev_priv, I915_USER_INTERRUPT); - } - spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); -} - void i915_trace_irq_get(struct drm_device *dev, u32 seqno) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c new file mode 100644 index 000000000000..13a796fafaee --- /dev/null +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -0,0 +1,568 @@ +/* + * Copyright © 2008-2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Zou Nan hai <nanhai.zou@intel.com> + * Xiang Hai hao<haihao.xiang@intel.com> + * + */ + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "i915_trace.h" +#include "intel_drv.h" + +void +i915_gem_flush(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + uint32_t cmd; + RING_LOCALS; + +#if WATCH_EXEC + DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, + invalidate_domains, flush_domains); +#endif + trace_i915_gem_request_flush(dev, dev_priv->mm.next_gem_seqno, + invalidate_domains, flush_domains); + + if (flush_domains & I915_GEM_DOMAIN_CPU) + drm_agp_chipset_flush(dev); + + if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { + /* + * read/write caches: + * + * I915_GEM_DOMAIN_RENDER is always invalidated, but is + * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is + * also flushed at 2d versus 3d pipeline switches. + * + * read-only caches: + * + * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if + * MI_READ_FLUSH is set, and is always flushed on 965. + * + * I915_GEM_DOMAIN_COMMAND may not exist? + * + * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is + * invalidated when MI_EXE_FLUSH is set. + * + * I915_GEM_DOMAIN_VERTEX, which exists on 965, is + * invalidated with every MI_FLUSH. + * + * TLBs: + * + * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND + * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and + * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER + * are flushed at any MI_FLUSH. + */ + + cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; + if ((invalidate_domains|flush_domains) & + I915_GEM_DOMAIN_RENDER) + cmd &= ~MI_NO_WRITE_FLUSH; + if (!IS_I965G(dev)) { + /* + * On the 965, the sampler cache always gets flushed + * and this bit is reserved. + */ + if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) + cmd |= MI_READ_FLUSH; + } + if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) + cmd |= MI_EXE_FLUSH; + +#if WATCH_EXEC + DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); +#endif + BEGIN_LP_RING(2); + OUT_RING(cmd); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } + +} +#define PIPE_CONTROL_FLUSH(addr) \ + OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ + PIPE_CONTROL_DEPTH_STALL); \ + OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \ + OUT_RING(0); \ + OUT_RING(0); \ + +/** + * Creates a new sequence number, emitting a write of it to the status page + * plus an interrupt, which will trigger i915_user_interrupt_handler. + * + * Must be called with struct_lock held. + * + * Returned sequence numbers are nonzero on success. + */ +uint32_t +i915_ring_add_request(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + uint32_t seqno; + RING_LOCALS; + + /* Grab the seqno we're going to make this request be, and bump the + * next (skipping 0 so it can be the reserved no-seqno value). + */ + seqno = dev_priv->mm.next_gem_seqno; + dev_priv->mm.next_gem_seqno++; + if (dev_priv->mm.next_gem_seqno == 0) + dev_priv->mm.next_gem_seqno++; + + if (HAS_PIPE_CONTROL(dev)) { + u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; + + /* + * Workaround qword write incoherence by flushing the + * PIPE_NOTIFY buffers out to memory before requesting + * an interrupt. + */ + BEGIN_LP_RING(32); + OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); + OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + OUT_RING(seqno); + OUT_RING(0); + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; /* write to separate cachelines */ + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | + PIPE_CONTROL_NOTIFY); + OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + OUT_RING(seqno); + OUT_RING(0); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(4); + OUT_RING(MI_STORE_DWORD_INDEX); + OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + OUT_RING(seqno); + + OUT_RING(MI_USER_INTERRUPT); + ADVANCE_LP_RING(); + } + return seqno; +} + +void i915_user_irq_get(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); + if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { + if (HAS_PCH_SPLIT(dev)) + ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); + else + i915_enable_irq(dev_priv, I915_USER_INTERRUPT); + } + spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); +} + +void i915_user_irq_put(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); + BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); + if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { + if (HAS_PCH_SPLIT(dev)) + ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); + else + i915_disable_irq(dev_priv, I915_USER_INTERRUPT); + } + spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); +} + +/** Dispatch a batchbuffer to the ring + */ +int +i915_dispatch_gem_execbuffer(struct drm_device *dev, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int nbox = exec->num_cliprects; + int i = 0, count; + uint32_t exec_start, exec_len; + RING_LOCALS; + + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; + exec_len = (uint32_t) exec->batch_len; + + trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno + 1); + + count = nbox ? nbox : 1; + + for (i = 0; i < count; i++) { + if (i < nbox) { + int ret = i915_emit_box(dev, cliprects, i, + exec->DR1, exec->DR4); + if (ret) + return ret; + } + + if (IS_I830(dev) || IS_845G(dev)) { + BEGIN_LP_RING(4); + OUT_RING(MI_BATCH_BUFFER); + OUT_RING(exec_start | MI_BATCH_NON_SECURE); + OUT_RING(exec_start + exec_len - 4); + OUT_RING(0); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(2); + if (IS_I965G(dev)) { + OUT_RING(MI_BATCH_BUFFER_START | + (2 << 6) | + MI_BATCH_NON_SECURE_I965); + OUT_RING(exec_start); + } else { + OUT_RING(MI_BATCH_BUFFER_START | + (2 << 6)); + OUT_RING(exec_start | MI_BATCH_NON_SECURE); + } + ADVANCE_LP_RING(); + } + } + + /* XXX breadcrumb */ + return 0; +} + +static void +i915_gem_cleanup_hws(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + + if (dev_priv->hws_obj == NULL) + return; + + obj = dev_priv->hws_obj; + obj_priv = to_intel_bo(obj); + + kunmap(obj_priv->pages[0]); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + dev_priv->hws_obj = NULL; + + memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); + dev_priv->hw_status_page = NULL; + + if (HAS_PIPE_CONTROL(dev)) + i915_gem_cleanup_pipe_control(dev); + + /* Write high address into HWS_PGA when disabling. */ + I915_WRITE(HWS_PGA, 0x1ffff000); +} + +static int +i915_gem_init_hws(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + int ret; + + /* If we need a physical address for the status page, it's already + * initialized at driver load time. + */ + if (!I915_NEED_GFX_HWS(dev)) + return 0; + + obj = i915_gem_alloc_object(dev, 4096); + if (obj == NULL) { + DRM_ERROR("Failed to allocate status page\n"); + ret = -ENOMEM; + goto err; + } + obj_priv = to_intel_bo(obj); + obj_priv->agp_type = AGP_USER_CACHED_MEMORY; + + ret = i915_gem_object_pin(obj, 4096); + if (ret != 0) { + drm_gem_object_unreference(obj); + goto err_unref; + } + + dev_priv->status_gfx_addr = obj_priv->gtt_offset; + + dev_priv->hw_status_page = kmap(obj_priv->pages[0]); + if (dev_priv->hw_status_page == NULL) { + DRM_ERROR("Failed to map status page.\n"); + memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); + ret = -EINVAL; + goto err_unpin; + } + + if (HAS_PIPE_CONTROL(dev)) { + ret = i915_gem_init_pipe_control(dev); + if (ret) + goto err_unpin; + } + + dev_priv->hws_obj = obj; + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + if (IS_GEN6(dev)) { + I915_WRITE(HWS_PGA_GEN6, dev_priv->status_gfx_addr); + I915_READ(HWS_PGA_GEN6); /* posting read */ + } else { + I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); + I915_READ(HWS_PGA); /* posting read */ + } + DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); + + return 0; + +err_unpin: + i915_gem_object_unpin(obj); +err_unref: + drm_gem_object_unreference(obj); +err: + return 0; +} + +int +i915_gem_init_ringbuffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + drm_i915_ring_buffer_t *ring = &dev_priv->ring; + int ret; + u32 head; + + ret = i915_gem_init_hws(dev); + if (ret != 0) + return ret; + + obj = i915_gem_alloc_object(dev, 128 * 1024); + if (obj == NULL) { + DRM_ERROR("Failed to allocate ringbuffer\n"); + i915_gem_cleanup_hws(dev); + return -ENOMEM; + } + obj_priv = to_intel_bo(obj); + + ret = i915_gem_object_pin(obj, 4096); + if (ret != 0) { + drm_gem_object_unreference(obj); + i915_gem_cleanup_hws(dev); + return ret; + } + + /* Set up the kernel mapping for the ring. */ + ring->Size = obj->size; + + ring->map.offset = dev->agp->base + obj_priv->gtt_offset; + ring->map.size = obj->size; + ring->map.type = 0; + ring->map.flags = 0; + ring->map.mtrr = 0; + + drm_core_ioremap_wc(&ring->map, dev); + if (ring->map.handle == NULL) { + DRM_ERROR("Failed to map ringbuffer.\n"); + memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + i915_gem_cleanup_hws(dev); + return -EINVAL; + } + ring->ring_obj = obj; + ring->virtual_start = ring->map.handle; + + /* Stop the ring if it's running. */ + I915_WRITE(PRB0_CTL, 0); + I915_WRITE(PRB0_TAIL, 0); + I915_WRITE(PRB0_HEAD, 0); + + /* Initialize the ring. */ + I915_WRITE(PRB0_START, obj_priv->gtt_offset); + head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + + /* G45 ring initialization fails to reset head to zero */ + if (head != 0) { + DRM_ERROR("Ring head not reset to zero " + "ctl %08x head %08x tail %08x start %08x\n", + I915_READ(PRB0_CTL), + I915_READ(PRB0_HEAD), + I915_READ(PRB0_TAIL), + I915_READ(PRB0_START)); + I915_WRITE(PRB0_HEAD, 0); + + DRM_ERROR("Ring head forced to zero " + "ctl %08x head %08x tail %08x start %08x\n", + I915_READ(PRB0_CTL), + I915_READ(PRB0_HEAD), + I915_READ(PRB0_TAIL), + I915_READ(PRB0_START)); + } + + I915_WRITE(PRB0_CTL, + ((obj->size - 4096) & RING_NR_PAGES) | + RING_NO_REPORT | + RING_VALID); + + head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + + /* If the head is still not zero, the ring is dead */ + if (head != 0) { + DRM_ERROR("Ring initialization failed " + "ctl %08x head %08x tail %08x start %08x\n", + I915_READ(PRB0_CTL), + I915_READ(PRB0_HEAD), + I915_READ(PRB0_TAIL), + I915_READ(PRB0_START)); + return -EIO; + } + + /* Update our cache of the ring state */ + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_kernel_lost_context(dev); + else { + ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->Size; + } + + if (IS_I9XX(dev) && !IS_GEN3(dev)) { + I915_WRITE(MI_MODE, + (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH); + } + + return 0; +} + +void +i915_gem_cleanup_ringbuffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + if (dev_priv->ring.ring_obj == NULL) + return; + + drm_core_ioremapfree(&dev_priv->ring.map, dev); + + i915_gem_object_unpin(dev_priv->ring.ring_obj); + drm_gem_object_unreference(dev_priv->ring.ring_obj); + dev_priv->ring.ring_obj = NULL; + memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); + + i915_gem_cleanup_hws(dev); +} + +/* As a ringbuffer is only allowed to wrap between instructions, fill + * the tail with NOOPs. + */ +int i915_wrap_ring(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + volatile unsigned int *virt; + int rem; + + rem = dev_priv->ring.Size - dev_priv->ring.tail; + if (dev_priv->ring.space < rem) { + int ret = i915_wait_ring(dev, rem, __func__); + if (ret) + return ret; + } + dev_priv->ring.space -= rem; + + virt = (unsigned int *) + (dev_priv->ring.virtual_start + dev_priv->ring.tail); + rem /= 4; + while (rem--) + *virt++ = MI_NOOP; + + dev_priv->ring.tail = 0; + + return 0; +} + +int i915_wait_ring(struct drm_device * dev, int n, const char *caller) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; + u32 last_acthd = I915_READ(acthd_reg); + u32 acthd; + u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + int i; + + trace_i915_ring_wait_begin (dev); + + for (i = 0; i < 100000; i++) { + ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + acthd = I915_READ(acthd_reg); + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->Size; + if (ring->space >= n) { + trace_i915_ring_wait_end (dev); + return 0; + } + + if (dev->primary->master) { + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; + } + + + if (ring->head != last_head) + i = 0; + if (acthd != last_acthd) + i = 0; + + last_head = ring->head; + last_acthd = acthd; + msleep_interruptible(10); + + } + + trace_i915_ring_wait_end (dev); + return -EBUSY; +} -- GitLab From d3301d86b4bf2bcf649982ae464211d8bcf9575a Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Fri, 21 May 2010 13:55:54 -0700 Subject: [PATCH 210/842] drm/i915: Rename dev_priv->ring to dev_priv->render_ring. With the advent of the BSD ring, be clear about which ring this is. The docs are pretty consistent with calling this the Render engine at this point. --- drivers/gpu/drm/i915/i915_debugfs.c | 8 +++--- drivers/gpu/drm/i915/i915_dma.c | 38 ++++++++++++------------- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 20 ++++++------- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 12 ++++---- drivers/gpu/drm/i915/intel_ringbuffer.c | 28 +++++++++--------- 7 files changed, 55 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 322070c0c631..488175c70c7d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -317,14 +317,14 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) u8 *virt; uint32_t *ptr, off; - if (!dev_priv->ring.ring_obj) { + if (!dev_priv->render_ring.ring_obj) { seq_printf(m, "No ringbuffer setup\n"); return 0; } - virt = dev_priv->ring.virtual_start; + virt = dev_priv->render_ring.virtual_start; - for (off = 0; off < dev_priv->ring.Size; off += 4) { + for (off = 0; off < dev_priv->render_ring.Size; off += 4) { ptr = (uint32_t *)(virt + off); seq_printf(m, "%08x : %08x\n", off, *ptr); } @@ -344,7 +344,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) seq_printf(m, "RingHead : %08x\n", head); seq_printf(m, "RingTail : %08x\n", tail); - seq_printf(m, "RingSize : %08lx\n", dev_priv->ring.Size); + seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.Size); seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); return 0; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a657e3315950..6de7eace4319 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -95,7 +95,7 @@ void i915_kernel_lost_context(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; - drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + drm_i915_ring_buffer_t *ring = &(dev_priv->render_ring); /* * We should never lose context on the ring with modesetting @@ -128,11 +128,11 @@ static int i915_dma_cleanup(struct drm_device * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); - if (dev_priv->ring.virtual_start) { - drm_core_ioremapfree(&dev_priv->ring.map, dev); - dev_priv->ring.virtual_start = NULL; - dev_priv->ring.map.handle = NULL; - dev_priv->ring.map.size = 0; + if (dev_priv->render_ring.virtual_start) { + drm_core_ioremapfree(&dev_priv->render_ring.map, dev); + dev_priv->render_ring.virtual_start = NULL; + dev_priv->render_ring.map.handle = NULL; + dev_priv->render_ring.map.size = 0; } /* Clear the HWS virtual address at teardown */ @@ -156,24 +156,24 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) } if (init->ring_size != 0) { - if (dev_priv->ring.ring_obj != NULL) { + if (dev_priv->render_ring.ring_obj != NULL) { i915_dma_cleanup(dev); DRM_ERROR("Client tried to initialize ringbuffer in " "GEM mode\n"); return -EINVAL; } - dev_priv->ring.Size = init->ring_size; + dev_priv->render_ring.Size = init->ring_size; - dev_priv->ring.map.offset = init->ring_start; - dev_priv->ring.map.size = init->ring_size; - dev_priv->ring.map.type = 0; - dev_priv->ring.map.flags = 0; - dev_priv->ring.map.mtrr = 0; + dev_priv->render_ring.map.offset = init->ring_start; + dev_priv->render_ring.map.size = init->ring_size; + dev_priv->render_ring.map.type = 0; + dev_priv->render_ring.map.flags = 0; + dev_priv->render_ring.map.mtrr = 0; - drm_core_ioremap_wc(&dev_priv->ring.map, dev); + drm_core_ioremap_wc(&dev_priv->render_ring.map, dev); - if (dev_priv->ring.map.handle == NULL) { + if (dev_priv->render_ring.map.handle == NULL) { i915_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); @@ -181,7 +181,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) } } - dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->render_ring.virtual_start = dev_priv->render_ring.map.handle; dev_priv->cpp = init->cpp; dev_priv->back_offset = init->back_offset; @@ -203,7 +203,7 @@ static int i915_dma_resume(struct drm_device * dev) DRM_DEBUG_DRIVER("%s\n", __func__); - if (dev_priv->ring.map.handle == NULL) { + if (dev_priv->render_ring.map.handle == NULL) { DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); return -ENOMEM; @@ -332,7 +332,7 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords) int i; RING_LOCALS; - if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8) + if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.Size - 8) return -EINVAL; BEGIN_LP_RING((dwords+1)&~1); @@ -563,7 +563,7 @@ static int i915_quiescent(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; i915_kernel_lost_context(dev); - return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__); + return i915_wait_ring(dev, dev_priv->render_ring.Size - 8, __func__); } static int i915_flush_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 5c51e45ab68d..a1814f65fdb4 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -389,7 +389,7 @@ int i965_reset(struct drm_device *dev, u8 flags) */ if (drm_core_check_feature(dev, DRIVER_MODESET) || !dev_priv->mm.suspended) { - drm_i915_ring_buffer_t *ring = &dev_priv->ring; + drm_i915_ring_buffer_t *ring = &dev_priv->render_ring; struct drm_gem_object *obj = ring->ring_obj; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); dev_priv->mm.suspended = 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 114653aa9ae2..a39440cf1dee 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -244,7 +244,7 @@ typedef struct drm_i915_private { void __iomem *regs; struct pci_dev *bridge_dev; - drm_i915_ring_buffer_t ring; + drm_i915_ring_buffer_t render_ring; drm_dma_handle_t *status_page_dmah; void *hw_status_page; @@ -1044,7 +1044,7 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); * has access to the ring. */ #define RING_LOCK_TEST_WITH_RETURN(dev, file_priv) do { \ - if (((drm_i915_private_t *)dev->dev_private)->ring.ring_obj == NULL) \ + if (((drm_i915_private_t *)dev->dev_private)->render_ring.ring_obj == NULL) \ LOCK_TEST_WITH_RETURN(dev, file_priv); \ } while (0) @@ -1066,15 +1066,15 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); int bytes__ = 4*(n); \ if (I915_VERBOSE) DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \ /* a wrap must occur between instructions so pad beforehand */ \ - if (unlikely (dev_priv->ring.tail + bytes__ > dev_priv->ring.Size)) \ + if (unlikely (dev_priv->render_ring.tail + bytes__ > dev_priv->render_ring.Size)) \ i915_wrap_ring(dev); \ - if (unlikely (dev_priv->ring.space < bytes__)) \ + if (unlikely (dev_priv->render_ring.space < bytes__)) \ i915_wait_ring(dev, bytes__, __func__); \ ring_virt__ = (unsigned int *) \ - (dev_priv->ring.virtual_start + dev_priv->ring.tail); \ - dev_priv->ring.tail += bytes__; \ - dev_priv->ring.tail &= dev_priv->ring.Size - 1; \ - dev_priv->ring.space -= bytes__; \ + (dev_priv->render_ring.virtual_start + dev_priv->render_ring.tail); \ + dev_priv->render_ring.tail += bytes__; \ + dev_priv->render_ring.tail &= dev_priv->render_ring.Size - 1; \ + dev_priv->render_ring.space -= bytes__; \ } while (0) #define OUT_RING(n) do { \ @@ -1084,8 +1084,8 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); #define ADVANCE_LP_RING() do { \ if (I915_VERBOSE) \ - DRM_DEBUG("ADVANCE_LP_RING %x\n", dev_priv->ring.tail); \ - I915_WRITE(PRB0_TAIL, dev_priv->ring.tail); \ + DRM_DEBUG("ADVANCE_LP_RING %x\n", dev_priv->render_ring.tail); \ + I915_WRITE(PRB0_TAIL, dev_priv->render_ring.tail); \ } while(0) /** diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4f2f5f8cdca2..95dbe5628a25 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4378,7 +4378,7 @@ i915_gem_idle(struct drm_device *dev) mutex_lock(&dev->struct_mutex); - if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) { + if (dev_priv->mm.suspended || dev_priv->render_ring.ring_obj == NULL) { mutex_unlock(&dev->struct_mutex); return 0; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 896184bfeb12..dd91c97de968 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -536,17 +536,17 @@ i915_ringbuffer_last_batch(struct drm_device *dev) */ bbaddr = 0; head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - ring = (u32 *)(dev_priv->ring.virtual_start + head); + ring = (u32 *)(dev_priv->render_ring.virtual_start + head); - while (--ring >= (u32 *)dev_priv->ring.virtual_start) { + while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) { bbaddr = i915_get_bbaddr(dev, ring); if (bbaddr) break; } if (bbaddr == 0) { - ring = (u32 *)(dev_priv->ring.virtual_start + dev_priv->ring.Size); - while (--ring >= (u32 *)dev_priv->ring.virtual_start) { + ring = (u32 *)(dev_priv->render_ring.virtual_start + dev_priv->render_ring.Size); + while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) { bbaddr = i915_get_bbaddr(dev, ring); if (bbaddr) break; @@ -639,7 +639,7 @@ static void i915_capture_error_state(struct drm_device *dev) error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); /* Record the ringbuffer */ - error->ringbuffer = i915_error_object_create(dev, dev_priv->ring.ring_obj); + error->ringbuffer = i915_error_object_create(dev, dev_priv->render_ring.ring_obj); /* Record buffers on the active list. */ error->active_bo = NULL; @@ -1056,7 +1056,7 @@ int i915_irq_emit(struct drm_device *dev, void *data, drm_i915_irq_emit_t *emit = data; int result; - if (!dev_priv || !dev_priv->ring.virtual_start) { + if (!dev_priv || !dev_priv->render_ring.virtual_start) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 13a796fafaee..06058ddb4eed 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -368,7 +368,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - drm_i915_ring_buffer_t *ring = &dev_priv->ring; + drm_i915_ring_buffer_t *ring = &dev_priv->render_ring; int ret; u32 head; @@ -403,7 +403,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev) drm_core_ioremap_wc(&ring->map, dev); if (ring->map.handle == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); - memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); + memset(&dev_priv->render_ring, 0, sizeof(dev_priv->render_ring)); i915_gem_object_unpin(obj); drm_gem_object_unreference(obj); i915_gem_cleanup_hws(dev); @@ -481,15 +481,15 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - if (dev_priv->ring.ring_obj == NULL) + if (dev_priv->render_ring.ring_obj == NULL) return; - drm_core_ioremapfree(&dev_priv->ring.map, dev); + drm_core_ioremapfree(&dev_priv->render_ring.map, dev); - i915_gem_object_unpin(dev_priv->ring.ring_obj); - drm_gem_object_unreference(dev_priv->ring.ring_obj); - dev_priv->ring.ring_obj = NULL; - memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); + i915_gem_object_unpin(dev_priv->render_ring.ring_obj); + drm_gem_object_unreference(dev_priv->render_ring.ring_obj); + dev_priv->render_ring.ring_obj = NULL; + memset(&dev_priv->render_ring, 0, sizeof(dev_priv->render_ring)); i915_gem_cleanup_hws(dev); } @@ -503,21 +503,21 @@ int i915_wrap_ring(struct drm_device *dev) volatile unsigned int *virt; int rem; - rem = dev_priv->ring.Size - dev_priv->ring.tail; - if (dev_priv->ring.space < rem) { + rem = dev_priv->render_ring.Size - dev_priv->render_ring.tail; + if (dev_priv->render_ring.space < rem) { int ret = i915_wait_ring(dev, rem, __func__); if (ret) return ret; } - dev_priv->ring.space -= rem; + dev_priv->render_ring.space -= rem; virt = (unsigned int *) - (dev_priv->ring.virtual_start + dev_priv->ring.tail); + (dev_priv->render_ring.virtual_start + dev_priv->render_ring.tail); rem /= 4; while (rem--) *virt++ = MI_NOOP; - dev_priv->ring.tail = 0; + dev_priv->render_ring.tail = 0; return 0; } @@ -525,7 +525,7 @@ int i915_wrap_ring(struct drm_device *dev) int i915_wait_ring(struct drm_device * dev, int n, const char *caller) { drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_ring_buffer_t *ring = &(dev_priv->ring); + drm_i915_ring_buffer_t *ring = &(dev_priv->render_ring); u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; u32 last_acthd = I915_READ(acthd_reg); u32 acthd; -- GitLab From 8187a2b70e34c727a06617441f74f202b6fefaf9 Mon Sep 17 00:00:00 2001 From: Zou Nan hai <nanhai.zou@intel.com> Date: Fri, 21 May 2010 09:08:55 +0800 Subject: [PATCH 211/842] drm/i915: introduce intel_ring_buffer structure (V2) Introduces a more complete intel_ring_buffer structure with callbacks for setup and management of a particular ringbuffer, and converts the render ring buffer consumers to use it. Signed-off-by: Zou Nan hai <nanhai.zou@intel.com> Signed-off-by: Xiang Hai hao <haihao.xiang@intel.com> [anholt: Fixed up whitespace fail and rebased against prep patches] Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +- drivers/gpu/drm/i915/i915_dma.c | 58 +-- drivers/gpu/drm/i915/i915_drv.c | 29 +- drivers/gpu/drm/i915/i915_drv.h | 80 +--- drivers/gpu/drm/i915/i915_gem.c | 76 +++- drivers/gpu/drm/i915/i915_irq.c | 15 +- drivers/gpu/drm/i915/intel_display.c | 1 - drivers/gpu/drm/i915/intel_overlay.c | 8 - drivers/gpu/drm/i915/intel_ringbuffer.c | 582 ++++++++++++++---------- drivers/gpu/drm/i915/intel_ringbuffer.h | 124 +++++ include/drm/i915_drm.h | 4 +- 11 files changed, 606 insertions(+), 377 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_ringbuffer.h diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 488175c70c7d..4fddf094deb2 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -317,14 +317,14 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) u8 *virt; uint32_t *ptr, off; - if (!dev_priv->render_ring.ring_obj) { + if (!dev_priv->render_ring.gem_object) { seq_printf(m, "No ringbuffer setup\n"); return 0; } virt = dev_priv->render_ring.virtual_start; - for (off = 0; off < dev_priv->render_ring.Size; off += 4) { + for (off = 0; off < dev_priv->render_ring.size; off += 4) { ptr = (uint32_t *)(virt + off); seq_printf(m, "%08x : %08x\n", off, *ptr); } @@ -344,7 +344,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) seq_printf(m, "RingHead : %08x\n", head); seq_printf(m, "RingTail : %08x\n", tail); - seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.Size); + seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.size); seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); return 0; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 6de7eace4319..2541428b2fe5 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -40,7 +40,6 @@ #include <linux/vga_switcheroo.h> #include <linux/slab.h> - /** * Sets up the hardware status page for devices that need a physical address * in the register. @@ -56,10 +55,11 @@ static int i915_init_phys_hws(struct drm_device *dev) DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; + dev_priv->render_ring.status_page.page_addr + = dev_priv->status_page_dmah->vaddr; dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE); if (IS_I965G(dev)) dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) & @@ -95,7 +95,7 @@ void i915_kernel_lost_context(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; - drm_i915_ring_buffer_t *ring = &(dev_priv->render_ring); + struct intel_ring_buffer *ring = &dev_priv->render_ring; /* * We should never lose context on the ring with modesetting @@ -108,7 +108,7 @@ void i915_kernel_lost_context(struct drm_device * dev) ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) - ring->space += ring->Size; + ring->space += ring->size; if (!dev->primary->master) return; @@ -128,12 +128,7 @@ static int i915_dma_cleanup(struct drm_device * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); - if (dev_priv->render_ring.virtual_start) { - drm_core_ioremapfree(&dev_priv->render_ring.map, dev); - dev_priv->render_ring.virtual_start = NULL; - dev_priv->render_ring.map.handle = NULL; - dev_priv->render_ring.map.size = 0; - } + intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); /* Clear the HWS virtual address at teardown */ if (I915_NEED_GFX_HWS(dev)) @@ -156,14 +151,14 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) } if (init->ring_size != 0) { - if (dev_priv->render_ring.ring_obj != NULL) { + if (dev_priv->render_ring.gem_object != NULL) { i915_dma_cleanup(dev); DRM_ERROR("Client tried to initialize ringbuffer in " "GEM mode\n"); return -EINVAL; } - dev_priv->render_ring.Size = init->ring_size; + dev_priv->render_ring.size = init->ring_size; dev_priv->render_ring.map.offset = init->ring_start; dev_priv->render_ring.map.size = init->ring_size; @@ -201,26 +196,29 @@ static int i915_dma_resume(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct intel_ring_buffer *ring; DRM_DEBUG_DRIVER("%s\n", __func__); - if (dev_priv->render_ring.map.handle == NULL) { + ring = &dev_priv->render_ring; + + if (ring->map.handle == NULL) { DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); return -ENOMEM; } /* Program Hardware Status Page */ - if (!dev_priv->hw_status_page) { + if (!ring->status_page.page_addr) { DRM_ERROR("Can not find hardware status page\n"); return -EINVAL; } DRM_DEBUG_DRIVER("hw status page @ %p\n", - dev_priv->hw_status_page); - - if (dev_priv->status_gfx_addr != 0) - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); + ring->status_page.page_addr); + if (ring->status_page.gfx_addr != 0) + ring->setup_status_page(dev, ring); else I915_WRITE(HWS_PGA, dev_priv->dma_status_page); + DRM_DEBUG_DRIVER("Enabled hardware status page\n"); return 0; @@ -330,9 +328,8 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords) { drm_i915_private_t *dev_priv = dev->dev_private; int i; - RING_LOCALS; - if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.Size - 8) + if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8) return -EINVAL; BEGIN_LP_RING((dwords+1)&~1); @@ -365,9 +362,7 @@ i915_emit_box(struct drm_device *dev, struct drm_clip_rect *boxes, int i, int DR1, int DR4) { - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_clip_rect box = boxes[i]; - RING_LOCALS; if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { DRM_ERROR("Bad box %d,%d..%d,%d\n", @@ -404,7 +399,6 @@ static void i915_emit_breadcrumb(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - RING_LOCALS; dev_priv->counter++; if (dev_priv->counter > 0x7FFFFFFFUL) @@ -458,10 +452,8 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, drm_i915_batchbuffer_t * batch, struct drm_clip_rect *cliprects) { - drm_i915_private_t *dev_priv = dev->dev_private; int nbox = batch->num_cliprects; int i = 0, count; - RING_LOCALS; if ((batch->start | batch->used) & 0x7) { DRM_ERROR("alignment"); @@ -510,7 +502,6 @@ static int i915_dispatch_flip(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - RING_LOCALS; if (!master_priv->sarea_priv) return -EINVAL; @@ -563,7 +554,8 @@ static int i915_quiescent(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; i915_kernel_lost_context(dev); - return i915_wait_ring(dev, dev_priv->render_ring.Size - 8, __func__); + return intel_wait_ring_buffer(dev, &dev_priv->render_ring, + dev_priv->render_ring.size - 8); } static int i915_flush_ioctl(struct drm_device *dev, void *data, @@ -805,6 +797,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_hws_addr_t *hws = data; + struct intel_ring_buffer *ring = &dev_priv->render_ring; if (!I915_NEED_GFX_HWS(dev)) return -EINVAL; @@ -821,7 +814,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, DRM_DEBUG_DRIVER("set status page addr 0x%08x\n", (u32)hws->addr); - dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); + ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12); dev_priv->hws_map.offset = dev->agp->base + hws->addr; dev_priv->hws_map.size = 4*1024; @@ -837,10 +830,10 @@ static int i915_set_status_page(struct drm_device *dev, void *data, " G33 hw status page\n"); return -ENOMEM; } - dev_priv->hw_status_page = dev_priv->hws_map.handle; + ring->status_page.page_addr = dev_priv->hws_map.handle; + memset(ring->status_page.page_addr, 0, PAGE_SIZE); + I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n", dev_priv->status_gfx_addr); DRM_DEBUG_DRIVER("load hws at %p\n", @@ -1639,7 +1632,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->user_irq_lock); spin_lock_init(&dev_priv->error_lock); - dev_priv->user_irq_refcount = 0; dev_priv->trace_irq_seqno = 0; ret = drm_vblank_init(dev, I915_NUM_PIPE); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a1814f65fdb4..c57c54f403da 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -388,33 +388,10 @@ int i965_reset(struct drm_device *dev, u8 flags) * switched away). */ if (drm_core_check_feature(dev, DRIVER_MODESET) || - !dev_priv->mm.suspended) { - drm_i915_ring_buffer_t *ring = &dev_priv->render_ring; - struct drm_gem_object *obj = ring->ring_obj; - struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + !dev_priv->mm.suspended) { + struct intel_ring_buffer *ring = &dev_priv->render_ring; dev_priv->mm.suspended = 0; - - /* Stop the ring if it's running. */ - I915_WRITE(PRB0_CTL, 0); - I915_WRITE(PRB0_TAIL, 0); - I915_WRITE(PRB0_HEAD, 0); - - /* Initialize the ring. */ - I915_WRITE(PRB0_START, obj_priv->gtt_offset); - I915_WRITE(PRB0_CTL, - ((obj->size - 4096) & RING_NR_PAGES) | - RING_NO_REPORT | - RING_VALID); - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - i915_kernel_lost_context(dev); - else { - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; - ring->space = ring->head - (ring->tail + 8); - if (ring->space < 0) - ring->space += ring->Size; - } - + ring->init(dev, ring); mutex_unlock(&dev->struct_mutex); drm_irq_uninstall(dev); drm_irq_install(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a39440cf1dee..6bb7933d49dc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -31,8 +31,8 @@ #define _I915_DRV_H_ #include "i915_reg.h" -#include "i915_drm.h" #include "intel_bios.h" +#include "intel_ringbuffer.h" #include <linux/io-mapping.h> /* General customization: @@ -92,16 +92,6 @@ struct drm_i915_gem_phys_object { struct drm_gem_object *cur_obj; }; -typedef struct _drm_i915_ring_buffer { - unsigned long Size; - u8 *virtual_start; - int head; - int tail; - int space; - drm_local_map_t map; - struct drm_gem_object *ring_obj; -} drm_i915_ring_buffer_t; - struct mem_block { struct mem_block *next; struct mem_block *prev; @@ -244,7 +234,7 @@ typedef struct drm_i915_private { void __iomem *regs; struct pci_dev *bridge_dev; - drm_i915_ring_buffer_t render_ring; + struct intel_ring_buffer render_ring; drm_dma_handle_t *status_page_dmah; void *hw_status_page; @@ -270,8 +260,6 @@ typedef struct drm_i915_private { atomic_t irq_received; /** Protects user_irq_refcount and irq_mask_reg */ spinlock_t user_irq_lock; - /** Refcount for i915_user_irq_get() versus i915_user_irq_put(). */ - int user_irq_refcount; u32 trace_irq_seqno; /** Cached value of IMR to avoid reads in updating the bitfield */ u32 irq_mask_reg; @@ -832,9 +820,7 @@ extern int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); -void i915_user_irq_get(struct drm_device *dev); void i915_trace_irq_get(struct drm_device *dev, u32 seqno); -void i915_user_irq_put(struct drm_device *dev); extern void i915_enable_interrupt (struct drm_device *dev); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); @@ -853,8 +839,10 @@ extern int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask); extern void i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask); -void ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask); -void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask); +extern void ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, + u32 mask); +extern void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, + u32 mask); void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); @@ -962,8 +950,6 @@ void i915_gem_object_flush_write_domain(struct drm_gem_object *obj); void i915_gem_shrinker_init(void); void i915_gem_shrinker_exit(void); -int i915_gem_init_pipe_control(struct drm_device *dev); -void i915_gem_cleanup_pipe_control(struct drm_device *dev); /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); @@ -1014,16 +1000,6 @@ static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; static inline void opregion_enable_asle(struct drm_device *dev) { return; } #endif -/* intel_ringbuffer.c */ -extern void i915_gem_flush(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains); -extern int i915_dispatch_gem_execbuffer(struct drm_device *dev, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset); -extern uint32_t i915_ring_add_request(struct drm_device *dev); - /* modesetting */ extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); @@ -1044,7 +1020,8 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); * has access to the ring. */ #define RING_LOCK_TEST_WITH_RETURN(dev, file_priv) do { \ - if (((drm_i915_private_t *)dev->dev_private)->render_ring.ring_obj == NULL) \ + if (((drm_i915_private_t *)dev->dev_private)->render_ring.gem_object \ + == NULL) \ LOCK_TEST_WITH_RETURN(dev, file_priv); \ } while (0) @@ -1060,32 +1037,27 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); #define I915_VERBOSE 0 -#define RING_LOCALS volatile unsigned int *ring_virt__; - -#define BEGIN_LP_RING(n) do { \ - int bytes__ = 4*(n); \ - if (I915_VERBOSE) DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \ - /* a wrap must occur between instructions so pad beforehand */ \ - if (unlikely (dev_priv->render_ring.tail + bytes__ > dev_priv->render_ring.Size)) \ - i915_wrap_ring(dev); \ - if (unlikely (dev_priv->render_ring.space < bytes__)) \ - i915_wait_ring(dev, bytes__, __func__); \ - ring_virt__ = (unsigned int *) \ - (dev_priv->render_ring.virtual_start + dev_priv->render_ring.tail); \ - dev_priv->render_ring.tail += bytes__; \ - dev_priv->render_ring.tail &= dev_priv->render_ring.Size - 1; \ - dev_priv->render_ring.space -= bytes__; \ +#define BEGIN_LP_RING(n) do { \ + drm_i915_private_t *dev_priv = dev->dev_private; \ + if (I915_VERBOSE) \ + DRM_DEBUG(" BEGIN_LP_RING %x\n", (int)(n)); \ + intel_ring_begin(dev, &dev_priv->render_ring, 4*(n)); \ } while (0) -#define OUT_RING(n) do { \ - if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ - *ring_virt__++ = (n); \ + +#define OUT_RING(x) do { \ + drm_i915_private_t *dev_priv = dev->dev_private; \ + if (I915_VERBOSE) \ + DRM_DEBUG(" OUT_RING %x\n", (int)(x)); \ + intel_ring_emit(dev, &dev_priv->render_ring, x); \ } while (0) #define ADVANCE_LP_RING() do { \ + drm_i915_private_t *dev_priv = dev->dev_private; \ if (I915_VERBOSE) \ - DRM_DEBUG("ADVANCE_LP_RING %x\n", dev_priv->render_ring.tail); \ - I915_WRITE(PRB0_TAIL, dev_priv->render_ring.tail); \ + DRM_DEBUG("ADVANCE_LP_RING %x\n", \ + dev_priv->render_ring.tail); \ + intel_ring_advance(dev, &dev_priv->render_ring); \ } while(0) /** @@ -1103,14 +1075,12 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); * * The area from dword 0x20 to 0x3ff is available for driver usage. */ -#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) +#define READ_HWSP(dev_priv, reg) (((volatile u32 *)\ + (dev_priv->render_ring.status_page.page_addr))[reg]) #define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX) #define I915_GEM_HWS_INDEX 0x20 #define I915_BREADCRUMB_INDEX 0x21 -extern int i915_wrap_ring(struct drm_device * dev); -extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); - #define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info) #define IS_I830(dev) ((dev)->pci_device == 0x3577) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 95dbe5628a25..58b6e814fae1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1590,6 +1590,7 @@ i915_gem_process_flushing_list(struct drm_device *dev, } } } + uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, uint32_t flush_domains) @@ -1607,7 +1608,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, if (request == NULL) return 0; - seqno = i915_ring_add_request(dev); + seqno = dev_priv->render_ring.add_request(dev, &dev_priv->render_ring, + file_priv, flush_domains); DRM_DEBUG_DRIVER("%d\n", seqno); @@ -1645,10 +1647,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, static uint32_t i915_retire_commands(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; uint32_t cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; uint32_t flush_domains = 0; - RING_LOCALS; /* The sampler always gets flushed on i965 (sigh) */ if (IS_I965G(dev)) @@ -1746,7 +1746,9 @@ i915_gem_retire_requests(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; uint32_t seqno; - if (!dev_priv->hw_status_page || list_empty(&dev_priv->mm.request_list)) + struct intel_ring_buffer *ring = &(dev_priv->render_ring); + if (!ring->status_page.page_addr + || list_empty(&dev_priv->mm.request_list)) return; seqno = i915_get_gem_seqno(dev); @@ -1773,7 +1775,8 @@ i915_gem_retire_requests(struct drm_device *dev) if (unlikely (dev_priv->trace_irq_seqno && i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) { - i915_user_irq_put(dev); + + ring->user_irq_put(dev, ring); dev_priv->trace_irq_seqno = 0; } } @@ -1803,6 +1806,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) u32 ier; int ret = 0; + struct intel_ring_buffer *ring = &dev_priv->render_ring; BUG_ON(seqno == 0); if (atomic_read(&dev_priv->mm.wedged)) @@ -1823,7 +1827,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) trace_i915_gem_request_wait_begin(dev, seqno); dev_priv->mm.waiting_gem_seqno = seqno; - i915_user_irq_get(dev); + ring->user_irq_get(dev, ring); if (interruptible) ret = wait_event_interruptible(dev_priv->irq_queue, i915_seqno_passed(i915_get_gem_seqno(dev), seqno) || @@ -1833,7 +1837,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) i915_seqno_passed(i915_get_gem_seqno(dev), seqno) || atomic_read(&dev_priv->mm.wedged)); - i915_user_irq_put(dev); + ring->user_irq_put(dev, ring); dev_priv->mm.waiting_gem_seqno = 0; trace_i915_gem_request_wait_end(dev, seqno); @@ -1867,6 +1871,19 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno) } +static void +i915_gem_flush(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + if (flush_domains & I915_GEM_DOMAIN_CPU) + drm_agp_chipset_flush(dev); + dev_priv->render_ring.flush(dev, &dev_priv->render_ring, + invalidate_domains, + flush_domains); +} + /** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. @@ -3820,7 +3837,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, #endif /* Exec the batchbuffer */ - ret = i915_dispatch_gem_execbuffer(dev, args, cliprects, exec_offset); + ret = dev_priv->render_ring.dispatch_gem_execbuffer(dev, + &dev_priv->render_ring, + args, + cliprects, + exec_offset); if (ret) { DRM_ERROR("dispatch failed %d\n", ret); goto err; @@ -4378,7 +4399,8 @@ i915_gem_idle(struct drm_device *dev) mutex_lock(&dev->struct_mutex); - if (dev_priv->mm.suspended || dev_priv->render_ring.ring_obj == NULL) { + if (dev_priv->mm.suspended || + dev_priv->render_ring.gem_object == NULL) { mutex_unlock(&dev->struct_mutex); return 0; } @@ -4420,7 +4442,7 @@ i915_gem_idle(struct drm_device *dev) * 965+ support PIPE_CONTROL commands, which provide finer grained control * over cache flushing. */ -int +static int i915_gem_init_pipe_control(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -4459,7 +4481,8 @@ err: return ret; } -void + +static void i915_gem_cleanup_pipe_control(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -4476,6 +4499,37 @@ i915_gem_cleanup_pipe_control(struct drm_device *dev) dev_priv->seqno_page = NULL; } +int +i915_gem_init_ringbuffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + dev_priv->render_ring = render_ring; + if (!I915_NEED_GFX_HWS(dev)) { + dev_priv->render_ring.status_page.page_addr + = dev_priv->status_page_dmah->vaddr; + memset(dev_priv->render_ring.status_page.page_addr, + 0, PAGE_SIZE); + } + if (HAS_PIPE_CONTROL(dev)) { + ret = i915_gem_init_pipe_control(dev); + if (ret) + return ret; + } + ret = intel_init_ring_buffer(dev, &dev_priv->render_ring); + return ret; +} + +void +i915_gem_cleanup_ringbuffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); + if (HAS_PIPE_CONTROL(dev)) + i915_gem_cleanup_pipe_control(dev); +} + int i915_gem_entervt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index dd91c97de968..e07c643c8365 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -545,7 +545,8 @@ i915_ringbuffer_last_batch(struct drm_device *dev) } if (bbaddr == 0) { - ring = (u32 *)(dev_priv->render_ring.virtual_start + dev_priv->render_ring.Size); + ring = (u32 *)(dev_priv->render_ring.virtual_start + + dev_priv->render_ring.size); while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) { bbaddr = i915_get_bbaddr(dev, ring); if (bbaddr) @@ -639,7 +640,8 @@ static void i915_capture_error_state(struct drm_device *dev) error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); /* Record the ringbuffer */ - error->ringbuffer = i915_error_object_create(dev, dev_priv->render_ring.ring_obj); + error->ringbuffer = i915_error_object_create(dev, + dev_priv->render_ring.gem_object); /* Record buffers on the active list. */ error->active_bo = NULL; @@ -984,7 +986,6 @@ static int i915_emit_irq(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - RING_LOCALS; i915_kernel_lost_context(dev); @@ -1009,9 +1010,10 @@ static int i915_emit_irq(struct drm_device * dev) void i915_trace_irq_get(struct drm_device *dev, u32 seqno) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; if (dev_priv->trace_irq_seqno == 0) - i915_user_irq_get(dev); + render_ring->user_irq_get(dev, render_ring); dev_priv->trace_irq_seqno = seqno; } @@ -1021,6 +1023,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; int ret = 0; + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; DRM_DEBUG_DRIVER("irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv)); @@ -1034,10 +1037,10 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; - i915_user_irq_get(dev); + render_ring->user_irq_get(dev, render_ring); DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); - i915_user_irq_put(dev); + render_ring->user_irq_put(dev, render_ring); if (ret == -EBUSY) { DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f469a84cacfd..b867f3c78408 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4629,7 +4629,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, unsigned long flags; int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC; int ret, pipesrc; - RING_LOCALS; work = kzalloc(sizeof *work, GFP_KERNEL); if (work == NULL) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index b0e17b06eb6e..93da83782e5e 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -211,9 +211,7 @@ static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay) static int intel_overlay_on(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; - drm_i915_private_t *dev_priv = dev->dev_private; int ret; - RING_LOCALS; BUG_ON(overlay->active); @@ -248,7 +246,6 @@ static void intel_overlay_continue(struct intel_overlay *overlay, drm_i915_private_t *dev_priv = dev->dev_private; u32 flip_addr = overlay->flip_addr; u32 tmp; - RING_LOCALS; BUG_ON(!overlay->active); @@ -274,7 +271,6 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay) drm_i915_private_t *dev_priv = dev->dev_private; int ret; u32 tmp; - RING_LOCALS; if (overlay->last_flip_req != 0) { ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); @@ -314,9 +310,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) { u32 flip_addr = overlay->flip_addr; struct drm_device *dev = overlay->dev; - drm_i915_private_t *dev_priv = dev->dev_private; int ret; - RING_LOCALS; BUG_ON(!overlay->active); @@ -390,11 +384,9 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, int interruptible) { struct drm_device *dev = overlay->dev; - drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; u32 flip_addr; int ret; - RING_LOCALS; if (overlay->hw_wedged == HW_WEDGED) return -EIO; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 06058ddb4eed..5715c4d8cce9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -29,30 +29,24 @@ #include "drmP.h" #include "drm.h" -#include "i915_drm.h" #include "i915_drv.h" +#include "i915_drm.h" #include "i915_trace.h" -#include "intel_drv.h" -void -i915_gem_flush(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains) +static void +render_ring_flush(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) { - drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t cmd; - RING_LOCALS; - #if WATCH_EXEC DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, invalidate_domains, flush_domains); #endif - trace_i915_gem_request_flush(dev, dev_priv->mm.next_gem_seqno, + u32 cmd; + trace_i915_gem_request_flush(dev, ring->next_seqno, invalidate_domains, flush_domains); - if (flush_domains & I915_GEM_DOMAIN_CPU) - drm_agp_chipset_flush(dev); - if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { /* * read/write caches: @@ -100,19 +94,130 @@ i915_gem_flush(struct drm_device *dev, #if WATCH_EXEC DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); #endif - BEGIN_LP_RING(2); - OUT_RING(cmd); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + intel_ring_begin(dev, ring, 8); + intel_ring_emit(dev, ring, cmd); + intel_ring_emit(dev, ring, MI_NOOP); + intel_ring_advance(dev, ring); } +} + +static unsigned int render_ring_get_head(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(PRB0_HEAD) & HEAD_ADDR; +} +static unsigned int render_ring_get_tail(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(PRB0_TAIL) & TAIL_ADDR; } + +static unsigned int render_ring_get_active_head(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; + + return I915_READ(acthd_reg); +} + +static void render_ring_advance_ring(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + I915_WRITE(PRB0_TAIL, ring->tail); +} + +static int init_ring_common(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + u32 head; + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj_priv; + obj_priv = to_intel_bo(ring->gem_object); + + /* Stop the ring if it's running. */ + I915_WRITE(ring->regs.ctl, 0); + I915_WRITE(ring->regs.head, 0); + I915_WRITE(ring->regs.tail, 0); + + /* Initialize the ring. */ + I915_WRITE(ring->regs.start, obj_priv->gtt_offset); + head = ring->get_head(dev, ring); + + /* G45 ring initialization fails to reset head to zero */ + if (head != 0) { + DRM_ERROR("%s head not reset to zero " + "ctl %08x head %08x tail %08x start %08x\n", + ring->name, + I915_READ(ring->regs.ctl), + I915_READ(ring->regs.head), + I915_READ(ring->regs.tail), + I915_READ(ring->regs.start)); + + I915_WRITE(ring->regs.head, 0); + + DRM_ERROR("%s head forced to zero " + "ctl %08x head %08x tail %08x start %08x\n", + ring->name, + I915_READ(ring->regs.ctl), + I915_READ(ring->regs.head), + I915_READ(ring->regs.tail), + I915_READ(ring->regs.start)); + } + + I915_WRITE(ring->regs.ctl, + ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES) + | RING_NO_REPORT | RING_VALID); + + head = I915_READ(ring->regs.head) & HEAD_ADDR; + /* If the head is still not zero, the ring is dead */ + if (head != 0) { + DRM_ERROR("%s initialization failed " + "ctl %08x head %08x tail %08x start %08x\n", + ring->name, + I915_READ(ring->regs.ctl), + I915_READ(ring->regs.head), + I915_READ(ring->regs.tail), + I915_READ(ring->regs.start)); + return -EIO; + } + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_kernel_lost_context(dev); + else { + ring->head = ring->get_head(dev, ring); + ring->tail = ring->get_tail(dev, ring); + ring->space = ring->head - (ring->tail + 8); + if (ring->space < 0) + ring->space += ring->size; + } + return 0; +} + +static int init_render_ring(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret = init_ring_common(dev, ring); + if (IS_I9XX(dev) && !IS_GEN3(dev)) { + I915_WRITE(MI_MODE, + (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH); + } + return ret; +} + #define PIPE_CONTROL_FLUSH(addr) \ +do { \ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ PIPE_CONTROL_DEPTH_STALL); \ OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \ OUT_RING(0); \ OUT_RING(0); \ +} while (0) /** * Creates a new sequence number, emitting a write of it to the status page @@ -122,21 +227,15 @@ i915_gem_flush(struct drm_device *dev, * * Returned sequence numbers are nonzero on success. */ -uint32_t -i915_ring_add_request(struct drm_device *dev) +static u32 +render_ring_add_request(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_file *file_priv, + u32 flush_domains) { + u32 seqno; drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t seqno; - RING_LOCALS; - - /* Grab the seqno we're going to make this request be, and bump the - * next (skipping 0 so it can be the reserved no-seqno value). - */ - seqno = dev_priv->mm.next_gem_seqno; - dev_priv->mm.next_gem_seqno++; - if (dev_priv->mm.next_gem_seqno == 0) - dev_priv->mm.next_gem_seqno++; - + seqno = intel_ring_get_seqno(dev, ring); if (HAS_PIPE_CONTROL(dev)) { u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; @@ -181,13 +280,26 @@ i915_ring_add_request(struct drm_device *dev) return seqno; } -void i915_user_irq_get(struct drm_device *dev) +static u32 +render_ring_get_gem_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (HAS_PIPE_CONTROL(dev)) + return ((volatile u32 *)(dev_priv->seqno_page))[0]; + else + return intel_read_status_page(ring, I915_GEM_HWS_INDEX); +} + +static void +render_ring_get_user_irq(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { + if (dev->irq_enabled && (++ring->user_irq_refcount == 1)) { if (HAS_PCH_SPLIT(dev)) ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); else @@ -196,14 +308,16 @@ void i915_user_irq_get(struct drm_device *dev) spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } -void i915_user_irq_put(struct drm_device *dev) +static void +render_ring_put_user_irq(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); - if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { + BUG_ON(dev->irq_enabled && ring->user_irq_refcount <= 0); + if (dev->irq_enabled && (--ring->user_irq_refcount == 0)) { if (HAS_PCH_SPLIT(dev)) ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); else @@ -212,20 +326,31 @@ void i915_user_irq_put(struct drm_device *dev) spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } -/** Dispatch a batchbuffer to the ring - */ -int -i915_dispatch_gem_execbuffer(struct drm_device *dev, - struct drm_i915_gem_execbuffer2 *exec, - struct drm_clip_rect *cliprects, - uint64_t exec_offset) +static void render_setup_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + if (IS_GEN6(dev)) { + I915_WRITE(HWS_PGA_GEN6, ring->status_page.gfx_addr); + I915_READ(HWS_PGA_GEN6); /* posting read */ + } else { + I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); + I915_READ(HWS_PGA); /* posting read */ + } + +} + +static int +render_ring_dispatch_gem_execbuffer(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) { drm_i915_private_t *dev_priv = dev->dev_private; int nbox = exec->num_cliprects; int i = 0, count; uint32_t exec_start, exec_len; - RING_LOCALS; - exec_start = (uint32_t) exec_offset + exec->batch_start_offset; exec_len = (uint32_t) exec->batch_len; @@ -242,74 +367,61 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev, } if (IS_I830(dev) || IS_845G(dev)) { - BEGIN_LP_RING(4); - OUT_RING(MI_BATCH_BUFFER); - OUT_RING(exec_start | MI_BATCH_NON_SECURE); - OUT_RING(exec_start + exec_len - 4); - OUT_RING(0); - ADVANCE_LP_RING(); + intel_ring_begin(dev, ring, 4); + intel_ring_emit(dev, ring, MI_BATCH_BUFFER); + intel_ring_emit(dev, ring, + exec_start | MI_BATCH_NON_SECURE); + intel_ring_emit(dev, ring, exec_start + exec_len - 4); + intel_ring_emit(dev, ring, 0); } else { - BEGIN_LP_RING(2); + intel_ring_begin(dev, ring, 4); if (IS_I965G(dev)) { - OUT_RING(MI_BATCH_BUFFER_START | - (2 << 6) | - MI_BATCH_NON_SECURE_I965); - OUT_RING(exec_start); + intel_ring_emit(dev, ring, + MI_BATCH_BUFFER_START | (2 << 6) + | MI_BATCH_NON_SECURE_I965); + intel_ring_emit(dev, ring, exec_start); } else { - OUT_RING(MI_BATCH_BUFFER_START | - (2 << 6)); - OUT_RING(exec_start | MI_BATCH_NON_SECURE); + intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START + | (2 << 6)); + intel_ring_emit(dev, ring, exec_start | + MI_BATCH_NON_SECURE); } - ADVANCE_LP_RING(); } + intel_ring_advance(dev, ring); } /* XXX breadcrumb */ return 0; } -static void -i915_gem_cleanup_hws(struct drm_device *dev) +static void cleanup_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - if (dev_priv->hws_obj == NULL) + obj = ring->status_page.obj; + if (obj == NULL) return; - - obj = dev_priv->hws_obj; obj_priv = to_intel_bo(obj); kunmap(obj_priv->pages[0]); i915_gem_object_unpin(obj); drm_gem_object_unreference(obj); - dev_priv->hws_obj = NULL; + ring->status_page.obj = NULL; memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); - dev_priv->hw_status_page = NULL; - - if (HAS_PIPE_CONTROL(dev)) - i915_gem_cleanup_pipe_control(dev); - - /* Write high address into HWS_PGA when disabling. */ - I915_WRITE(HWS_PGA, 0x1ffff000); } -static int -i915_gem_init_hws(struct drm_device *dev) +static int init_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; int ret; - /* If we need a physical address for the status page, it's already - * initialized at driver load time. - */ - if (!I915_NEED_GFX_HWS(dev)) - return 0; - obj = i915_gem_alloc_object(dev, 4096); if (obj == NULL) { DRM_ERROR("Failed to allocate status page\n"); @@ -321,36 +433,21 @@ i915_gem_init_hws(struct drm_device *dev) ret = i915_gem_object_pin(obj, 4096); if (ret != 0) { - drm_gem_object_unreference(obj); goto err_unref; } - dev_priv->status_gfx_addr = obj_priv->gtt_offset; - - dev_priv->hw_status_page = kmap(obj_priv->pages[0]); - if (dev_priv->hw_status_page == NULL) { - DRM_ERROR("Failed to map status page.\n"); + ring->status_page.gfx_addr = obj_priv->gtt_offset; + ring->status_page.page_addr = kmap(obj_priv->pages[0]); + if (ring->status_page.page_addr == NULL) { memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); - ret = -EINVAL; goto err_unpin; } + ring->status_page.obj = obj; + memset(ring->status_page.page_addr, 0, PAGE_SIZE); - if (HAS_PIPE_CONTROL(dev)) { - ret = i915_gem_init_pipe_control(dev); - if (ret) - goto err_unpin; - } - - dev_priv->hws_obj = obj; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - if (IS_GEN6(dev)) { - I915_WRITE(HWS_PGA_GEN6, dev_priv->status_gfx_addr); - I915_READ(HWS_PGA_GEN6); /* posting read */ - } else { - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); - I915_READ(HWS_PGA); /* posting read */ - } - DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); + ring->setup_status_page(dev, ring); + DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n", + ring->name, ring->status_page.gfx_addr); return 0; @@ -359,43 +456,42 @@ err_unpin: err_unref: drm_gem_object_unreference(obj); err: - return 0; + return ret; } -int -i915_gem_init_ringbuffer(struct drm_device *dev) + +int intel_init_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - drm_i915_ring_buffer_t *ring = &dev_priv->render_ring; int ret; - u32 head; + struct drm_i915_gem_object *obj_priv; + struct drm_gem_object *obj; + ring->dev = dev; - ret = i915_gem_init_hws(dev); - if (ret != 0) - return ret; + if (I915_NEED_GFX_HWS(dev)) { + ret = init_status_page(dev, ring); + if (ret) + return ret; + } - obj = i915_gem_alloc_object(dev, 128 * 1024); + obj = i915_gem_alloc_object(dev, ring->size); if (obj == NULL) { DRM_ERROR("Failed to allocate ringbuffer\n"); - i915_gem_cleanup_hws(dev); - return -ENOMEM; + ret = -ENOMEM; + goto cleanup; } - obj_priv = to_intel_bo(obj); - ret = i915_gem_object_pin(obj, 4096); + ring->gem_object = obj; + + ret = i915_gem_object_pin(obj, ring->alignment); if (ret != 0) { drm_gem_object_unreference(obj); - i915_gem_cleanup_hws(dev); - return ret; + goto cleanup; } - /* Set up the kernel mapping for the ring. */ - ring->Size = obj->size; - + obj_priv = to_intel_bo(obj); + ring->map.size = ring->size; ring->map.offset = dev->agp->base + obj_priv->gtt_offset; - ring->map.size = obj->size; ring->map.type = 0; ring->map.flags = 0; ring->map.mtrr = 0; @@ -403,143 +499,85 @@ i915_gem_init_ringbuffer(struct drm_device *dev) drm_core_ioremap_wc(&ring->map, dev); if (ring->map.handle == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); - memset(&dev_priv->render_ring, 0, sizeof(dev_priv->render_ring)); i915_gem_object_unpin(obj); drm_gem_object_unreference(obj); - i915_gem_cleanup_hws(dev); - return -EINVAL; - } - ring->ring_obj = obj; - ring->virtual_start = ring->map.handle; - - /* Stop the ring if it's running. */ - I915_WRITE(PRB0_CTL, 0); - I915_WRITE(PRB0_TAIL, 0); - I915_WRITE(PRB0_HEAD, 0); - - /* Initialize the ring. */ - I915_WRITE(PRB0_START, obj_priv->gtt_offset); - head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - - /* G45 ring initialization fails to reset head to zero */ - if (head != 0) { - DRM_ERROR("Ring head not reset to zero " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); - I915_WRITE(PRB0_HEAD, 0); - - DRM_ERROR("Ring head forced to zero " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); + ret = -EINVAL; + goto cleanup; } - I915_WRITE(PRB0_CTL, - ((obj->size - 4096) & RING_NR_PAGES) | - RING_NO_REPORT | - RING_VALID); - - head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - - /* If the head is still not zero, the ring is dead */ - if (head != 0) { - DRM_ERROR("Ring initialization failed " - "ctl %08x head %08x tail %08x start %08x\n", - I915_READ(PRB0_CTL), - I915_READ(PRB0_HEAD), - I915_READ(PRB0_TAIL), - I915_READ(PRB0_START)); - return -EIO; + ring->virtual_start = ring->map.handle; + ret = ring->init(dev, ring); + if (ret != 0) { + intel_cleanup_ring_buffer(dev, ring); + return ret; } - /* Update our cache of the ring state */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_kernel_lost_context(dev); else { - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; + ring->head = ring->get_head(dev, ring); + ring->tail = ring->get_tail(dev, ring); ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) - ring->space += ring->Size; + ring->space += ring->size; } - - if (IS_I9XX(dev) && !IS_GEN3(dev)) { - I915_WRITE(MI_MODE, - (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH); - } - - return 0; + INIT_LIST_HEAD(&ring->active_list); + INIT_LIST_HEAD(&ring->request_list); + return ret; +cleanup: + cleanup_status_page(dev, ring); + return ret; } -void -i915_gem_cleanup_ringbuffer(struct drm_device *dev) +void intel_cleanup_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - - if (dev_priv->render_ring.ring_obj == NULL) + if (ring->gem_object == NULL) return; - drm_core_ioremapfree(&dev_priv->render_ring.map, dev); - - i915_gem_object_unpin(dev_priv->render_ring.ring_obj); - drm_gem_object_unreference(dev_priv->render_ring.ring_obj); - dev_priv->render_ring.ring_obj = NULL; - memset(&dev_priv->render_ring, 0, sizeof(dev_priv->render_ring)); + drm_core_ioremapfree(&ring->map, dev); - i915_gem_cleanup_hws(dev); + i915_gem_object_unpin(ring->gem_object); + drm_gem_object_unreference(ring->gem_object); + ring->gem_object = NULL; + cleanup_status_page(dev, ring); } -/* As a ringbuffer is only allowed to wrap between instructions, fill - * the tail with NOOPs. - */ -int i915_wrap_ring(struct drm_device *dev) +int intel_wrap_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - volatile unsigned int *virt; + unsigned int *virt; int rem; + rem = ring->size - ring->tail; - rem = dev_priv->render_ring.Size - dev_priv->render_ring.tail; - if (dev_priv->render_ring.space < rem) { - int ret = i915_wait_ring(dev, rem, __func__); + if (ring->space < rem) { + int ret = intel_wait_ring_buffer(dev, ring, rem); if (ret) return ret; } - dev_priv->render_ring.space -= rem; - virt = (unsigned int *) - (dev_priv->render_ring.virtual_start + dev_priv->render_ring.tail); + virt = (unsigned int *)(ring->virtual_start + ring->tail); rem /= 4; while (rem--) *virt++ = MI_NOOP; - dev_priv->render_ring.tail = 0; + ring->tail = 0; return 0; } -int i915_wait_ring(struct drm_device * dev, int n, const char *caller) +int intel_wait_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring, int n) { - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_ring_buffer_t *ring = &(dev_priv->render_ring); - u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; - u32 last_acthd = I915_READ(acthd_reg); - u32 acthd; - u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - int i; + unsigned long end; trace_i915_ring_wait_begin (dev); - - for (i = 0; i < 100000; i++) { - ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; - acthd = I915_READ(acthd_reg); + end = jiffies + 3 * HZ; + do { + ring->head = ring->get_head(dev, ring); ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) - ring->space += ring->Size; + ring->space += ring->size; if (ring->space >= n) { trace_i915_ring_wait_end (dev); return 0; @@ -550,19 +588,97 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; } + yield(); + } while (!time_after(jiffies, end)); + trace_i915_ring_wait_end (dev); + return -EBUSY; +} +void intel_ring_begin(struct drm_device *dev, + struct intel_ring_buffer *ring, int n) +{ + if (unlikely(ring->tail + n > ring->size)) + intel_wrap_ring_buffer(dev, ring); + if (unlikely(ring->space < n)) + intel_wait_ring_buffer(dev, ring, n); +} - if (ring->head != last_head) - i = 0; - if (acthd != last_acthd) - i = 0; +void intel_ring_emit(struct drm_device *dev, + struct intel_ring_buffer *ring, unsigned int data) +{ + unsigned int *virt = ring->virtual_start + ring->tail; + *virt = data; + ring->tail += 4; + ring->tail &= ring->size - 1; + ring->space -= 4; +} - last_head = ring->head; - last_acthd = acthd; - msleep_interruptible(10); +void intel_ring_advance(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + ring->advance_ring(dev, ring); +} - } +void intel_fill_struct(struct drm_device *dev, + struct intel_ring_buffer *ring, + void *data, + unsigned int len) +{ + unsigned int *virt = ring->virtual_start + ring->tail; + BUG_ON((len&~(4-1)) != 0); + intel_ring_begin(dev, ring, len); + memcpy(virt, data, len); + ring->tail += len; + ring->tail &= ring->size - 1; + ring->space -= len; + intel_ring_advance(dev, ring); +} - trace_i915_ring_wait_end (dev); - return -EBUSY; +u32 intel_ring_get_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + u32 seqno; + seqno = ring->next_seqno; + + /* reserve 0 for non-seqno */ + if (++ring->next_seqno == 0) + ring->next_seqno = 1; + return seqno; } + +struct intel_ring_buffer render_ring = { + .name = "render ring", + .regs = { + .ctl = PRB0_CTL, + .head = PRB0_HEAD, + .tail = PRB0_TAIL, + .start = PRB0_START + }, + .ring_flag = I915_EXEC_RENDER, + .size = 32 * PAGE_SIZE, + .alignment = PAGE_SIZE, + .virtual_start = NULL, + .dev = NULL, + .gem_object = NULL, + .head = 0, + .tail = 0, + .space = 0, + .next_seqno = 1, + .user_irq_refcount = 0, + .irq_gem_seqno = 0, + .waiting_gem_seqno = 0, + .setup_status_page = render_setup_status_page, + .init = init_render_ring, + .get_head = render_ring_get_head, + .get_tail = render_ring_get_tail, + .get_active_head = render_ring_get_active_head, + .advance_ring = render_ring_advance_ring, + .flush = render_ring_flush, + .add_request = render_ring_add_request, + .get_gem_seqno = render_ring_get_gem_seqno, + .user_irq_get = render_ring_get_user_irq, + .user_irq_put = render_ring_put_user_irq, + .dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer, + .status_page = {NULL, 0, NULL}, + .map = {0,} +}; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h new file mode 100644 index 000000000000..d5568d3766de --- /dev/null +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -0,0 +1,124 @@ +#ifndef _INTEL_RINGBUFFER_H_ +#define _INTEL_RINGBUFFER_H_ + +struct intel_hw_status_page { + void *page_addr; + unsigned int gfx_addr; + struct drm_gem_object *obj; +}; + +struct drm_i915_gem_execbuffer2; +struct intel_ring_buffer { + const char *name; + struct ring_regs { + u32 ctl; + u32 head; + u32 tail; + u32 start; + } regs; + unsigned int ring_flag; + unsigned long size; + unsigned int alignment; + void *virtual_start; + struct drm_device *dev; + struct drm_gem_object *gem_object; + + unsigned int head; + unsigned int tail; + unsigned int space; + u32 next_seqno; + struct intel_hw_status_page status_page; + + u32 irq_gem_seqno; /* last seq seem at irq time */ + u32 waiting_gem_seqno; + int user_irq_refcount; + void (*user_irq_get)(struct drm_device *dev, + struct intel_ring_buffer *ring); + void (*user_irq_put)(struct drm_device *dev, + struct intel_ring_buffer *ring); + void (*setup_status_page)(struct drm_device *dev, + struct intel_ring_buffer *ring); + + int (*init)(struct drm_device *dev, + struct intel_ring_buffer *ring); + + unsigned int (*get_head)(struct drm_device *dev, + struct intel_ring_buffer *ring); + unsigned int (*get_tail)(struct drm_device *dev, + struct intel_ring_buffer *ring); + unsigned int (*get_active_head)(struct drm_device *dev, + struct intel_ring_buffer *ring); + void (*advance_ring)(struct drm_device *dev, + struct intel_ring_buffer *ring); + void (*flush)(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains); + u32 (*add_request)(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_file *file_priv, + u32 flush_domains); + u32 (*get_gem_seqno)(struct drm_device *dev, + struct intel_ring_buffer *ring); + int (*dispatch_gem_execbuffer)(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset); + + /** + * List of objects currently involved in rendering from the + * ringbuffer. + * + * Includes buffers having the contents of their GPU caches + * flushed, not necessarily primitives. last_rendering_seqno + * represents when the rendering involved will be completed. + * + * A reference is held on the buffer while on this list. + */ + struct list_head active_list; + + /** + * List of breadcrumbs associated with GPU requests currently + * outstanding. + */ + struct list_head request_list; + + wait_queue_head_t irq_queue; + drm_local_map_t map; +}; + +static inline u32 +intel_read_status_page(struct intel_ring_buffer *ring, + int reg) +{ + u32 *regs = ring->status_page.page_addr; + return regs[reg]; +} + +int intel_init_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring); +void intel_cleanup_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring); +int intel_wait_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring, int n); +int intel_wrap_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring); +void intel_ring_begin(struct drm_device *dev, + struct intel_ring_buffer *ring, int n); +void intel_ring_emit(struct drm_device *dev, + struct intel_ring_buffer *ring, u32 data); +void intel_fill_struct(struct drm_device *dev, + struct intel_ring_buffer *ring, + void *data, + unsigned int len); +void intel_ring_advance(struct drm_device *dev, + struct intel_ring_buffer *ring); + +u32 intel_ring_get_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring); + +extern struct intel_ring_buffer render_ring; +extern struct intel_ring_buffer bsd_ring; + +#endif /* _INTEL_RINGBUFFER_H_ */ diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index b64a8d7cdf6d..e9168704cabe 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -616,7 +616,9 @@ struct drm_i915_gem_execbuffer2 { __u32 num_cliprects; /** This is a struct drm_clip_rect *cliprects */ __u64 cliprects_ptr; - __u64 flags; /* currently unused */ +#define I915_EXEC_RENDER (1<<0) +#define I915_EXEC_BSD (1<<1) + __u64 flags; __u64 rsvd1; __u64 rsvd2; }; -- GitLab From 852835f343146a82a528c3b712b373661d4fa17a Mon Sep 17 00:00:00 2001 From: Zou Nan hai <nanhai.zou@intel.com> Date: Fri, 21 May 2010 09:08:56 +0800 Subject: [PATCH 212/842] drm/i915: convert some gem structures to per-ring V2 The active list and request list move into the ringbuffer structure, so each can track its active objects in the order they are in that ring. The flushing list does not, as it doesn't matter which ring caused data to end up in the render cache. Objects gain a pointer to the ring they are active on (if any). Signed-off-by: Zou Nan hai <nanhai.zou@intel.com> Signed-off-by: Xiang Hai hao <haihao.xiang@intel.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_debugfs.c | 12 +- drivers/gpu/drm/i915/i915_dma.c | 8 +- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 39 +++-- drivers/gpu/drm/i915/i915_gem.c | 210 +++++++++++++++------------ drivers/gpu/drm/i915/i915_irq.c | 45 +++--- drivers/gpu/drm/i915/intel_overlay.c | 44 ++++-- 7 files changed, 207 insertions(+), 153 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4fddf094deb2..c864858d5064 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -77,7 +77,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) case ACTIVE_LIST: seq_printf(m, "Active:\n"); lock = &dev_priv->mm.active_list_lock; - head = &dev_priv->mm.active_list; + head = &dev_priv->render_ring.active_list; break; case INACTIVE_LIST: seq_printf(m, "Inactive:\n"); @@ -129,7 +129,8 @@ static int i915_gem_request_info(struct seq_file *m, void *data) struct drm_i915_gem_request *gem_request; seq_printf(m, "Request:\n"); - list_for_each_entry(gem_request, &dev_priv->mm.request_list, list) { + list_for_each_entry(gem_request, &dev_priv->render_ring.request_list, + list) { seq_printf(m, " %d @ %d\n", gem_request->seqno, (int) (jiffies - gem_request->emitted_jiffies)); @@ -145,7 +146,7 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) if (dev_priv->hw_status_page != NULL) { seq_printf(m, "Current sequence: %d\n", - i915_get_gem_seqno(dev)); + i915_get_gem_seqno(dev, &dev_priv->render_ring)); } else { seq_printf(m, "Current sequence: hws uninitialized\n"); } @@ -197,7 +198,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) atomic_read(&dev_priv->irq_received)); if (dev_priv->hw_status_page != NULL) { seq_printf(m, "Current sequence: %d\n", - i915_get_gem_seqno(dev)); + i915_get_gem_seqno(dev, &dev_priv->render_ring)); } else { seq_printf(m, "Current sequence: hws uninitialized\n"); } @@ -287,7 +288,8 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) spin_lock(&dev_priv->mm.active_list_lock); - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) { + list_for_each_entry(obj_priv, &dev_priv->render_ring.active_list, + list) { obj = &obj_priv->base; if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) { ret = i915_gem_object_get_pages(obj, 0); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2541428b2fe5..f485880300ce 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -82,7 +82,8 @@ static void i915_free_hws(struct drm_device *dev) dev_priv->status_page_dmah = NULL; } - if (dev_priv->status_gfx_addr) { + if (dev_priv->render_ring.status_page.gfx_addr) { + dev_priv->render_ring.status_page.gfx_addr = 0; dev_priv->status_gfx_addr = 0; drm_core_ioremapfree(&dev_priv->hws_map, dev); } @@ -835,9 +836,9 @@ static int i915_set_status_page(struct drm_device *dev, void *data, I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n", - dev_priv->status_gfx_addr); + dev_priv->status_gfx_addr); DRM_DEBUG_DRIVER("load hws at %p\n", - dev_priv->hw_status_page); + dev_priv->hw_status_page); return 0; } @@ -1510,7 +1511,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) resource_size_t base, size; int ret = 0, mmio_bar; uint32_t agp_size, prealloc_size, prealloc_start; - /* i915 has 4 more counters */ dev->counters += 4; dev->types[6] = _DRM_STAT_IRQ; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c57c54f403da..d40f62d36453 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -340,7 +340,7 @@ int i965_reset(struct drm_device *dev, u8 flags) /* * Clear request list */ - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, &dev_priv->render_ring); if (need_display) i915_save_display(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6bb7933d49dc..3f35989ba74c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -505,18 +505,7 @@ typedef struct drm_i915_private { */ struct list_head shrink_list; - /** - * List of objects currently involved in rendering from the - * ringbuffer. - * - * Includes buffers having the contents of their GPU caches - * flushed, not necessarily primitives. last_rendering_seqno - * represents when the rendering involved will be completed. - * - * A reference is held on the buffer while on this list. - */ spinlock_t active_list_lock; - struct list_head active_list; /** * List of objects which are not in the ringbuffer but which @@ -553,12 +542,6 @@ typedef struct drm_i915_private { /** LRU list of objects with fence regs on them. */ struct list_head fence_list; - /** - * List of breadcrumbs associated with GPU requests currently - * outstanding. - */ - struct list_head request_list; - /** * We leave the user IRQ off as much as possible, * but this means that requests will finish and never @@ -683,6 +666,9 @@ struct drm_i915_gem_object { */ uint32_t gtt_offset; + /* Which ring is refering to is this object */ + struct intel_ring_buffer *ring; + /** * Fake offset for use by mmap(2) */ @@ -756,6 +742,9 @@ struct drm_i915_gem_object { * an emission time with seqnos for tracking how far ahead of the GPU we are. */ struct drm_i915_gem_request { + /** On Which ring this request was generated */ + struct intel_ring_buffer *ring; + /** GEM sequence number associated with this request. */ uint32_t seqno; @@ -916,11 +905,13 @@ void i915_gem_object_unpin(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj); void i915_gem_release_mmap(struct drm_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); -uint32_t i915_get_gem_seqno(struct drm_device *dev); +uint32_t i915_get_gem_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring); bool i915_seqno_passed(uint32_t seq1, uint32_t seq2); int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); int i915_gem_object_put_fence_reg(struct drm_gem_object *obj); -void i915_gem_retire_requests(struct drm_device *dev); +void i915_gem_retire_requests(struct drm_device *dev, + struct intel_ring_buffer *ring); void i915_gem_retire_work_handler(struct work_struct *work); void i915_gem_clflush_object(struct drm_gem_object *obj); int i915_gem_object_set_domain(struct drm_gem_object *obj, @@ -931,9 +922,13 @@ void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int i915_gem_do_init(struct drm_device *dev, unsigned long start, unsigned long end); int i915_gem_idle(struct drm_device *dev); -uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, - uint32_t flush_domains); -int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible); +uint32_t i915_add_request(struct drm_device *dev, + struct drm_file *file_priv, + uint32_t flush_domains, + struct intel_ring_buffer *ring); +int i915_do_wait_request(struct drm_device *dev, + uint32_t seqno, int interruptible, + struct intel_ring_buffer *ring); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 58b6e814fae1..af664ba923c5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1482,11 +1482,14 @@ i915_gem_object_put_pages(struct drm_gem_object *obj) } static void -i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno) +i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno, + struct intel_ring_buffer *ring) { struct drm_device *dev = obj->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + BUG_ON(ring == NULL); + obj_priv->ring = ring; /* Add a reference if we're newly entering the active list. */ if (!obj_priv->active) { @@ -1495,8 +1498,7 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno) } /* Move from whatever list we were on to the tail of execution. */ spin_lock(&dev_priv->mm.active_list_lock); - list_move_tail(&obj_priv->list, - &dev_priv->mm.active_list); + list_move_tail(&obj_priv->list, &ring->active_list); spin_unlock(&dev_priv->mm.active_list_lock); obj_priv->last_rendering_seqno = seqno; } @@ -1549,6 +1551,7 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) BUG_ON(!list_empty(&obj_priv->gpu_write_list)); obj_priv->last_rendering_seqno = 0; + obj_priv->ring = NULL; if (obj_priv->active) { obj_priv->active = 0; drm_gem_object_unreference(obj); @@ -1558,7 +1561,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) static void i915_gem_process_flushing_list(struct drm_device *dev, - uint32_t flush_domains, uint32_t seqno) + uint32_t flush_domains, uint32_t seqno, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv, *next; @@ -1569,12 +1573,13 @@ i915_gem_process_flushing_list(struct drm_device *dev, struct drm_gem_object *obj = &obj_priv->base; if ((obj->write_domain & flush_domains) == - obj->write_domain) { + obj->write_domain && + obj_priv->ring->ring_flag == ring->ring_flag) { uint32_t old_write_domain = obj->write_domain; obj->write_domain = 0; list_del_init(&obj_priv->gpu_write_list); - i915_gem_object_move_to_active(obj, seqno); + i915_gem_object_move_to_active(obj, seqno, ring); /* update the fence lru list */ if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { @@ -1593,7 +1598,7 @@ i915_gem_process_flushing_list(struct drm_device *dev, uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, - uint32_t flush_domains) + uint32_t flush_domains, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_file_private *i915_file_priv = NULL; @@ -1608,15 +1613,14 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, if (request == NULL) return 0; - seqno = dev_priv->render_ring.add_request(dev, &dev_priv->render_ring, - file_priv, flush_domains); - - DRM_DEBUG_DRIVER("%d\n", seqno); + seqno = ring->add_request(dev, ring, file_priv, flush_domains); request->seqno = seqno; + request->ring = ring; request->emitted_jiffies = jiffies; - was_empty = list_empty(&dev_priv->mm.request_list); - list_add_tail(&request->list, &dev_priv->mm.request_list); + was_empty = list_empty(&ring->request_list); + list_add_tail(&request->list, &ring->request_list); + if (i915_file_priv) { list_add_tail(&request->client_list, &i915_file_priv->mm.request_list); @@ -1628,7 +1632,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, * domain we're flushing with our flush. */ if (flush_domains != 0) - i915_gem_process_flushing_list(dev, flush_domains, seqno); + i915_gem_process_flushing_list(dev, flush_domains, seqno, ring); if (!dev_priv->mm.suspended) { mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); @@ -1645,18 +1649,16 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, * before signalling the CPU */ static uint32_t -i915_retire_commands(struct drm_device *dev) +i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring) { - uint32_t cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; uint32_t flush_domains = 0; /* The sampler always gets flushed on i965 (sigh) */ if (IS_I965G(dev)) flush_domains |= I915_GEM_DOMAIN_SAMPLER; - BEGIN_LP_RING(2); - OUT_RING(cmd); - OUT_RING(0); /* noop */ - ADVANCE_LP_RING(); + + ring->flush(dev, ring, + I915_GEM_DOMAIN_COMMAND, flush_domains); return flush_domains; } @@ -1676,11 +1678,11 @@ i915_gem_retire_request(struct drm_device *dev, * by the ringbuffer to the flushing/inactive lists as appropriate. */ spin_lock(&dev_priv->mm.active_list_lock); - while (!list_empty(&dev_priv->mm.active_list)) { + while (!list_empty(&request->ring->active_list)) { struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - obj_priv = list_first_entry(&dev_priv->mm.active_list, + obj_priv = list_first_entry(&request->ring->active_list, struct drm_i915_gem_object, list); obj = &obj_priv->base; @@ -1727,37 +1729,33 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) } uint32_t -i915_get_gem_seqno(struct drm_device *dev) +i915_get_gem_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; - - if (HAS_PIPE_CONTROL(dev)) - return ((volatile u32 *)(dev_priv->seqno_page))[0]; - else - return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX); + return ring->get_gem_seqno(dev, ring); } /** * This function clears the request list as sequence numbers are passed. */ void -i915_gem_retire_requests(struct drm_device *dev) +i915_gem_retire_requests(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; uint32_t seqno; - struct intel_ring_buffer *ring = &(dev_priv->render_ring); if (!ring->status_page.page_addr - || list_empty(&dev_priv->mm.request_list)) + || list_empty(&ring->request_list)) return; - seqno = i915_get_gem_seqno(dev); + seqno = i915_get_gem_seqno(dev, ring); - while (!list_empty(&dev_priv->mm.request_list)) { + while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; uint32_t retiring_seqno; - request = list_first_entry(&dev_priv->mm.request_list, + request = list_first_entry(&ring->request_list, struct drm_i915_gem_request, list); retiring_seqno = request->seqno; @@ -1792,27 +1790,28 @@ i915_gem_retire_work_handler(struct work_struct *work) dev = dev_priv->dev; mutex_lock(&dev->struct_mutex); - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, &dev_priv->render_ring); + if (!dev_priv->mm.suspended && - !list_empty(&dev_priv->mm.request_list)) + (!list_empty(&dev_priv->render_ring.request_list))) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); mutex_unlock(&dev->struct_mutex); } int -i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) +i915_do_wait_request(struct drm_device *dev, uint32_t seqno, + int interruptible, struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; u32 ier; int ret = 0; - struct intel_ring_buffer *ring = &dev_priv->render_ring; BUG_ON(seqno == 0); if (atomic_read(&dev_priv->mm.wedged)) return -EIO; - if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) { + if (!i915_seqno_passed(ring->get_gem_seqno(dev, ring), seqno)) { if (HAS_PCH_SPLIT(dev)) ier = I915_READ(DEIER) | I915_READ(GTIER); else @@ -1826,19 +1825,21 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) trace_i915_gem_request_wait_begin(dev, seqno); - dev_priv->mm.waiting_gem_seqno = seqno; + ring->waiting_gem_seqno = seqno; ring->user_irq_get(dev, ring); if (interruptible) - ret = wait_event_interruptible(dev_priv->irq_queue, - i915_seqno_passed(i915_get_gem_seqno(dev), seqno) || - atomic_read(&dev_priv->mm.wedged)); + ret = wait_event_interruptible(ring->irq_queue, + i915_seqno_passed( + ring->get_gem_seqno(dev, ring), seqno) + || atomic_read(&dev_priv->mm.wedged)); else - wait_event(dev_priv->irq_queue, - i915_seqno_passed(i915_get_gem_seqno(dev), seqno) || - atomic_read(&dev_priv->mm.wedged)); + wait_event(ring->irq_queue, + i915_seqno_passed( + ring->get_gem_seqno(dev, ring), seqno) + || atomic_read(&dev_priv->mm.wedged)); ring->user_irq_put(dev, ring); - dev_priv->mm.waiting_gem_seqno = 0; + ring->waiting_gem_seqno = 0; trace_i915_gem_request_wait_end(dev, seqno); } @@ -1847,7 +1848,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) if (ret && ret != -ERESTARTSYS) DRM_ERROR("%s returns %d (awaiting %d at %d)\n", - __func__, ret, seqno, i915_get_gem_seqno(dev)); + __func__, ret, seqno, ring->get_gem_seqno(dev, ring)); /* Directly dispatch request retiring. While we have the work queue * to handle this, the waiter on a request often wants an associated @@ -1855,7 +1856,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) * a separate wait queue to handle that. */ if (ret == 0) - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, ring); return ret; } @@ -1865,12 +1866,12 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible) * request and object lists appropriately for that event. */ static int -i915_wait_request(struct drm_device *dev, uint32_t seqno) +i915_wait_request(struct drm_device *dev, uint32_t seqno, + struct intel_ring_buffer *ring) { - return i915_do_wait_request(dev, seqno, 1); + return i915_do_wait_request(dev, seqno, 1, ring); } - static void i915_gem_flush(struct drm_device *dev, uint32_t invalidate_domains, @@ -1884,6 +1885,19 @@ i915_gem_flush(struct drm_device *dev, flush_domains); } +static void +i915_gem_flush_ring(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains, + struct intel_ring_buffer *ring) +{ + if (flush_domains & I915_GEM_DOMAIN_CPU) + drm_agp_chipset_flush(dev); + ring->flush(dev, ring, + invalidate_domains, + flush_domains); +} + /** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. @@ -1908,7 +1922,8 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj) DRM_INFO("%s: object %p wait for seqno %08x\n", __func__, obj, obj_priv->last_rendering_seqno); #endif - ret = i915_wait_request(dev, obj_priv->last_rendering_seqno); + ret = i915_wait_request(dev, + obj_priv->last_rendering_seqno, obj_priv->ring); if (ret != 0) return ret; } @@ -2025,10 +2040,11 @@ i915_gpu_idle(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; bool lists_empty; uint32_t seqno; + int ret; spin_lock(&dev_priv->mm.active_list_lock); lists_empty = list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->mm.active_list); + list_empty(&dev_priv->render_ring.active_list); spin_unlock(&dev_priv->mm.active_list_lock); if (lists_empty) @@ -2036,11 +2052,13 @@ i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); + seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS, + &dev_priv->render_ring); if (seqno == 0) return -ENOMEM; + ret = i915_wait_request(dev, seqno, &dev_priv->render_ring); - return i915_wait_request(dev, seqno); + return ret; } static int @@ -2053,7 +2071,7 @@ i915_gem_evict_everything(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->mm.active_list)); + list_empty(&dev_priv->render_ring.active_list)); spin_unlock(&dev_priv->mm.active_list_lock); if (lists_empty) @@ -2073,7 +2091,7 @@ i915_gem_evict_everything(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->mm.active_list)); + list_empty(&dev_priv->render_ring.active_list)); spin_unlock(&dev_priv->mm.active_list_lock); BUG_ON(!lists_empty); @@ -2087,8 +2105,9 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) struct drm_gem_object *obj; int ret; + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; for (;;) { - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, render_ring); /* If there's an inactive buffer available now, grab it * and be done. @@ -2112,14 +2131,15 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) * things, wait for the next to finish and hopefully leave us * a buffer to evict. */ - if (!list_empty(&dev_priv->mm.request_list)) { + if (!list_empty(&render_ring->request_list)) { struct drm_i915_gem_request *request; - request = list_first_entry(&dev_priv->mm.request_list, + request = list_first_entry(&render_ring->request_list, struct drm_i915_gem_request, list); - ret = i915_wait_request(dev, request->seqno); + ret = i915_wait_request(dev, + request->seqno, request->ring); if (ret) return ret; @@ -2146,10 +2166,13 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) if (obj != NULL) { uint32_t seqno; - i915_gem_flush(dev, + i915_gem_flush_ring(dev, + obj->write_domain, obj->write_domain, - obj->write_domain); - seqno = i915_add_request(dev, NULL, obj->write_domain); + obj_priv->ring); + seqno = i915_add_request(dev, NULL, + obj->write_domain, + obj_priv->ring); if (seqno == 0) return -ENOMEM; continue; @@ -2685,6 +2708,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; uint32_t old_write_domain; + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) return; @@ -2692,7 +2716,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) /* Queue the GPU write cache flushing we need. */ old_write_domain = obj->write_domain; i915_gem_flush(dev, 0, obj->write_domain); - (void) i915_add_request(dev, NULL, obj->write_domain); + (void) i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring); BUG_ON(obj->write_domain); trace_i915_gem_object_change_domain(obj, @@ -2832,7 +2856,10 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) DRM_INFO("%s: object %p wait for seqno %08x\n", __func__, obj, obj_priv->last_rendering_seqno); #endif - ret = i915_do_wait_request(dev, obj_priv->last_rendering_seqno, 0); + ret = i915_do_wait_request(dev, + obj_priv->last_rendering_seqno, + 0, + obj_priv->ring); if (ret != 0) return ret; } @@ -3451,7 +3478,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv) if (time_after_eq(request->emitted_jiffies, recent_enough)) break; - ret = i915_wait_request(dev, request->seqno); + ret = i915_wait_request(dev, request->seqno, request->ring); if (ret != 0) break; } @@ -3608,6 +3635,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, uint32_t seqno, flush_domains, reloc_index; int pin_tries, flips; + struct intel_ring_buffer *ring = NULL; + #if WATCH_EXEC DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", (int) args->buffers_ptr, args->buffer_count, args->batch_len); @@ -3665,6 +3694,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } + ring = &dev_priv->render_ring; + /* Look up object handles */ flips = 0; for (i = 0; i < args->buffer_count; i++) { @@ -3798,9 +3829,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_flush(dev, dev->invalidate_domains, dev->flush_domains); - if (dev->flush_domains & I915_GEM_GPU_DOMAINS) + if (dev->flush_domains & I915_GEM_GPU_DOMAINS) { (void)i915_add_request(dev, file_priv, - dev->flush_domains); + dev->flush_domains, + &dev_priv->render_ring); + + } } for (i = 0; i < args->buffer_count; i++) { @@ -3837,11 +3871,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, #endif /* Exec the batchbuffer */ - ret = dev_priv->render_ring.dispatch_gem_execbuffer(dev, - &dev_priv->render_ring, - args, - cliprects, - exec_offset); + ret = ring->dispatch_gem_execbuffer(dev, ring, args, + cliprects, exec_offset); if (ret) { DRM_ERROR("dispatch failed %d\n", ret); goto err; @@ -3851,7 +3882,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * Ensure that the commands in the batch buffer are * finished before the interrupt fires */ - flush_domains = i915_retire_commands(dev); + flush_domains = i915_retire_commands(dev, ring); i915_verify_inactive(dev, __FILE__, __LINE__); @@ -3862,12 +3893,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * *some* interrupts representing completion of buffers that we can * wait on when trying to clear up gtt space). */ - seqno = i915_add_request(dev, file_priv, flush_domains); + seqno = i915_add_request(dev, file_priv, flush_domains, ring); BUG_ON(seqno == 0); for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; + obj_priv = to_intel_bo(obj); - i915_gem_object_move_to_active(obj, seqno); + i915_gem_object_move_to_active(obj, seqno, ring); #if WATCH_LRU DRM_INFO("%s: move to exec list %p\n", __func__, obj); #endif @@ -3979,7 +4011,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, exec2.DR4 = args->DR4; exec2.num_cliprects = args->num_cliprects; exec2.cliprects_ptr = args->cliprects_ptr; - exec2.flags = 0; + exec2.flags = I915_EXEC_RENDER; ret = i915_gem_do_execbuffer(dev, data, file_priv, &exec2, exec2_list); if (!ret) { @@ -4218,6 +4250,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_busy *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; + drm_i915_private_t *dev_priv = dev->dev_private; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) { @@ -4232,7 +4265,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * actually unmasked, and our working set ends up being larger than * required. */ - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, &dev_priv->render_ring); obj_priv = to_intel_bo(obj); /* Don't count being on the flushing list against the object being @@ -4555,12 +4588,12 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, } spin_lock(&dev_priv->mm.active_list_lock); - BUG_ON(!list_empty(&dev_priv->mm.active_list)); + BUG_ON(!list_empty(&dev_priv->render_ring.active_list)); spin_unlock(&dev_priv->mm.active_list_lock); BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); - BUG_ON(!list_empty(&dev_priv->mm.request_list)); + BUG_ON(!list_empty(&dev_priv->render_ring.request_list)); mutex_unlock(&dev->struct_mutex); drm_irq_install(dev); @@ -4599,18 +4632,16 @@ i915_gem_load(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; spin_lock_init(&dev_priv->mm.active_list_lock); - INIT_LIST_HEAD(&dev_priv->mm.active_list); INIT_LIST_HEAD(&dev_priv->mm.flushing_list); INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); - INIT_LIST_HEAD(&dev_priv->mm.request_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list); + INIT_LIST_HEAD(&dev_priv->render_ring.active_list); + INIT_LIST_HEAD(&dev_priv->render_ring.request_list); for (i = 0; i < 16; i++) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, i915_gem_retire_work_handler); - dev_priv->mm.next_gem_seqno = 1; - spin_lock(&shrink_list_lock); list_add(&dev_priv->mm.shrink_list, &shrink_list); spin_unlock(&shrink_list_lock); @@ -4842,7 +4873,7 @@ i915_gpu_is_active(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->mm.active_list); + list_empty(&dev_priv->render_ring.active_list); spin_unlock(&dev_priv->mm.active_list_lock); return !lists_empty; @@ -4887,8 +4918,7 @@ rescan: continue; spin_unlock(&shrink_list_lock); - - i915_gem_retire_requests(dev); + i915_gem_retire_requests(dev, &dev_priv->render_ring); list_for_each_entry_safe(obj_priv, next_obj, &dev_priv->mm.inactive_list, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e07c643c8365..8a667f1db75a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -331,6 +331,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) int ret = IRQ_NONE; u32 de_iir, gt_iir, de_ier, pch_iir; struct drm_i915_master_private *master_priv; + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; /* disable master interrupt before clearing iir */ de_ier = I915_READ(DEIER); @@ -354,10 +355,10 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) } if (gt_iir & GT_PIPE_NOTIFY) { - u32 seqno = i915_get_gem_seqno(dev); - dev_priv->mm.irq_gem_seqno = seqno; + u32 seqno = render_ring->get_gem_seqno(dev, render_ring); + render_ring->irq_gem_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); - DRM_WAKEUP(&dev_priv->irq_queue); + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } @@ -588,7 +589,7 @@ static void i915_capture_error_state(struct drm_device *dev) return; } - error->seqno = i915_get_gem_seqno(dev); + error->seqno = i915_get_gem_seqno(dev, &dev_priv->render_ring); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); error->pipeastat = I915_READ(PIPEASTAT); @@ -616,7 +617,9 @@ static void i915_capture_error_state(struct drm_device *dev) batchbuffer[0] = NULL; batchbuffer[1] = NULL; count = 0; - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) { + list_for_each_entry(obj_priv, + &dev_priv->render_ring.active_list, list) { + struct drm_gem_object *obj = &obj_priv->base; if (batchbuffer[0] == NULL && @@ -653,7 +656,8 @@ static void i915_capture_error_state(struct drm_device *dev) if (error->active_bo) { int i = 0; - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) { + list_for_each_entry(obj_priv, + &dev_priv->render_ring.active_list, list) { struct drm_gem_object *obj = &obj_priv->base; error->active_bo[i].size = obj->size; @@ -831,7 +835,7 @@ static void i915_handle_error(struct drm_device *dev, bool wedged) /* * Wakeup waiting processes so they don't hang */ - DRM_WAKEUP(&dev_priv->irq_queue); + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); } queue_work(dev_priv->wq, &dev_priv->error_work); @@ -850,6 +854,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) unsigned long irqflags; int irq_received; int ret = IRQ_NONE; + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; atomic_inc(&dev_priv->irq_received); @@ -930,10 +935,11 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (iir & I915_USER_INTERRUPT) { - u32 seqno = i915_get_gem_seqno(dev); - dev_priv->mm.irq_gem_seqno = seqno; + u32 seqno = + render_ring->get_gem_seqno(dev, render_ring); + render_ring->irq_gem_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); - DRM_WAKEUP(&dev_priv->irq_queue); + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } @@ -1038,7 +1044,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; render_ring->user_irq_get(dev, render_ring); - DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, + DRM_WAIT_ON(ret, dev_priv->render_ring.irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); render_ring->user_irq_put(dev, render_ring); @@ -1205,9 +1211,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data, return -EINVAL; } -struct drm_i915_gem_request *i915_get_tail_request(struct drm_device *dev) { +struct drm_i915_gem_request * +i915_get_tail_request(struct drm_device *dev) +{ drm_i915_private_t *dev_priv = dev->dev_private; - return list_entry(dev_priv->mm.request_list.prev, struct drm_i915_gem_request, list); + return list_entry(dev_priv->render_ring.request_list.prev, + struct drm_i915_gem_request, list); } /** @@ -1232,8 +1241,10 @@ void i915_hangcheck_elapsed(unsigned long data) acthd = I915_READ(ACTHD_I965); /* If all work is done then ACTHD clearly hasn't advanced. */ - if (list_empty(&dev_priv->mm.request_list) || - i915_seqno_passed(i915_get_gem_seqno(dev), i915_get_tail_request(dev)->seqno)) { + if (list_empty(&dev_priv->render_ring.request_list) || + i915_seqno_passed(i915_get_gem_seqno(dev, + &dev_priv->render_ring), + i915_get_tail_request(dev)->seqno)) { dev_priv->hangcheck_count = 0; return; } @@ -1300,7 +1311,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) (void) I915_READ(DEIER); /* user interrupt should be enabled, but masked initial */ - dev_priv->gt_irq_mask_reg = 0xffffffff; + dev_priv->gt_irq_mask_reg = ~render_mask; dev_priv->gt_irq_enable_reg = render_mask; I915_WRITE(GTIIR, I915_READ(GTIIR)); @@ -1363,7 +1374,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev) u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; u32 error_mask; - DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue); dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 93da83782e5e..d7ad5139d17c 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -212,6 +212,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; int ret; + drm_i915_private_t *dev_priv = dev->dev_private; BUG_ON(overlay->active); @@ -225,11 +226,13 @@ static int intel_overlay_on(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); + ret = i915_do_wait_request(dev, + overlay->last_flip_req, 1, &dev_priv->render_ring); if (ret != 0) return ret; @@ -262,7 +265,8 @@ static void intel_overlay_continue(struct intel_overlay *overlay, OUT_RING(flip_addr); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); } static int intel_overlay_wait_flip(struct intel_overlay *overlay) @@ -273,7 +277,8 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay) u32 tmp; if (overlay->last_flip_req != 0) { - ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); + ret = i915_do_wait_request(dev, overlay->last_flip_req, + 1, &dev_priv->render_ring); if (ret == 0) { overlay->last_flip_req = 0; @@ -292,11 +297,13 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); + ret = i915_do_wait_request(dev, overlay->last_flip_req, + 1, &dev_priv->render_ring); if (ret != 0) return ret; @@ -310,6 +317,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) { u32 flip_addr = overlay->flip_addr; struct drm_device *dev = overlay->dev; + drm_i915_private_t *dev_priv = dev->dev_private; int ret; BUG_ON(!overlay->active); @@ -330,11 +338,13 @@ static int intel_overlay_off(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); + ret = i915_do_wait_request(dev, overlay->last_flip_req, + 1, &dev_priv->render_ring); if (ret != 0) return ret; @@ -348,11 +358,13 @@ static int intel_overlay_off(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; - ret = i915_do_wait_request(dev, overlay->last_flip_req, 1); + ret = i915_do_wait_request(dev, overlay->last_flip_req, + 1, &dev_priv->render_ring); if (ret != 0) return ret; @@ -385,6 +397,7 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, { struct drm_device *dev = overlay->dev; struct drm_gem_object *obj; + drm_i915_private_t *dev_priv = dev->dev_private; u32 flip_addr; int ret; @@ -392,12 +405,14 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, return -EIO; if (overlay->last_flip_req == 0) { - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = + i915_add_request(dev, NULL, 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; } - ret = i915_do_wait_request(dev, overlay->last_flip_req, interruptible); + ret = i915_do_wait_request(dev, overlay->last_flip_req, + interruptible, &dev_priv->render_ring); if (ret != 0) return ret; @@ -421,12 +436,13 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - overlay->last_flip_req = i915_add_request(dev, NULL, 0); + overlay->last_flip_req = i915_add_request(dev, NULL, + 0, &dev_priv->render_ring); if (overlay->last_flip_req == 0) return -ENOMEM; ret = i915_do_wait_request(dev, overlay->last_flip_req, - interruptible); + interruptible, &dev_priv->render_ring); if (ret != 0) return ret; -- GitLab From d1b851fc0d105caa6b6e3e7c92d2987dfb52cbe0 Mon Sep 17 00:00:00 2001 From: Zou Nan hai <nanhai.zou@intel.com> Date: Fri, 21 May 2010 09:08:57 +0800 Subject: [PATCH 213/842] drm/i915: implement BSD ring buffer V2 The BSD (bit stream decoder) ring is used for accessing the BSD engine which decodes video bitstream for H.264 and VC1 on G45+. It is asynchronous with the render ring and has access to separate parts of the GPU from it, though the render cache is coherent between the two. Signed-off-by: Zou Nan hai <nanhai.zou@intel.com> Signed-off-by: Xiang Hai hao <haihao.xiang@intel.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_dma.c | 2 + drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_gem.c | 107 +++++++++++++++-- drivers/gpu/drm/i915/i915_irq.c | 13 +- drivers/gpu/drm/i915/i915_reg.h | 14 +++ drivers/gpu/drm/i915/intel_ringbuffer.c | 153 ++++++++++++++++++++++++ 6 files changed, 276 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f485880300ce..1dbed700800e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -130,6 +130,8 @@ static int i915_dma_cleanup(struct drm_device * dev) drm_irq_uninstall(dev); intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring); /* Clear the HWS virtual address at teardown */ if (I915_NEED_GFX_HWS(dev)) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3f35989ba74c..6bc0fc080f2b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -235,6 +235,7 @@ typedef struct drm_i915_private { struct pci_dev *bridge_dev; struct intel_ring_buffer render_ring; + struct intel_ring_buffer bsd_ring; drm_dma_handle_t *status_page_dmah; void *hw_status_page; @@ -1121,6 +1122,7 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); (dev)->pci_device == 0x2A42 || \ (dev)->pci_device == 0x2E42) +#define HAS_BSD(dev) (IS_IRONLAKE(dev) || IS_G4X(dev)) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index af664ba923c5..c51495f15718 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1730,7 +1730,7 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) uint32_t i915_get_gem_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring) { return ring->get_gem_seqno(dev, ring); } @@ -1792,8 +1792,13 @@ i915_gem_retire_work_handler(struct work_struct *work) mutex_lock(&dev->struct_mutex); i915_gem_retire_requests(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + i915_gem_retire_requests(dev, &dev_priv->bsd_ring); + if (!dev_priv->mm.suspended && - (!list_empty(&dev_priv->render_ring.request_list))) + (!list_empty(&dev_priv->render_ring.request_list) || + (HAS_BSD(dev) && + !list_empty(&dev_priv->bsd_ring.request_list)))) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); mutex_unlock(&dev->struct_mutex); } @@ -1883,6 +1888,11 @@ i915_gem_flush(struct drm_device *dev, dev_priv->render_ring.flush(dev, &dev_priv->render_ring, invalidate_domains, flush_domains); + + if (HAS_BSD(dev)) + dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring, + invalidate_domains, + flush_domains); } static void @@ -2039,12 +2049,14 @@ i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; bool lists_empty; - uint32_t seqno; + uint32_t seqno1, seqno2; int ret; spin_lock(&dev_priv->mm.active_list_lock); - lists_empty = list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list); + lists_empty = (list_empty(&dev_priv->mm.flushing_list) && + list_empty(&dev_priv->render_ring.active_list) && + (!HAS_BSD(dev) || + list_empty(&dev_priv->bsd_ring.active_list))); spin_unlock(&dev_priv->mm.active_list_lock); if (lists_empty) @@ -2052,11 +2064,23 @@ i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS, + seqno1 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS, &dev_priv->render_ring); - if (seqno == 0) + if (seqno1 == 0) return -ENOMEM; - ret = i915_wait_request(dev, seqno, &dev_priv->render_ring); + ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring); + + if (HAS_BSD(dev)) { + seqno2 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS, + &dev_priv->bsd_ring); + if (seqno2 == 0) + return -ENOMEM; + + ret = i915_wait_request(dev, seqno2, &dev_priv->bsd_ring); + if (ret) + return ret; + } + return ret; } @@ -2071,7 +2095,9 @@ i915_gem_evict_everything(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list)); + list_empty(&dev_priv->render_ring.active_list) && + (!HAS_BSD(dev) + || list_empty(&dev_priv->bsd_ring.active_list))); spin_unlock(&dev_priv->mm.active_list_lock); if (lists_empty) @@ -2091,7 +2117,9 @@ i915_gem_evict_everything(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = (list_empty(&dev_priv->mm.inactive_list) && list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list)); + list_empty(&dev_priv->render_ring.active_list) && + (!HAS_BSD(dev) + || list_empty(&dev_priv->bsd_ring.active_list))); spin_unlock(&dev_priv->mm.active_list_lock); BUG_ON(!lists_empty); @@ -2106,9 +2134,13 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) int ret; struct intel_ring_buffer *render_ring = &dev_priv->render_ring; + struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; for (;;) { i915_gem_retire_requests(dev, render_ring); + if (HAS_BSD(dev)) + i915_gem_retire_requests(dev, bsd_ring); + /* If there's an inactive buffer available now, grab it * and be done. */ @@ -2146,6 +2178,21 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) continue; } + if (HAS_BSD(dev) && !list_empty(&bsd_ring->request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&bsd_ring->request_list, + struct drm_i915_gem_request, + list); + + ret = i915_wait_request(dev, + request->seqno, request->ring); + if (ret) + return ret; + + continue; + } + /* If we didn't have anything on the request list but there * are buffers awaiting a flush, emit one and try again. * When we wait on it, those buffers waiting for that flush @@ -3641,6 +3688,16 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", (int) args->buffers_ptr, args->buffer_count, args->batch_len); #endif + if (args->flags & I915_EXEC_BSD) { + if (!HAS_BSD(dev)) { + DRM_ERROR("execbuf with wrong flag\n"); + return -EINVAL; + } + ring = &dev_priv->bsd_ring; + } else { + ring = &dev_priv->render_ring; + } + if (args->buffer_count < 1) { DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); @@ -3694,8 +3751,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } - ring = &dev_priv->render_ring; - /* Look up object handles */ flips = 0; for (i = 0; i < args->buffer_count; i++) { @@ -3834,6 +3889,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, dev->flush_domains, &dev_priv->render_ring); + if (HAS_BSD(dev)) + (void)i915_add_request(dev, file_priv, + dev->flush_domains, + &dev_priv->bsd_ring); } } @@ -4267,6 +4326,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, */ i915_gem_retire_requests(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + i915_gem_retire_requests(dev, &dev_priv->bsd_ring); + obj_priv = to_intel_bo(obj); /* Don't count being on the flushing list against the object being * done. Otherwise, a buffer left on the flushing list but not getting @@ -4433,7 +4495,9 @@ i915_gem_idle(struct drm_device *dev) mutex_lock(&dev->struct_mutex); if (dev_priv->mm.suspended || - dev_priv->render_ring.gem_object == NULL) { + (dev_priv->render_ring.gem_object == NULL) || + (HAS_BSD(dev) && + dev_priv->bsd_ring.gem_object == NULL)) { mutex_unlock(&dev->struct_mutex); return 0; } @@ -4550,6 +4614,10 @@ i915_gem_init_ringbuffer(struct drm_device *dev) return ret; } ret = intel_init_ring_buffer(dev, &dev_priv->render_ring); + if (!ret && HAS_BSD(dev)) { + dev_priv->bsd_ring = bsd_ring; + ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring); + } return ret; } @@ -4559,6 +4627,8 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring); if (HAS_PIPE_CONTROL(dev)) i915_gem_cleanup_pipe_control(dev); } @@ -4589,11 +4659,13 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, spin_lock(&dev_priv->mm.active_list_lock); BUG_ON(!list_empty(&dev_priv->render_ring.active_list)); + BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.active_list)); spin_unlock(&dev_priv->mm.active_list_lock); BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); BUG_ON(!list_empty(&dev_priv->render_ring.request_list)); + BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.request_list)); mutex_unlock(&dev->struct_mutex); drm_irq_install(dev); @@ -4638,6 +4710,10 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->mm.fence_list); INIT_LIST_HEAD(&dev_priv->render_ring.active_list); INIT_LIST_HEAD(&dev_priv->render_ring.request_list); + if (HAS_BSD(dev)) { + INIT_LIST_HEAD(&dev_priv->bsd_ring.active_list); + INIT_LIST_HEAD(&dev_priv->bsd_ring.request_list); + } for (i = 0; i < 16; i++) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, @@ -4874,6 +4950,8 @@ i915_gpu_is_active(struct drm_device *dev) spin_lock(&dev_priv->mm.active_list_lock); lists_empty = list_empty(&dev_priv->mm.flushing_list) && list_empty(&dev_priv->render_ring.active_list); + if (HAS_BSD(dev)) + lists_empty &= list_empty(&dev_priv->bsd_ring.active_list); spin_unlock(&dev_priv->mm.active_list_lock); return !lists_empty; @@ -4920,6 +4998,9 @@ rescan: spin_unlock(&shrink_list_lock); i915_gem_retire_requests(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + i915_gem_retire_requests(dev, &dev_priv->bsd_ring); + list_for_each_entry_safe(obj_priv, next_obj, &dev_priv->mm.inactive_list, list) { diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8a667f1db75a..0a3a5806a12e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -53,7 +53,7 @@ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) /** Interrupts that we mask and unmask at runtime. */ -#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) +#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT | I915_BSD_USER_INTERRUPT) #define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ PIPE_VBLANK_INTERRUPT_STATUS) @@ -362,6 +362,9 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) dev_priv->hangcheck_count = 0; mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } + if (gt_iir & GT_BSD_USER_INTERRUPT) + DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + if (de_iir & DE_GSE) ironlake_opregion_gse_intr(dev); @@ -944,6 +947,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); } + if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT)) + DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) intel_prepare_page_flip(dev, 0); @@ -1297,7 +1303,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; - u32 render_mask = GT_PIPE_NOTIFY; + u32 render_mask = GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT; u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; @@ -1376,6 +1382,9 @@ int i915_driver_irq_postinstall(struct drm_device *dev) DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue); + if (HAS_BSD(dev)) + DRM_INIT_WAITQUEUE(&dev_priv->bsd_ring.irq_queue); + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; if (HAS_PCH_SPLIT(dev)) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f3e39cc46f0d..784cf3c914e9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -334,6 +334,7 @@ #define I915_DEBUG_INTERRUPT (1<<2) #define I915_USER_INTERRUPT (1<<1) #define I915_ASLE_INTERRUPT (1<<0) +#define I915_BSD_USER_INTERRUPT (1<<25) #define EIR 0x020b0 #define EMR 0x020b4 #define ESR 0x020b8 @@ -368,6 +369,17 @@ #define BB_ADDR 0x02140 /* 8 bytes */ #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ +/* + * BSD (bit stream decoder instruction and interrupt control register defines + * (G4X and Ironlake only) + */ + +#define BSD_RING_TAIL 0x04030 +#define BSD_RING_HEAD 0x04034 +#define BSD_RING_START 0x04038 +#define BSD_RING_CTL 0x0403c +#define BSD_RING_ACTHD 0x04074 +#define BSD_HWS_PGA 0x04080 /* * Framebuffer compression (915+ only) @@ -2355,6 +2367,8 @@ #define GT_PIPE_NOTIFY (1 << 4) #define GT_SYNC_STATUS (1 << 2) #define GT_USER_INTERRUPT (1 << 0) +#define GT_BSD_USER_INTERRUPT (1 << 5) + #define GTISR 0x44010 #define GTIMR 0x44014 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 5715c4d8cce9..f6b84fe8099a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -340,6 +340,119 @@ static void render_setup_status_page(struct drm_device *dev, } +void +bsd_ring_flush(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) +{ + intel_ring_begin(dev, ring, 8); + intel_ring_emit(dev, ring, MI_FLUSH); + intel_ring_emit(dev, ring, MI_NOOP); + intel_ring_advance(dev, ring); +} + +static inline unsigned int bsd_ring_get_head(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(BSD_RING_HEAD) & HEAD_ADDR; +} + +static inline unsigned int bsd_ring_get_tail(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(BSD_RING_TAIL) & TAIL_ADDR; +} + +static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + return I915_READ(BSD_RING_ACTHD); +} + +static inline void bsd_ring_advance_ring(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + I915_WRITE(BSD_RING_TAIL, ring->tail); +} + +static int init_bsd_ring(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + return init_ring_common(dev, ring); +} + +static u32 +bsd_ring_add_request(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_file *file_priv, + u32 flush_domains) +{ + u32 seqno; + seqno = intel_ring_get_seqno(dev, ring); + intel_ring_begin(dev, ring, 4); + intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(dev, ring, + I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(dev, ring, seqno); + intel_ring_emit(dev, ring, MI_USER_INTERRUPT); + intel_ring_advance(dev, ring); + + DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno); + + return seqno; +} + +static void bsd_setup_status_page(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + I915_WRITE(BSD_HWS_PGA, ring->status_page.gfx_addr); + I915_READ(BSD_HWS_PGA); +} + +static void +bsd_ring_get_user_irq(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + /* do nothing */ +} +static void +bsd_ring_put_user_irq(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + /* do nothing */ +} + +static u32 +bsd_ring_get_gem_seqno(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + return intel_read_status_page(ring, I915_GEM_HWS_INDEX); +} + +static int +bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev, + struct intel_ring_buffer *ring, + struct drm_i915_gem_execbuffer2 *exec, + struct drm_clip_rect *cliprects, + uint64_t exec_offset) +{ + uint32_t exec_start; + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; + intel_ring_begin(dev, ring, 2); + intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START | + (2 << 6) | MI_BATCH_NON_SECURE_I965); + intel_ring_emit(dev, ring, exec_start); + intel_ring_advance(dev, ring); + return 0; +} + + static int render_ring_dispatch_gem_execbuffer(struct drm_device *dev, struct intel_ring_buffer *ring, @@ -588,6 +701,7 @@ int intel_wait_ring_buffer(struct drm_device *dev, if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; } + yield(); } while (!time_after(jiffies, end)); trace_i915_ring_wait_end (dev); @@ -682,3 +796,42 @@ struct intel_ring_buffer render_ring = { .status_page = {NULL, 0, NULL}, .map = {0,} }; + +/* ring buffer for bit-stream decoder */ + +struct intel_ring_buffer bsd_ring = { + .name = "bsd ring", + .regs = { + .ctl = BSD_RING_CTL, + .head = BSD_RING_HEAD, + .tail = BSD_RING_TAIL, + .start = BSD_RING_START + }, + .ring_flag = I915_EXEC_BSD, + .size = 32 * PAGE_SIZE, + .alignment = PAGE_SIZE, + .virtual_start = NULL, + .dev = NULL, + .gem_object = NULL, + .head = 0, + .tail = 0, + .space = 0, + .next_seqno = 1, + .user_irq_refcount = 0, + .irq_gem_seqno = 0, + .waiting_gem_seqno = 0, + .setup_status_page = bsd_setup_status_page, + .init = init_bsd_ring, + .get_head = bsd_ring_get_head, + .get_tail = bsd_ring_get_tail, + .get_active_head = bsd_ring_get_active_head, + .advance_ring = bsd_ring_advance_ring, + .flush = bsd_ring_flush, + .add_request = bsd_ring_add_request, + .get_gem_seqno = bsd_ring_get_gem_seqno, + .user_irq_get = bsd_ring_get_user_irq, + .user_irq_put = bsd_ring_put_user_irq, + .dispatch_gem_execbuffer = bsd_ring_dispatch_gem_execbuffer, + .status_page = {NULL, 0, NULL}, + .map = {0,} +}; -- GitLab From 9517a92f48b08bb02cfb616825850b82b28461cc Mon Sep 17 00:00:00 2001 From: Jesse Barnes <jbarnes@virtuousgeek.org> Date: Fri, 21 May 2010 09:40:45 -0700 Subject: [PATCH 214/842] drm/i915: add timeout to FBC disable waits FBC disable on 965 can take long enough to trigger latency checks in the kernel so be sure to timeout after a reasonable period. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=15015. Tested-by: James Ettle <theholyettlz@googlemail.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_display.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b867f3c78408..36afe9409964 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1029,19 +1029,28 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) void i8xx_disable_fbc(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long timeout = jiffies + msecs_to_jiffies(1); u32 fbc_ctl; if (!I915_HAS_FBC(dev)) return; + if (!(I915_READ(FBC_CONTROL) & FBC_CTL_EN)) + return; /* Already off, just return */ + /* Disable compression */ fbc_ctl = I915_READ(FBC_CONTROL); fbc_ctl &= ~FBC_CTL_EN; I915_WRITE(FBC_CONTROL, fbc_ctl); /* Wait for compressing bit to clear */ - while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) - ; /* nothing */ + while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) { + if (time_after(jiffies, timeout)) { + DRM_DEBUG_DRIVER("FBC idle timed out\n"); + break; + } + ; /* do nothing */ + } intel_wait_for_vblank(dev); -- GitLab From f41275e893191eeb7a88e431d594e167adbd5234 Mon Sep 17 00:00:00 2001 From: Li Zefan <lizf@cn.fujitsu.com> Date: Mon, 24 May 2010 16:25:44 +0800 Subject: [PATCH 215/842] drm/i915: Convert more trace events to DEFINE_EVENT Convert i915_gem_object_clflush to DEFINE_EVENT, and save ~0.5K: text data bss dec hex filename 13204 2732 12 15948 3e4c i915_trace_points.o.orig 12668 2732 12 15412 3c34 i915_trace_points.o No change in functionality. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_trace.h | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 9e4c45f68d6e..fab21760dd57 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -53,23 +53,6 @@ TRACE_EVENT(i915_gem_object_bind, __entry->obj, __entry->gtt_offset) ); -TRACE_EVENT(i915_gem_object_clflush, - - TP_PROTO(struct drm_gem_object *obj), - - TP_ARGS(obj), - - TP_STRUCT__entry( - __field(struct drm_gem_object *, obj) - ), - - TP_fast_assign( - __entry->obj = obj; - ), - - TP_printk("obj=%p", __entry->obj) -); - TRACE_EVENT(i915_gem_object_change_domain, TP_PROTO(struct drm_gem_object *obj, uint32_t old_read_domains, uint32_t old_write_domain), @@ -132,6 +115,13 @@ DECLARE_EVENT_CLASS(i915_gem_object, TP_printk("obj=%p", __entry->obj) ); +DEFINE_EVENT(i915_gem_object, i915_gem_object_clflush, + + TP_PROTO(struct drm_gem_object *obj), + + TP_ARGS(obj) +); + DEFINE_EVENT(i915_gem_object, i915_gem_object_unbind, TP_PROTO(struct drm_gem_object *obj), -- GitLab From f953c9353f5fe6e98fa7f32f51060a74d845b5f8 Mon Sep 17 00:00:00 2001 From: Daniel J Blueman <daniel.blueman@gmail.com> Date: Mon, 17 May 2010 14:23:52 +0100 Subject: [PATCH 216/842] i915: fix lock imbalance on error path... While investigating Intel i5 Arrandale GPU lockups with -rc4, I noticed a lock imbalance. Signed-off-by: Daniel J Blueman <daniel.blueman@gmail.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index d40f62d36453..c072b212979c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -370,6 +370,7 @@ int i965_reset(struct drm_device *dev, u8 flags) } } else { DRM_ERROR("Error occurred. Don't know how to reset this chip.\n"); + mutex_unlock(&dev->struct_mutex); return -ENODEV; } -- GitLab From 734b4157b367d66405f7dab80085d17c9c8dd3b5 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa <khc@pm.waw.pl> Date: Tue, 25 May 2010 18:41:46 +0200 Subject: [PATCH 217/842] drm/i915: Add support for interlaced display. This doesn't change the clock limits (minimums), i.e. it won't make it output 720x576 PAL nor 720x480 NTSC, but it will work with modes like 1080i etc. (including GLX and textured Xvideo, not sure about the overlay). Tested on i915 + analog VGA, it would be worth checking if newer chips (and which ones) still support interlaced mode. Signed-off-by: Krzysztof Halasa <khc@pm.waw.pl> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index e16ac5a28c3c..d5c130202396 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -569,7 +569,7 @@ void intel_crt_init(struct drm_device *dev) (1 << INTEL_ANALOG_CLONE_BIT) | (1 << INTEL_SDVO_LVDS_CLONE_BIT); intel_encoder->crtc_mask = (1 << 0) | (1 << 1); - connector->interlace_allowed = 0; + connector->interlace_allowed = 1; connector->doublescan_allowed = 0; drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 36afe9409964..4c7c151114f7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2354,6 +2354,8 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, if (mode->clock * 3 > 27000 * 4) return MODE_CLOCK_HIGH; } + + drm_mode_set_crtcinfo(adjusted_mode, 0); return true; } @@ -3781,6 +3783,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } } + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; + /* the chip adds 2 halflines automatically */ + adjusted_mode->crtc_vdisplay -= 1; + adjusted_mode->crtc_vtotal -= 1; + adjusted_mode->crtc_vblank_start -= 1; + adjusted_mode->crtc_vblank_end -= 1; + adjusted_mode->crtc_vsync_end -= 1; + adjusted_mode->crtc_vsync_start -= 1; + } else + pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */ + I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16)); I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | -- GitLab From 7a772c492fcfffae812ffca78a628e76fa57fe58 Mon Sep 17 00:00:00 2001 From: Adam Jackson <ajax@redhat.com> Date: Mon, 24 May 2010 16:46:29 -0400 Subject: [PATCH 218/842] drm/i915/gen4: Extra CRT hotplug paranoia Disable the CRT plug interrupt while doing the force cycle, explicitly clear any CRT interrupt we may have generated, and restore when done. Should mitigate interrupt storms from hotplug detection. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_reg.h | 1 - drivers/gpu/drm/i915/intel_crt.c | 21 ++++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 784cf3c914e9..7a726840efa7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1067,7 +1067,6 @@ #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) #define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */ -#define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f #define PORT_HOTPLUG_STAT 0x61114 #define HDMIB_HOTPLUG_INT_STATUS (1 << 29) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index d5c130202396..22ff38455731 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -217,7 +217,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 hotplug_en; + u32 hotplug_en, orig, stat; + bool ret = false; int i, tries = 0; if (HAS_PCH_SPLIT(dev)) @@ -232,8 +233,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) tries = 2; else tries = 1; - hotplug_en = I915_READ(PORT_HOTPLUG_EN); - hotplug_en &= CRT_FORCE_HOTPLUG_MASK; + hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN); + hotplug_en &= CRT_HOTPLUG_MASK; hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; if (IS_G4X(dev)) @@ -255,11 +256,17 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) } while (time_after(timeout, jiffies)); } - if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) != - CRT_HOTPLUG_MONITOR_NONE) - return true; + stat = I915_READ(PORT_HOTPLUG_STAT); + if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE) + ret = true; + + /* clear the interrupt we just generated, if any */ + I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS); - return false; + /* and put the bits back */ + I915_WRITE(PORT_HOTPLUG_EN, orig); + + return ret; } static bool intel_crt_detect_ddc(struct drm_encoder *encoder) -- GitLab From 7648fa99eb77a2e1a90b7beaa420e07d819b9c11 Mon Sep 17 00:00:00 2001 From: Jesse Barnes <jbarnes@virtuousgeek.org> Date: Thu, 20 May 2010 14:28:11 -0700 Subject: [PATCH 219/842] drm/i915: add power monitoring support Add power monitoring support to the i915 driver for use by the IPS driver. Export the available power info to the IPS driver through a few new inter-driver hooks. When used together, the IPS driver and this patch can significantly increase graphics performance on Ironlake class chips. Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> [anholt: Fixed 32-bit compile. stupid obfuscating div_u64()] Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_debugfs.c | 56 ++- drivers/gpu/drm/i915/i915_dma.c | 533 ++++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_drv.h | 20 +- drivers/gpu/drm/i915/i915_irq.c | 28 +- drivers/gpu/drm/i915/i915_reg.h | 41 +++ drivers/gpu/drm/i915/intel_display.c | 147 +++++++- 6 files changed, 772 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c864858d5064..eb11e1e049cb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -491,11 +491,14 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; u16 rgvswctl = I915_READ16(MEMSWCTL); + u16 rgvstat = I915_READ16(MEMSTAT_ILK); - seq_printf(m, "Last command: 0x%01x\n", (rgvswctl >> 13) & 0x3); - seq_printf(m, "Command status: %d\n", (rgvswctl >> 12) & 1); - seq_printf(m, "P%d DELAY 0x%02x\n", (rgvswctl >> 8) & 0xf, - rgvswctl & 0x3f); + seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); + seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f); + seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> + MEMSTAT_VID_SHIFT); + seq_printf(m, "Current P-state: %d\n", + (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); return 0; } @@ -510,7 +513,8 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) for (i = 0; i < 16; i++) { delayfreq = I915_READ(PXVFREQ_BASE + i * 4); - seq_printf(m, "P%02dVIDFREQ: 0x%08x\n", i, delayfreq); + seq_printf(m, "P%02dVIDFREQ: 0x%08x (VID: %d)\n", i, delayfreq, + (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT); } return 0; @@ -543,6 +547,8 @@ static int i915_drpc_info(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; u32 rgvmodectl = I915_READ(MEMMODECTL); + u32 rstdbyctl = I915_READ(MCHBAR_RENDER_STANDBY); + u16 crstandvid = I915_READ16(CRSTANDVID); seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? "yes" : "no"); @@ -557,9 +563,13 @@ static int i915_drpc_info(struct seq_file *m, void *unused) rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no"); seq_printf(m, "Starting frequency: P%d\n", (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT); - seq_printf(m, "Max frequency: P%d\n", + seq_printf(m, "Max P-state: P%d\n", (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT); - seq_printf(m, "Min frequency: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK)); + seq_printf(m, "Min P-state: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK)); + seq_printf(m, "RS1 VID: %d\n", (crstandvid & 0x3f)); + seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f)); + seq_printf(m, "Render standby enabled: %s\n", + (rstdbyctl & RCX_SW_EXIT) ? "no" : "yes"); return 0; } @@ -623,6 +633,36 @@ static int i915_sr_status(struct seq_file *m, void *unused) return 0; } +static int i915_emon_status(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long temp, chipset, gfx; + + temp = i915_mch_val(dev_priv); + chipset = i915_chipset_val(dev_priv); + gfx = i915_gfx_val(dev_priv); + + seq_printf(m, "GMCH temp: %ld\n", temp); + seq_printf(m, "Chipset power: %ld\n", chipset); + seq_printf(m, "GFX power: %ld\n", gfx); + seq_printf(m, "Total power: %ld\n", chipset + gfx); + + return 0; +} + +static int i915_gfxec(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + seq_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4)); + + return 0; +} + static int i915_wedged_open(struct inode *inode, struct file *filp) @@ -745,6 +785,8 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_delayfreq_table", i915_delayfreq_table, 0}, {"i915_inttoext_table", i915_inttoext_table, 0}, {"i915_drpc_info", i915_drpc_info, 0}, + {"i915_emon_status", i915_emon_status, 0}, + {"i915_gfxec", i915_gfxec, 0}, {"i915_fbc_status", i915_fbc_status, 0}, {"i915_sr_status", i915_sr_status, 0}, }; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 1dbed700800e..12e92f2cc3a7 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1458,14 +1458,11 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) master->driver_priv = NULL; } -static void i915_get_mem_freq(struct drm_device *dev) +static void i915_pineview_get_mem_freq(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; u32 tmp; - if (!IS_PINEVIEW(dev)) - return; - tmp = I915_READ(CLKCFG); switch (tmp & CLKCFG_FSB_MASK) { @@ -1496,6 +1493,519 @@ static void i915_get_mem_freq(struct drm_device *dev) } } +static void i915_ironlake_get_mem_freq(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u16 ddrpll, csipll; + + ddrpll = I915_READ16(DDRMPLL1); + csipll = I915_READ16(CSIPLL0); + + switch (ddrpll & 0xff) { + case 0xc: + dev_priv->mem_freq = 800; + break; + case 0x10: + dev_priv->mem_freq = 1066; + break; + case 0x14: + dev_priv->mem_freq = 1333; + break; + case 0x18: + dev_priv->mem_freq = 1600; + break; + default: + DRM_DEBUG_DRIVER("unknown memory frequency 0x%02x\n", + ddrpll & 0xff); + dev_priv->mem_freq = 0; + break; + } + + dev_priv->r_t = dev_priv->mem_freq; + + switch (csipll & 0x3ff) { + case 0x00c: + dev_priv->fsb_freq = 3200; + break; + case 0x00e: + dev_priv->fsb_freq = 3733; + break; + case 0x010: + dev_priv->fsb_freq = 4266; + break; + case 0x012: + dev_priv->fsb_freq = 4800; + break; + case 0x014: + dev_priv->fsb_freq = 5333; + break; + case 0x016: + dev_priv->fsb_freq = 5866; + break; + case 0x018: + dev_priv->fsb_freq = 6400; + break; + default: + DRM_DEBUG_DRIVER("unknown fsb frequency 0x%04x\n", + csipll & 0x3ff); + dev_priv->fsb_freq = 0; + break; + } + + if (dev_priv->fsb_freq == 3200) { + dev_priv->c_m = 0; + } else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) { + dev_priv->c_m = 1; + } else { + dev_priv->c_m = 2; + } +} + +struct v_table { + u8 vid; + unsigned long vd; /* in .1 mil */ + unsigned long vm; /* in .1 mil */ + u8 pvid; +}; + +static struct v_table v_table[] = { + { 0, 16125, 15000, 0x7f, }, + { 1, 16000, 14875, 0x7e, }, + { 2, 15875, 14750, 0x7d, }, + { 3, 15750, 14625, 0x7c, }, + { 4, 15625, 14500, 0x7b, }, + { 5, 15500, 14375, 0x7a, }, + { 6, 15375, 14250, 0x79, }, + { 7, 15250, 14125, 0x78, }, + { 8, 15125, 14000, 0x77, }, + { 9, 15000, 13875, 0x76, }, + { 10, 14875, 13750, 0x75, }, + { 11, 14750, 13625, 0x74, }, + { 12, 14625, 13500, 0x73, }, + { 13, 14500, 13375, 0x72, }, + { 14, 14375, 13250, 0x71, }, + { 15, 14250, 13125, 0x70, }, + { 16, 14125, 13000, 0x6f, }, + { 17, 14000, 12875, 0x6e, }, + { 18, 13875, 12750, 0x6d, }, + { 19, 13750, 12625, 0x6c, }, + { 20, 13625, 12500, 0x6b, }, + { 21, 13500, 12375, 0x6a, }, + { 22, 13375, 12250, 0x69, }, + { 23, 13250, 12125, 0x68, }, + { 24, 13125, 12000, 0x67, }, + { 25, 13000, 11875, 0x66, }, + { 26, 12875, 11750, 0x65, }, + { 27, 12750, 11625, 0x64, }, + { 28, 12625, 11500, 0x63, }, + { 29, 12500, 11375, 0x62, }, + { 30, 12375, 11250, 0x61, }, + { 31, 12250, 11125, 0x60, }, + { 32, 12125, 11000, 0x5f, }, + { 33, 12000, 10875, 0x5e, }, + { 34, 11875, 10750, 0x5d, }, + { 35, 11750, 10625, 0x5c, }, + { 36, 11625, 10500, 0x5b, }, + { 37, 11500, 10375, 0x5a, }, + { 38, 11375, 10250, 0x59, }, + { 39, 11250, 10125, 0x58, }, + { 40, 11125, 10000, 0x57, }, + { 41, 11000, 9875, 0x56, }, + { 42, 10875, 9750, 0x55, }, + { 43, 10750, 9625, 0x54, }, + { 44, 10625, 9500, 0x53, }, + { 45, 10500, 9375, 0x52, }, + { 46, 10375, 9250, 0x51, }, + { 47, 10250, 9125, 0x50, }, + { 48, 10125, 9000, 0x4f, }, + { 49, 10000, 8875, 0x4e, }, + { 50, 9875, 8750, 0x4d, }, + { 51, 9750, 8625, 0x4c, }, + { 52, 9625, 8500, 0x4b, }, + { 53, 9500, 8375, 0x4a, }, + { 54, 9375, 8250, 0x49, }, + { 55, 9250, 8125, 0x48, }, + { 56, 9125, 8000, 0x47, }, + { 57, 9000, 7875, 0x46, }, + { 58, 8875, 7750, 0x45, }, + { 59, 8750, 7625, 0x44, }, + { 60, 8625, 7500, 0x43, }, + { 61, 8500, 7375, 0x42, }, + { 62, 8375, 7250, 0x41, }, + { 63, 8250, 7125, 0x40, }, + { 64, 8125, 7000, 0x3f, }, + { 65, 8000, 6875, 0x3e, }, + { 66, 7875, 6750, 0x3d, }, + { 67, 7750, 6625, 0x3c, }, + { 68, 7625, 6500, 0x3b, }, + { 69, 7500, 6375, 0x3a, }, + { 70, 7375, 6250, 0x39, }, + { 71, 7250, 6125, 0x38, }, + { 72, 7125, 6000, 0x37, }, + { 73, 7000, 5875, 0x36, }, + { 74, 6875, 5750, 0x35, }, + { 75, 6750, 5625, 0x34, }, + { 76, 6625, 5500, 0x33, }, + { 77, 6500, 5375, 0x32, }, + { 78, 6375, 5250, 0x31, }, + { 79, 6250, 5125, 0x30, }, + { 80, 6125, 5000, 0x2f, }, + { 81, 6000, 4875, 0x2e, }, + { 82, 5875, 4750, 0x2d, }, + { 83, 5750, 4625, 0x2c, }, + { 84, 5625, 4500, 0x2b, }, + { 85, 5500, 4375, 0x2a, }, + { 86, 5375, 4250, 0x29, }, + { 87, 5250, 4125, 0x28, }, + { 88, 5125, 4000, 0x27, }, + { 89, 5000, 3875, 0x26, }, + { 90, 4875, 3750, 0x25, }, + { 91, 4750, 3625, 0x24, }, + { 92, 4625, 3500, 0x23, }, + { 93, 4500, 3375, 0x22, }, + { 94, 4375, 3250, 0x21, }, + { 95, 4250, 3125, 0x20, }, + { 96, 4125, 3000, 0x1f, }, + { 97, 4125, 3000, 0x1e, }, + { 98, 4125, 3000, 0x1d, }, + { 99, 4125, 3000, 0x1c, }, + { 100, 4125, 3000, 0x1b, }, + { 101, 4125, 3000, 0x1a, }, + { 102, 4125, 3000, 0x19, }, + { 103, 4125, 3000, 0x18, }, + { 104, 4125, 3000, 0x17, }, + { 105, 4125, 3000, 0x16, }, + { 106, 4125, 3000, 0x15, }, + { 107, 4125, 3000, 0x14, }, + { 108, 4125, 3000, 0x13, }, + { 109, 4125, 3000, 0x12, }, + { 110, 4125, 3000, 0x11, }, + { 111, 4125, 3000, 0x10, }, + { 112, 4125, 3000, 0x0f, }, + { 113, 4125, 3000, 0x0e, }, + { 114, 4125, 3000, 0x0d, }, + { 115, 4125, 3000, 0x0c, }, + { 116, 4125, 3000, 0x0b, }, + { 117, 4125, 3000, 0x0a, }, + { 118, 4125, 3000, 0x09, }, + { 119, 4125, 3000, 0x08, }, + { 120, 1125, 0, 0x07, }, + { 121, 1000, 0, 0x06, }, + { 122, 875, 0, 0x05, }, + { 123, 750, 0, 0x04, }, + { 124, 625, 0, 0x03, }, + { 125, 500, 0, 0x02, }, + { 126, 375, 0, 0x01, }, + { 127, 0, 0, 0x00, }, +}; + +struct cparams { + int i; + int t; + int m; + int c; +}; + +static struct cparams cparams[] = { + { 1, 1333, 301, 28664 }, + { 1, 1066, 294, 24460 }, + { 1, 800, 294, 25192 }, + { 0, 1333, 276, 27605 }, + { 0, 1066, 276, 27605 }, + { 0, 800, 231, 23784 }, +}; + +unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) +{ + u64 total_count, diff, ret; + u32 count1, count2, count3, m = 0, c = 0; + unsigned long now = jiffies_to_msecs(jiffies), diff1; + int i; + + diff1 = now - dev_priv->last_time1; + + count1 = I915_READ(DMIEC); + count2 = I915_READ(DDREC); + count3 = I915_READ(CSIEC); + + total_count = count1 + count2 + count3; + + /* FIXME: handle per-counter overflow */ + if (total_count < dev_priv->last_count1) { + diff = ~0UL - dev_priv->last_count1; + diff += total_count; + } else { + diff = total_count - dev_priv->last_count1; + } + + for (i = 0; i < ARRAY_SIZE(cparams); i++) { + if (cparams[i].i == dev_priv->c_m && + cparams[i].t == dev_priv->r_t) { + m = cparams[i].m; + c = cparams[i].c; + break; + } + } + + div_u64(diff, diff1); + ret = ((m * diff) + c); + div_u64(ret, 10); + + dev_priv->last_count1 = total_count; + dev_priv->last_time1 = now; + + return ret; +} + +unsigned long i915_mch_val(struct drm_i915_private *dev_priv) +{ + unsigned long m, x, b; + u32 tsfs; + + tsfs = I915_READ(TSFS); + + m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT); + x = I915_READ8(TR1); + + b = tsfs & TSFS_INTR_MASK; + + return ((m * x) / 127) - b; +} + +static unsigned long pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) +{ + unsigned long val = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(v_table); i++) { + if (v_table[i].pvid == pxvid) { + if (IS_MOBILE(dev_priv->dev)) + val = v_table[i].vm; + else + val = v_table[i].vd; + } + } + + return val; +} + +void i915_update_gfx_val(struct drm_i915_private *dev_priv) +{ + struct timespec now, diff1; + u64 diff; + unsigned long diffms; + u32 count; + + getrawmonotonic(&now); + diff1 = timespec_sub(now, dev_priv->last_time2); + + /* Don't divide by 0 */ + diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000; + if (!diffms) + return; + + count = I915_READ(GFXEC); + + if (count < dev_priv->last_count2) { + diff = ~0UL - dev_priv->last_count2; + diff += count; + } else { + diff = count - dev_priv->last_count2; + } + + dev_priv->last_count2 = count; + dev_priv->last_time2 = now; + + /* More magic constants... */ + diff = diff * 1181; + div_u64(diff, diffms * 10); + dev_priv->gfx_power = diff; +} + +unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) +{ + unsigned long t, corr, state1, corr2, state2; + u32 pxvid, ext_v; + + pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4)); + pxvid = (pxvid >> 24) & 0x7f; + ext_v = pvid_to_extvid(dev_priv, pxvid); + + state1 = ext_v; + + t = i915_mch_val(dev_priv); + + /* Revel in the empirically derived constants */ + + /* Correction factor in 1/100000 units */ + if (t > 80) + corr = ((t * 2349) + 135940); + else if (t >= 50) + corr = ((t * 964) + 29317); + else /* < 50 */ + corr = ((t * 301) + 1004); + + corr = corr * ((150142 * state1) / 10000 - 78642); + corr /= 100000; + corr2 = (corr * dev_priv->corr); + + state2 = (corr2 * state1) / 10000; + state2 /= 100; /* convert to mW */ + + i915_update_gfx_val(dev_priv); + + return dev_priv->gfx_power + state2; +} + +/* Global for IPS driver to get at the current i915 device */ +static struct drm_i915_private *i915_mch_dev; +/* + * Lock protecting IPS related data structures + * - i915_mch_dev + * - dev_priv->max_delay + * - dev_priv->min_delay + * - dev_priv->fmax + * - dev_priv->gpu_busy + */ +DEFINE_SPINLOCK(mchdev_lock); + +/** + * i915_read_mch_val - return value for IPS use + * + * Calculate and return a value for the IPS driver to use when deciding whether + * we have thermal and power headroom to increase CPU or GPU power budget. + */ +unsigned long i915_read_mch_val(void) +{ + struct drm_i915_private *dev_priv; + unsigned long chipset_val, graphics_val, ret = 0; + + spin_lock(&mchdev_lock); + if (!i915_mch_dev) + goto out_unlock; + dev_priv = i915_mch_dev; + + chipset_val = i915_chipset_val(dev_priv); + graphics_val = i915_gfx_val(dev_priv); + + ret = chipset_val + graphics_val; + +out_unlock: + spin_unlock(&mchdev_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i915_read_mch_val); + +/** + * i915_gpu_raise - raise GPU frequency limit + * + * Raise the limit; IPS indicates we have thermal headroom. + */ +bool i915_gpu_raise(void) +{ + struct drm_i915_private *dev_priv; + bool ret = true; + + spin_lock(&mchdev_lock); + if (!i915_mch_dev) { + ret = false; + goto out_unlock; + } + dev_priv = i915_mch_dev; + + if (dev_priv->max_delay > dev_priv->fmax) + dev_priv->max_delay--; + +out_unlock: + spin_unlock(&mchdev_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i915_gpu_raise); + +/** + * i915_gpu_lower - lower GPU frequency limit + * + * IPS indicates we're close to a thermal limit, so throttle back the GPU + * frequency maximum. + */ +bool i915_gpu_lower(void) +{ + struct drm_i915_private *dev_priv; + bool ret = true; + + spin_lock(&mchdev_lock); + if (!i915_mch_dev) { + ret = false; + goto out_unlock; + } + dev_priv = i915_mch_dev; + + if (dev_priv->max_delay < dev_priv->min_delay) + dev_priv->max_delay++; + +out_unlock: + spin_unlock(&mchdev_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i915_gpu_lower); + +/** + * i915_gpu_busy - indicate GPU business to IPS + * + * Tell the IPS driver whether or not the GPU is busy. + */ +bool i915_gpu_busy(void) +{ + struct drm_i915_private *dev_priv; + bool ret = false; + + spin_lock(&mchdev_lock); + if (!i915_mch_dev) + goto out_unlock; + dev_priv = i915_mch_dev; + + ret = dev_priv->busy; + +out_unlock: + spin_unlock(&mchdev_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i915_gpu_busy); + +/** + * i915_gpu_turbo_disable - disable graphics turbo + * + * Disable graphics turbo by resetting the max frequency and setting the + * current frequency to the default. + */ +bool i915_gpu_turbo_disable(void) +{ + struct drm_i915_private *dev_priv; + bool ret = true; + + spin_lock(&mchdev_lock); + if (!i915_mch_dev) { + ret = false; + goto out_unlock; + } + dev_priv = i915_mch_dev; + + dev_priv->max_delay = dev_priv->fstart; + + if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart)) + ret = false; + +out_unlock: + spin_unlock(&mchdev_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable); + /** * i915_driver_load - setup chip and create an initial config * @dev: DRM device @@ -1616,7 +2126,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_workqueue_free; } - i915_get_mem_freq(dev); + if (IS_PINEVIEW(dev)) + i915_pineview_get_mem_freq(dev); + else if (IS_IRONLAKE(dev)) + i915_ironlake_get_mem_freq(dev); /* On the 945G/GM, the chipset reports the MSI capability on the * integrated graphics even though the support isn't actually there @@ -1662,6 +2175,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, (unsigned long) dev); + + spin_lock(&mchdev_lock); + i915_mch_dev = dev_priv; + dev_priv->mchdev_lock = &mchdev_lock; + spin_unlock(&mchdev_lock); + return 0; out_workqueue_free: @@ -1683,6 +2202,10 @@ int i915_driver_unload(struct drm_device *dev) i915_destroy_error_state(dev); + spin_lock(&mchdev_lock); + i915_mch_dev = NULL; + spin_unlock(&mchdev_lock); + destroy_workqueue(dev_priv->wq); del_timer_sync(&dev_priv->hangcheck_timer); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6bc0fc080f2b..91b3a1c20ef8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -619,6 +619,18 @@ typedef struct drm_i915_private { u8 cur_delay; u8 min_delay; u8 max_delay; + u8 fmax; + u8 fstart; + + u64 last_count1; + unsigned long last_time1; + u64 last_count2; + struct timespec last_time2; + unsigned long gfx_power; + int c_m; + int r_t; + u8 corr; + spinlock_t *mchdev_lock; enum no_fbc_reason no_fbc_reason; @@ -802,6 +814,11 @@ extern int i915_emit_box(struct drm_device *dev, struct drm_clip_rect *boxes, int i, int DR1, int DR4); extern int i965_reset(struct drm_device *dev, u8 flags); +extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); +extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); +extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); +extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); + /* i915_irq.c */ void i915_hangcheck_elapsed(unsigned long data); @@ -1005,7 +1022,7 @@ extern void g4x_disable_fbc(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev); extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); extern bool intel_fbc_enabled(struct drm_device *dev); - +extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern void intel_detect_pch (struct drm_device *dev); extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); @@ -1030,6 +1047,7 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); #define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg)) #define I915_READ64(reg) readq(dev_priv->regs + (reg)) #define POSTING_READ(reg) (void)I915_READ(reg) +#define POSTING_READ16(reg) (void)I915_READ16(reg) #define I915_VERBOSE 0 diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0a3a5806a12e..b5dba4795f6f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -278,10 +278,9 @@ static void i915_handle_rps_change(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; u32 busy_up, busy_down, max_avg, min_avg; - u16 rgvswctl; u8 new_delay = dev_priv->cur_delay; - I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS) & ~MEMINT_EVAL_CHG); + I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG); busy_up = I915_READ(RCPREVBSYTUPAVG); busy_down = I915_READ(RCPREVBSYTDNAVG); max_avg = I915_READ(RCBMAXAVG); @@ -300,27 +299,8 @@ static void i915_handle_rps_change(struct drm_device *dev) new_delay = dev_priv->min_delay; } - DRM_DEBUG("rps change requested: %d -> %d\n", - dev_priv->cur_delay, new_delay); - - rgvswctl = I915_READ(MEMSWCTL); - if (rgvswctl & MEMCTL_CMD_STS) { - DRM_ERROR("gpu busy, RCS change rejected\n"); - return; /* still busy with another command */ - } - - /* Program the new state */ - rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | - (new_delay << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; - I915_WRITE(MEMSWCTL, rgvswctl); - POSTING_READ(MEMSWCTL); - - rgvswctl |= MEMCTL_CMD_STS; - I915_WRITE(MEMSWCTL, rgvswctl); - - dev_priv->cur_delay = new_delay; - - DRM_DEBUG("rps changed\n"); + if (ironlake_set_drps(dev, new_delay)) + dev_priv->cur_delay = new_delay; return; } @@ -392,7 +372,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) } if (de_iir & DE_PCU_EVENT) { - I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS)); + I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); i915_handle_rps_change(dev); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7a726840efa7..df7224de0aed 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -838,6 +838,12 @@ #define CLKCFG_MEM_800 (3 << 4) #define CLKCFG_MEM_MASK (7 << 4) +#define TR1 0x11006 +#define TSFS 0x11020 +#define TSFS_SLOPE_MASK 0x0000ff00 +#define TSFS_SLOPE_SHIFT 8 +#define TSFS_INTR_MASK 0x000000ff + #define CRSTANDVID 0x11100 #define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */ #define PXVFREQ_PX_MASK 0x7f000000 @@ -976,6 +982,41 @@ #define MEMSTAT_SRC_CTL_STDBY 3 #define RCPREVBSYTUPAVG 0x113b8 #define RCPREVBSYTDNAVG 0x113bc +#define SDEW 0x1124c +#define CSIEW0 0x11250 +#define CSIEW1 0x11254 +#define CSIEW2 0x11258 +#define PEW 0x1125c +#define DEW 0x11270 +#define MCHAFE 0x112c0 +#define CSIEC 0x112e0 +#define DMIEC 0x112e4 +#define DDREC 0x112e8 +#define PEG0EC 0x112ec +#define PEG1EC 0x112f0 +#define GFXEC 0x112f4 +#define RPPREVBSYTUPAVG 0x113b8 +#define RPPREVBSYTDNAVG 0x113bc +#define ECR 0x11600 +#define ECR_GPFE (1<<31) +#define ECR_IMONE (1<<30) +#define ECR_CAP_MASK 0x0000001f /* Event range, 0-31 */ +#define OGW0 0x11608 +#define OGW1 0x1160c +#define EG0 0x11610 +#define EG1 0x11614 +#define EG2 0x11618 +#define EG3 0x1161c +#define EG4 0x11620 +#define EG5 0x11624 +#define EG6 0x11628 +#define EG7 0x1162c +#define PXW 0x11664 +#define PXWL 0x11680 +#define LCFUSE02 0x116c0 +#define LCFUSE_HIV_MASK 0x000000ff +#define CSIPLL0 0x12c10 +#define DDRMPLL1 0X12c20 #define PEG_BAND_GAP_DATA 0x14d68 /* diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4c7c151114f7..e94d1db35364 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4459,6 +4459,8 @@ static void intel_idle_update(struct work_struct *work) mutex_lock(&dev->struct_mutex); + i915_update_gfx_val(dev_priv); + if (IS_I945G(dev) || IS_I945GM(dev)) { DRM_DEBUG_DRIVER("enable memory self refresh on 945\n"); I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); @@ -5045,10 +5047,32 @@ err_unref: return NULL; } +bool ironlake_set_drps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u16 rgvswctl; + + rgvswctl = I915_READ16(MEMSWCTL); + if (rgvswctl & MEMCTL_CMD_STS) { + DRM_DEBUG("gpu busy, RCS change rejected\n"); + return false; /* still busy with another command */ + } + + rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | + (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; + I915_WRITE16(MEMSWCTL, rgvswctl); + POSTING_READ16(MEMSWCTL); + + rgvswctl |= MEMCTL_CMD_STS; + I915_WRITE16(MEMSWCTL, rgvswctl); + + return true; +} + void ironlake_enable_drps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl; + u32 rgvmodectl = I915_READ(MEMMODECTL); u8 fmax, fmin, fstart, vstart; int i = 0; @@ -5067,13 +5091,21 @@ void ironlake_enable_drps(struct drm_device *dev) fmin = (rgvmodectl & MEMMODE_FMIN_MASK); fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT; + fstart = fmax; + vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT; - dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */ + dev_priv->fmax = fstart; /* IPS callback will increase this */ + dev_priv->fstart = fstart; + + dev_priv->max_delay = fmax; dev_priv->min_delay = fmin; dev_priv->cur_delay = fstart; + DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", fmax, fmin, + fstart); + I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); /* @@ -5095,20 +5127,19 @@ void ironlake_enable_drps(struct drm_device *dev) } msleep(1); - rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | - (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; - I915_WRITE(MEMSWCTL, rgvswctl); - POSTING_READ(MEMSWCTL); + ironlake_set_drps(dev, fstart); - rgvswctl |= MEMCTL_CMD_STS; - I915_WRITE(MEMSWCTL, rgvswctl); + dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) + + I915_READ(0x112e0); + dev_priv->last_time1 = jiffies_to_msecs(jiffies); + dev_priv->last_count2 = I915_READ(0x112f4); + getrawmonotonic(&dev_priv->last_time2); } void ironlake_disable_drps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 rgvswctl; - u8 fstart; + u16 rgvswctl = I915_READ16(MEMSWCTL); /* Ack interrupts, disable EFC interrupt */ I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); @@ -5118,11 +5149,7 @@ void ironlake_disable_drps(struct drm_device *dev) I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT); /* Go back to the starting frequency */ - fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >> - MEMMODE_FSTART_SHIFT; - rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | - (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; - I915_WRITE(MEMSWCTL, rgvswctl); + ironlake_set_drps(dev, dev_priv->fstart); msleep(1); rgvswctl |= MEMCTL_CMD_STS; I915_WRITE(MEMSWCTL, rgvswctl); @@ -5130,6 +5157,92 @@ void ironlake_disable_drps(struct drm_device *dev) } +static unsigned long intel_pxfreq(u32 vidfreq) +{ + unsigned long freq; + int div = (vidfreq & 0x3f0000) >> 16; + int post = (vidfreq & 0x3000) >> 12; + int pre = (vidfreq & 0x7); + + if (!pre) + return 0; + + freq = ((div * 133333) / ((1<<post) * pre)); + + return freq; +} + +void intel_init_emon(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 lcfuse; + u8 pxw[16]; + int i; + + /* Disable to program */ + I915_WRITE(ECR, 0); + POSTING_READ(ECR); + + /* Program energy weights for various events */ + I915_WRITE(SDEW, 0x15040d00); + I915_WRITE(CSIEW0, 0x007f0000); + I915_WRITE(CSIEW1, 0x1e220004); + I915_WRITE(CSIEW2, 0x04000004); + + for (i = 0; i < 5; i++) + I915_WRITE(PEW + (i * 4), 0); + for (i = 0; i < 3; i++) + I915_WRITE(DEW + (i * 4), 0); + + /* Program P-state weights to account for frequency power adjustment */ + for (i = 0; i < 16; i++) { + u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4)); + unsigned long freq = intel_pxfreq(pxvidfreq); + unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >> + PXVFREQ_PX_SHIFT; + unsigned long val; + + val = vid * vid; + val *= (freq / 1000); + val *= 255; + val /= (127*127*900); + if (val > 0xff) + DRM_ERROR("bad pxval: %ld\n", val); + pxw[i] = val; + } + /* Render standby states get 0 weight */ + pxw[14] = 0; + pxw[15] = 0; + + for (i = 0; i < 4; i++) { + u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) | + (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]); + I915_WRITE(PXW + (i * 4), val); + } + + /* Adjust magic regs to magic values (more experimental results) */ + I915_WRITE(OGW0, 0); + I915_WRITE(OGW1, 0); + I915_WRITE(EG0, 0x00007f00); + I915_WRITE(EG1, 0x0000000e); + I915_WRITE(EG2, 0x000e0000); + I915_WRITE(EG3, 0x68000300); + I915_WRITE(EG4, 0x42000000); + I915_WRITE(EG5, 0x00140031); + I915_WRITE(EG6, 0); + I915_WRITE(EG7, 0); + + for (i = 0; i < 8; i++) + I915_WRITE(PXWL + (i * 4), 0); + + /* Enable PMON + select events */ + I915_WRITE(ECR, 0x80000019); + + lcfuse = I915_READ(LCFUSE02); + + dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); +} + void intel_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5376,8 +5489,10 @@ void intel_modeset_init(struct drm_device *dev) intel_init_clock_gating(dev); - if (IS_IRONLAKE_M(dev)) + if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); + intel_init_emon(dev); + } INIT_WORK(&dev_priv->idle_work, intel_idle_update); setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, -- GitLab From 9a7e8492d17394a81d5534abf90b5b2ada7ea3c0 Mon Sep 17 00:00:00 2001 From: Tobias Klauser <tklauser@distanz.ch> Date: Thu, 20 May 2010 10:33:46 +0200 Subject: [PATCH 220/842] drm/i915: Storage class should be before const qualifier The C99 specification states in section 6.11.5: The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature. Signed-off-by: Tobias Klauser <tklauser@distanz.ch> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_drv.c | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c072b212979c..423dc90c1e20 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -60,95 +60,95 @@ extern int intel_agp_enabled; .subdevice = PCI_ANY_ID, \ .driver_data = (unsigned long) info } -const static struct intel_device_info intel_i830_info = { +static const struct intel_device_info intel_i830_info = { .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_845g_info = { +static const struct intel_device_info intel_845g_info = { .is_i8xx = 1, }; -const static struct intel_device_info intel_i85x_info = { +static const struct intel_device_info intel_i85x_info = { .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_i865g_info = { +static const struct intel_device_info intel_i865g_info = { .is_i8xx = 1, }; -const static struct intel_device_info intel_i915g_info = { +static const struct intel_device_info intel_i915g_info = { .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_i915gm_info = { +static const struct intel_device_info intel_i915gm_info = { .is_i9xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_i945g_info = { +static const struct intel_device_info intel_i945g_info = { .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_i945gm_info = { +static const struct intel_device_info intel_i945gm_info = { .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1, .has_hotplug = 1, .cursor_needs_physical = 1, }; -const static struct intel_device_info intel_i965g_info = { +static const struct intel_device_info intel_i965g_info = { .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_i965gm_info = { +static const struct intel_device_info intel_i965gm_info = { .is_i965g = 1, .is_mobile = 1, .is_i965gm = 1, .is_i9xx = 1, .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_g33_info = { +static const struct intel_device_info intel_g33_info = { .is_g33 = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_g45_info = { +static const struct intel_device_info intel_g45_info = { .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_gm45_info = { +static const struct intel_device_info intel_gm45_info = { .is_i965g = 1, .is_mobile = 1, .is_g4x = 1, .is_i9xx = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_pineview_info = { +static const struct intel_device_info intel_pineview_info = { .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_ironlake_d_info = { +static const struct intel_device_info intel_ironlake_d_info = { .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_ironlake_m_info = { +static const struct intel_device_info intel_ironlake_m_info = { .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_rc6 = 1, .has_hotplug = 1, }; -const static struct intel_device_info intel_sandybridge_d_info = { +static const struct intel_device_info intel_sandybridge_d_info = { .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, .is_gen6 = 1, }; -const static struct intel_device_info intel_sandybridge_m_info = { +static const struct intel_device_info intel_sandybridge_m_info = { .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, .need_gfx_hws = 1, .has_hotplug = 1, .is_gen6 = 1, }; -const static struct pci_device_id pciidlist[] = { +static const struct pci_device_id pciidlist[] = { INTEL_VGA_DEVICE(0x3577, &intel_i830_info), INTEL_VGA_DEVICE(0x2562, &intel_845g_info), INTEL_VGA_DEVICE(0x3582, &intel_i85x_info), -- GitLab From f1befe71fa7a79ab733011b045639d8d809924ad Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 18 May 2010 12:24:51 +0100 Subject: [PATCH 221/842] agp/intel: Restrict GTT mapping to valid range on i915 and i945 References: Bug 15733 - Crash when accessing nonexistent GTT entries in i915 https://bugzilla.kernel.org/show_bug.cgi?id=15733 On G33 and above, the size of the GTT space is determined by the GMCH control register. Prior to this revision, the size is determined by the size of the aperture. So we must careful to map and fill the appropriate range depending on chipset. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/char/agp/intel-gtt.c | 46 ++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index e8ea6825822c..9344216183a4 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1059,7 +1059,7 @@ static void intel_i9xx_setup_flush(void) } } -static int intel_i915_configure(void) +static int intel_i9xx_configure(void) { struct aper_size_info_fixed *current_size; u32 temp; @@ -1207,6 +1207,38 @@ static int intel_i9xx_fetch_size(void) return 0; } +static int intel_i915_get_gtt_size(void) +{ + int size; + + if (IS_G33) { + u16 gmch_ctrl; + + /* G33's GTT size defined in gmch_ctrl */ + pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); + switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { + case G33_PGETBL_SIZE_1M: + size = 1024; + break; + case G33_PGETBL_SIZE_2M: + size = 2048; + break; + default: + dev_info(&agp_bridge->dev->dev, + "unknown page table size 0x%x, assuming 512KB\n", + (gmch_ctrl & G33_PGETBL_SIZE_MASK)); + size = 512; + } + } else { + /* On previous hardware, the GTT size was just what was + * required to map the aperture. + */ + size = agp_bridge->driver->fetch_size(); + } + + return KB(size); +} + /* The intel i915 automatically initializes the agp aperture during POST. * Use the memory already set aside for in the GTT. */ @@ -1216,7 +1248,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) struct aper_size_info_fixed *size; int num_entries; u32 temp, temp2; - int gtt_map_size = 256 * 1024; + int gtt_map_size; size = agp_bridge->current_size; page_order = size->page_order; @@ -1226,8 +1258,8 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2); - if (IS_G33) - gtt_map_size = 1024 * 1024; /* 1M on G33 */ + gtt_map_size = intel_i915_get_gtt_size(); + intel_private.gtt = ioremap(temp2, gtt_map_size); if (!intel_private.gtt) return -ENOMEM; @@ -1422,7 +1454,7 @@ static const struct agp_bridge_driver intel_915_driver = { .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, - .configure = intel_i915_configure, + .configure = intel_i9xx_configure, .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i810_mask_memory, @@ -1455,7 +1487,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, - .configure = intel_i915_configure, + .configure = intel_i9xx_configure, .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i965_mask_memory, @@ -1488,7 +1520,7 @@ static const struct agp_bridge_driver intel_g33_driver = { .size_type = FIXED_APER_SIZE, .num_aperture_sizes = 4, .needs_scratch_page = true, - .configure = intel_i915_configure, + .configure = intel_i9xx_configure, .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_i965_mask_memory, -- GitLab From 9908ff736adf261e749b4887486a32ffa209304c Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sat, 15 May 2010 09:57:03 +0100 Subject: [PATCH 222/842] drm/i915: Kill dangerous pending-flip debugging We can, by virtue of a vblank interrupt firing in the middle of setting up the unpin work (i.e. after we set the unpin_work field and before we write to the ringbuffer) enter intel_finish_page_flip() prior to receiving the pending flip notification. Therefore we can expect to hit intel_finish_page_flip() under normal circumstances without a pending flip and even without installing the pending_flip_obj. This is exacerbated by aperture thrashing whilst binding the framebuffer References: Bug 28079 - "glresize" causes kernel panic in intel_finish_page_flip. https://bugs.freedesktop.org/show_bug.cgi?id=28079 Reported-by: Nick Bowler <nbowler@draconx.ca> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Jesse Barnes <jbarnes@virtuousgeek.org> Cc: stable@kernel.org Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_display.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e94d1db35364..f946332612ec 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4589,12 +4589,6 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe) spin_lock_irqsave(&dev->event_lock, flags); work = intel_crtc->unpin_work; if (work == NULL || !work->pending) { - if (work && !work->pending) { - obj_priv = to_intel_bo(work->pending_flip_obj); - DRM_DEBUG_DRIVER("flip finish: %p (%d) not pending?\n", - obj_priv, - atomic_read(&obj_priv->pending_flip)); - } spin_unlock_irqrestore(&dev->event_lock, flags); return; } -- GitLab From 9962c9252e46eda7058067cbe73bdf1ed74b0d37 Mon Sep 17 00:00:00 2001 From: Adam Jackson <ajax@redhat.com> Date: Thu, 13 May 2010 14:45:42 -0400 Subject: [PATCH 223/842] drm/i915/dp: Only enable enhanced framing if the sink supports it DisplayPort spec v1.1a, Table 2-52. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_dp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6b1c9a27c27a..6eed9a2006d7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -675,10 +675,9 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, dp_priv->link_configuration[1] = dp_priv->lane_count; /* - * Check for DPCD version > 1.1, - * enable enahanced frame stuff in that case + * Check for DPCD version > 1.1 and enhanced framing support */ - if (dp_priv->dpcd[0] >= 0x11) { + if (dp_priv->dpcd[0] >= 0x11 && (dp_priv->dpcd[2] & DP_ENHANCED_FRAME_CAP)) { dp_priv->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; dp_priv->DP |= DP_ENHANCED_FRAMING; } -- GitLab From a7de64e540d2017a8e44dec1ca9d88a509aa7e05 Mon Sep 17 00:00:00 2001 From: Adam Jackson <ajax@redhat.com> Date: Thu, 13 May 2010 14:45:43 -0400 Subject: [PATCH 224/842] drm/i915/dp: Add DPCD data to debug output Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_dp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6eed9a2006d7..0a11c657c949 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1207,6 +1207,8 @@ ironlake_dp_detect(struct drm_connector *connector) if (dp_priv->dpcd[0] != 0) status = connector_status_connected; } + DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", dp_priv->dpcd[0], + dp_priv->dpcd[1], dp_priv->dpcd[2], dp_priv->dpcd[3]); return status; } -- GitLab From 778c35444f7bbb8f1816d40ada650e19c5da9c02 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 13 May 2010 11:49:44 +0200 Subject: [PATCH 225/842] drm/i915: combine all small integers into one single bitfield This saves a whooping 7 dwords. Zero functional changes. Because some of the refcounts are rather tightly calculated, I've put BUG_ONs in the code to check for overflows. Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_drv.h | 75 +++++++++++++++++++++------------ drivers/gpu/drm/i915/i915_gem.c | 5 +++ 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 91b3a1c20ef8..cccf8019f65a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -658,19 +658,64 @@ struct drm_i915_gem_object { * (has pending rendering), and is not set if it's on inactive (ready * to be unbound). */ - int active; + unsigned int active : 1; /** * This is set if the object has been written to since last bound * to the GTT */ - int dirty; + unsigned int dirty : 1; + + /** + * Fence register bits (if any) for this object. Will be set + * as needed when mapped into the GTT. + * Protected by dev->struct_mutex. + * + * Size: 4 bits for 16 fences + sign (for FENCE_REG_NONE) + */ + int fence_reg : 5; + + /** + * Used for checking the object doesn't appear more than once + * in an execbuffer object list. + */ + unsigned int in_execbuffer : 1; + + /** + * Advice: are the backing pages purgeable? + */ + unsigned int madv : 2; + + /** + * Refcount for the pages array. With the current locking scheme, there + * are at most two concurrent users: Binding a bo to the gtt and + * pwrite/pread using physical addresses. So two bits for a maximum + * of two users are enough. + */ + unsigned int pages_refcount : 2; +#define DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT 0x3 + + /** + * Current tiling mode for the object. + */ + unsigned int tiling_mode : 2; + + /** How many users have pinned this object in GTT space. The following + * users can each hold at most one reference: pwrite/pread, pin_ioctl + * (via user_pin_count), execbuffer (objects are not allowed multiple + * times for the same batchbuffer), and the framebuffer code. When + * switching/pageflipping, the framebuffer code has at most two buffers + * pinned per crtc. + * + * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 + * bits with absolutely no headroom. So use 4 bits. */ + int pin_count : 4; +#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf /** AGP memory structure for our GTT binding. */ DRM_AGP_MEM *agp_mem; struct page **pages; - int pages_refcount; /** * Current offset of the object in GTT space. @@ -687,21 +732,10 @@ struct drm_i915_gem_object { */ uint64_t mmap_offset; - /** - * Fence register bits (if any) for this object. Will be set - * as needed when mapped into the GTT. - * Protected by dev->struct_mutex. - */ - int fence_reg; - - /** How many users have pinned this object in GTT space */ - int pin_count; - /** Breadcrumb of last rendering to the buffer. */ uint32_t last_rendering_seqno; - /** Current tiling mode for the object. */ - uint32_t tiling_mode; + /** Current tiling stride for the object, if it's tiled. */ uint32_t stride; /** Record of address bit 17 of each page at last unbind. */ @@ -723,17 +757,6 @@ struct drm_i915_gem_object { /** for phy allocated objects */ struct drm_i915_gem_phys_object *phys_obj; - /** - * Used for checking the object doesn't appear more than once - * in an execbuffer object list. - */ - int in_execbuffer; - - /** - * Advice: are the backing pages purgeable? - */ - int madv; - /** * Number of crtcs where this object is currently the fb, but * will be page flipped away on the next vblank. When it diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c51495f15718..bf703551343a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2247,6 +2247,9 @@ i915_gem_object_get_pages(struct drm_gem_object *obj, struct inode *inode; struct page *page; + BUG_ON(obj_priv->pages_refcount + == DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT); + if (obj_priv->pages_refcount++ != 0) return 0; @@ -4156,6 +4159,8 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); int ret; + BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); + i915_verify_inactive(dev, __FILE__, __LINE__); if (obj_priv->gtt_space == NULL) { ret = i915_gem_object_bind_to_gtt(obj, alignment); -- GitLab From 467b200da78c56036e58850a7f27902937d506f7 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang <zhenyuw@linux.intel.com> Date: Wed, 12 May 2010 11:02:14 +0800 Subject: [PATCH 226/842] drm/i915: Fix HDMI mode select for Cougarpoint PCH For real HDMI sink, CPT HDMI port has to set 'HDMI' mode flag in order to make HDMI audio work correctly. This is required patch for drm/i915 to enable HDMI audio on CPT PCH, ALSA patch is at http://mailman.alsa-project.org/pipermail/alsa-devel/2010-May/027601.html Tested-by: Fengguang Wu <fengguang.wu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_hdmi.c | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index df7224de0aed..881fbe9a17f2 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2744,6 +2744,9 @@ #define SDVO_ENCODING (0) #define TMDS_ENCODING (2 << 10) #define NULL_PACKET_VSYNC_ENABLE (1 << 9) +/* CPT */ +#define HDMI_MODE_SELECT (1 << 9) +#define DVI_MODE_SELECT (0) #define SDVOB_BORDER_ENABLE (1 << 7) #define AUDIO_ENABLE (1 << 6) #define VSYNC_ACTIVE_HIGH (1 << 4) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 65727f0a79a3..83bd764b000e 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -59,8 +59,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH; - if (hdmi_priv->has_hdmi_sink) + if (hdmi_priv->has_hdmi_sink) { sdvox |= SDVO_AUDIO_ENABLE; + if (HAS_PCH_CPT(dev)) + sdvox |= HDMI_MODE_SELECT; + } if (intel_crtc->pipe == 1) { if (HAS_PCH_CPT(dev)) -- GitLab From 90a78e8f60f679b0937011314a6cda39c7449d1d Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Fri, 7 May 2010 10:40:09 +0200 Subject: [PATCH 227/842] i915/intel_sdvo: remove unneeded null check The "connector" variable is used as the cursor in a list_for_each_entry() and it's always non-null so we don't need to check it. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_sdvo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index aba72c489a2f..76993ac16cc1 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1479,7 +1479,7 @@ intel_find_analog_connector(struct drm_device *dev) intel_encoder = enc_to_intel_encoder(encoder); if (intel_encoder->type == INTEL_OUTPUT_ANALOG) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector && encoder == intel_attached_encoder(connector)) + if (encoder == intel_attached_encoder(connector)) return connector; } } -- GitLab From d8201ab6514f8dc1a0ccfac52c688d80976a425a Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Fri, 7 May 2010 10:39:00 +0200 Subject: [PATCH 228/842] i915: remove unneeded null checks The "encoder" variable can never be null because it is used as loop cursor in a list_for_each_entry() loop. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0a11c657c949..49b54f05d3cf 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -576,7 +576,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct intel_encoder *intel_encoder; struct intel_dp_priv *dp_priv; - if (!encoder || encoder->crtc != crtc) + if (encoder->crtc != crtc) continue; intel_encoder = enc_to_intel_encoder(encoder); @@ -1353,7 +1353,7 @@ intel_trans_dp_port_sel (struct drm_crtc *crtc) struct intel_encoder *intel_encoder = NULL; list_for_each_entry(encoder, &mode_config->encoder_list, head) { - if (!encoder || encoder->crtc != crtc) + if (encoder->crtc != crtc) continue; intel_encoder = enc_to_intel_encoder(encoder); -- GitLab From 9553426372eef71c849499fb1d232f4b0577c0f9 Mon Sep 17 00:00:00 2001 From: Li Peng <peng.li@linux.intel.com> Date: Tue, 18 May 2010 18:58:44 +0800 Subject: [PATCH 229/842] drm/i915: Add CxSR support on Pineview DDR3 Pineview with DDR3 memory has different latencies to enable CxSR. This patch updates CxSR latency table to add Pineview DDR3 latency configuration. It also adds one flag "is_ddr3" for checking DDR3 setting in MCHBAR. Cc: Shaohua Li <shaohua.li@intel.com> Cc: Zhao Yakui <yakui.zhao@intel.com> Signed-off-by: Li Peng <peng.li@intel.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_dma.c | 4 ++ drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_reg.h | 4 ++ drivers/gpu/drm/i915/intel_display.c | 72 +++++++++++++++++----------- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 12e92f2cc3a7..a5f401664845 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1491,6 +1491,10 @@ static void i915_pineview_get_mem_freq(struct drm_device *dev) dev_priv->mem_freq = 800; break; } + + /* detect pineview DDR3 setting */ + tmp = I915_READ(CSHRDDR3CTL); + dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0; } static void i915_ironlake_get_mem_freq(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cccf8019f65a..e6b4cab6565f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -326,7 +326,7 @@ typedef struct drm_i915_private { int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ int num_fence_regs; /* 8 on pre-965, 16 otherwise */ - unsigned int fsb_freq, mem_freq; + unsigned int fsb_freq, mem_freq, is_ddr3; spinlock_t error_lock; struct drm_i915_error_state *first_error; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 881fbe9a17f2..af7b10853e33 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -817,6 +817,10 @@ #define DCC_CHANNEL_XOR_DISABLE (1 << 10) #define DCC_CHANNEL_XOR_BIT_17 (1 << 9) +/** Pineview MCH register contains DDR3 setting */ +#define CSHRDDR3CTL 0x101a8 +#define CSHRDDR3CTL_DDR3 (1 << 2) + /** 965 MCH register controlling DRAM channel configuration */ #define C0DRB3 0x10206 #define C1DRB3 0x10606 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f946332612ec..cfac4dd1d483 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2640,6 +2640,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, struct cxsr_latency { int is_desktop; + int is_ddr3; unsigned long fsb_freq; unsigned long mem_freq; unsigned long display_sr; @@ -2649,33 +2650,45 @@ struct cxsr_latency { }; static struct cxsr_latency cxsr_latency_table[] = { - {1, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ - {1, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ - {1, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ - - {1, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */ - {1, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */ - {1, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */ - - {1, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */ - {1, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */ - {1, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */ - - {0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */ - {0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */ - {0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */ - - {0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */ - {0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */ - {0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */ - - {0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */ - {0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */ - {0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */ + {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ + {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ + {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ + {1, 1, 800, 667, 6420, 36420, 6873, 36873}, /* DDR3-667 SC */ + {1, 1, 800, 800, 5902, 35902, 6318, 36318}, /* DDR3-800 SC */ + + {1, 0, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */ + {1, 0, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */ + {1, 0, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */ + {1, 1, 667, 667, 6438, 36438, 6911, 36911}, /* DDR3-667 SC */ + {1, 1, 667, 800, 5941, 35941, 6377, 36377}, /* DDR3-800 SC */ + + {1, 0, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */ + {1, 0, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */ + {1, 0, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */ + {1, 1, 400, 667, 6509, 36509, 7062, 37062}, /* DDR3-667 SC */ + {1, 1, 400, 800, 5985, 35985, 6501, 36501}, /* DDR3-800 SC */ + + {0, 0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */ + {0, 0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */ + {0, 0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */ + {0, 1, 800, 667, 6476, 36476, 6955, 36955}, /* DDR3-667 SC */ + {0, 1, 800, 800, 5958, 35958, 6400, 36400}, /* DDR3-800 SC */ + + {0, 0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */ + {0, 0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */ + {0, 0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */ + {0, 1, 667, 667, 6494, 36494, 6993, 36993}, /* DDR3-667 SC */ + {0, 1, 667, 800, 5998, 35998, 6460, 36460}, /* DDR3-800 SC */ + + {0, 0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */ + {0, 0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */ + {0, 0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */ + {0, 1, 400, 667, 6566, 36566, 7145, 37145}, /* DDR3-667 SC */ + {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */ }; -static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb, - int mem) +static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int is_ddr3, + int fsb, int mem) { int i; struct cxsr_latency *latency; @@ -2686,6 +2699,7 @@ static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb, for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) { latency = &cxsr_latency_table[i]; if (is_desktop == latency->is_desktop && + is_ddr3 == latency->is_ddr3 && fsb == latency->fsb_freq && mem == latency->mem_freq) return latency; } @@ -2800,8 +2814,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, struct cxsr_latency *latency; int sr_clock; - latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->fsb_freq, - dev_priv->mem_freq); + latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, + dev_priv->fsb_freq, dev_priv->mem_freq); if (!latency) { DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); pineview_disable_cxsr(dev); @@ -5406,11 +5420,13 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_wm = NULL; } else if (IS_PINEVIEW(dev)) { if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev), + dev_priv->is_ddr3, dev_priv->fsb_freq, dev_priv->mem_freq)) { DRM_INFO("failed to find known CxSR latency " - "(found fsb freq %d, mem freq %d), " + "(found ddr%s fsb freq %d, mem freq %d), " "disabling CxSR\n", + (dev_priv->is_ddr3 == 1) ? "3": "2", dev_priv->fsb_freq, dev_priv->mem_freq); /* Disable CxSR and never update its watermark again */ pineview_disable_cxsr(dev); -- GitLab From e20f9c64c79e2282f9eb531509181965ec8f0a92 Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Wed, 26 May 2010 14:51:06 -0700 Subject: [PATCH 230/842] drm/i915: Clean up leftover bits from hws move to ring structure. Fixes /debug/dri/0/i915_gem_interrupt output for status page. Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +++--- drivers/gpu/drm/i915/i915_dma.c | 7 +++---- drivers/gpu/drm/i915/i915_drv.h | 3 --- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index eb11e1e049cb..52510ad8b25d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -144,7 +144,7 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - if (dev_priv->hw_status_page != NULL) { + if (dev_priv->render_ring.status_page.page_addr != NULL) { seq_printf(m, "Current sequence: %d\n", i915_get_gem_seqno(dev, &dev_priv->render_ring)); } else { @@ -196,7 +196,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) } seq_printf(m, "Interrupts received: %d\n", atomic_read(&dev_priv->irq_received)); - if (dev_priv->hw_status_page != NULL) { + if (dev_priv->render_ring.status_page.page_addr != NULL) { seq_printf(m, "Current sequence: %d\n", i915_get_gem_seqno(dev, &dev_priv->render_ring)); } else { @@ -252,7 +252,7 @@ static int i915_hws_info(struct seq_file *m, void *data) int i; volatile u32 *hws; - hws = (volatile u32 *)dev_priv->hw_status_page; + hws = (volatile u32 *)dev_priv->render_ring.status_page.page_addr; if (hws == NULL) return 0; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a5f401664845..6577798d3441 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -84,7 +84,6 @@ static void i915_free_hws(struct drm_device *dev) if (dev_priv->render_ring.status_page.gfx_addr) { dev_priv->render_ring.status_page.gfx_addr = 0; - dev_priv->status_gfx_addr = 0; drm_core_ioremapfree(&dev_priv->hws_map, dev); } @@ -828,7 +827,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, drm_core_ioremap_wc(&dev_priv->hws_map, dev); if (dev_priv->hws_map.handle == NULL) { i915_dma_cleanup(dev); - dev_priv->status_gfx_addr = 0; + ring->status_page.gfx_addr = 0; DRM_ERROR("can not ioremap virtual address for" " G33 hw status page\n"); return -ENOMEM; @@ -838,9 +837,9 @@ static int i915_set_status_page(struct drm_device *dev, void *data, I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n", - dev_priv->status_gfx_addr); + ring->status_page.gfx_addr); DRM_DEBUG_DRIVER("load hws at %p\n", - dev_priv->hw_status_page); + ring->status_page.page_addr); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e6b4cab6565f..9ed8ecd95801 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -238,14 +238,11 @@ typedef struct drm_i915_private { struct intel_ring_buffer bsd_ring; drm_dma_handle_t *status_page_dmah; - void *hw_status_page; void *seqno_page; dma_addr_t dma_status_page; uint32_t counter; - unsigned int status_gfx_addr; unsigned int seqno_gfx_addr; drm_local_map_t hws_map; - struct drm_gem_object *hws_obj; struct drm_gem_object *seqno_obj; struct drm_gem_object *pwrctx; -- GitLab From 138de1c44a8e0606501cd8593407e9248e84f1b7 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@arm.linux.org.uk> Date: Thu, 27 May 2010 08:23:29 +0100 Subject: [PATCH 231/842] ARM: VFP: Fix vfp_put_double() for d16-d31 vfp_put_double() takes the double value in r0,r1 not r1,r2. Reported-by: Tarun Kanti DebBarma <tarun.kanti@ti.com> Cc: <stable@kernel.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/vfp/vfphw.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 66dc2d03b7fc..d66cead97d28 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -277,7 +277,7 @@ ENTRY(vfp_put_double) #ifdef CONFIG_VFPv3 @ d16 - d31 registers .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 -1: mcrr p11, 3, r1, r2, c\dr @ fmdrr r1, r2, d\dr +1: mcrr p11, 3, r0, r1, c\dr @ fmdrr r0, r1, d\dr mov pc, lr .org 1b + 8 .endr -- GitLab From ea208f646c8fb91c39c852e952fc911e1ad045ab Mon Sep 17 00:00:00 2001 From: Linus Walleij <linus.walleij@stericsson.com> Date: Wed, 26 May 2010 07:37:57 +0100 Subject: [PATCH 232/842] ARM: 6144/1: TCM memory bug freeing bug This fixes a bug in mm/init.c when freeing the TCM compile memory, this was being referred to as a char * which is incorrect: this will dereference the pointer and feed in the value at the location instead of the address to it. Change it to a plain char and use &(char) to reference it. Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Cc: <stable@kernel.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/mm/init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 1ba6cf5a2c02..f6a999465323 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -678,10 +678,10 @@ void __init mem_init(void) void free_initmem(void) { #ifdef CONFIG_HAVE_TCM - extern char *__tcm_start, *__tcm_end; + extern char __tcm_start, __tcm_end; - totalram_pages += free_area(__phys_to_pfn(__pa(__tcm_start)), - __phys_to_pfn(__pa(__tcm_end)), + totalram_pages += free_area(__phys_to_pfn(__pa(&__tcm_start)), + __phys_to_pfn(__pa(&__tcm_end)), "TCM link"); #endif -- GitLab From ba327b1e5296b70745e50bcf0446ae8f82e3d478 Mon Sep 17 00:00:00 2001 From: Linus Walleij <linus.walleij@stericsson.com> Date: Wed, 26 May 2010 07:38:54 +0100 Subject: [PATCH 233/842] ARM: 6145/1: ux500 MTU clockrate correction This adjusts the clockrate for the MTU timer. On the different UX500 variants this rate is different. The platform can also have been set up at hardware initialization, bootloader or early init for different clock speeds. To have the clock framework available early so the timers can use them, the clock initialization for Nomadik and ux500 is moved to IRQ init time. A custom per-clock callback is added to handle special cases like this. This solves a user-visible bug: without this patch the current UX500 platforms will not be synchronized to wall-clock time and the platform will drift in time. Acked-by: Rabin Vincent <rabin.vincent@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/mach-nomadik/clock.c | 11 ++-- arch/arm/mach-nomadik/clock.h | 2 + arch/arm/mach-nomadik/cpu-8815.c | 8 +++ arch/arm/mach-ux500/clock.c | 104 +++++++++++++++++++++++++++++-- arch/arm/mach-ux500/clock.h | 22 +++++++ arch/arm/mach-ux500/cpu.c | 6 ++ arch/arm/plat-nomadik/timer.c | 26 +++++++- 7 files changed, 167 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-nomadik/clock.c b/arch/arm/mach-nomadik/clock.c index 2c471fc451d7..f035f4185274 100644 --- a/arch/arm/mach-nomadik/clock.c +++ b/arch/arm/mach-nomadik/clock.c @@ -32,7 +32,10 @@ void clk_disable(struct clk *clk) } EXPORT_SYMBOL(clk_disable); -/* We have a fixed clock alone, for now */ +static struct clk clk_24 = { + .rate = 2400000, +}; + static struct clk clk_48 = { .rate = 48 * 1000 * 1000, }; @@ -50,6 +53,8 @@ static struct clk clk_default; } static struct clk_lookup lookups[] = { + CLK(&clk_24, "mtu0"), + CLK(&clk_24, "mtu1"), CLK(&clk_48, "uart0"), CLK(&clk_48, "uart1"), CLK(&clk_default, "gpio.0"), @@ -59,10 +64,8 @@ static struct clk_lookup lookups[] = { CLK(&clk_default, "rng"), }; -static int __init clk_init(void) +int __init clk_init(void) { clkdev_add_table(lookups, ARRAY_SIZE(lookups)); return 0; } - -arch_initcall(clk_init); diff --git a/arch/arm/mach-nomadik/clock.h b/arch/arm/mach-nomadik/clock.h index 5563985a2cc7..78da2e7c3985 100644 --- a/arch/arm/mach-nomadik/clock.h +++ b/arch/arm/mach-nomadik/clock.h @@ -11,3 +11,5 @@ struct clk { unsigned long rate; }; + +int __init clk_init(void); diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c index 91c3c901b469..ac58e3b03b1a 100644 --- a/arch/arm/mach-nomadik/cpu-8815.c +++ b/arch/arm/mach-nomadik/cpu-8815.c @@ -31,6 +31,8 @@ #include <asm/cacheflush.h> #include <asm/hardware/cache-l2x0.h> +#include "clock.h" + #define __MEM_4K_RESOURCE(x) \ .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM} @@ -143,6 +145,12 @@ void __init cpu8815_init_irq(void) /* This modified VIC cell has two register blocks, at 0 and 0x20 */ vic_init(io_p2v(NOMADIK_IC_BASE + 0x00), IRQ_VIC_START + 0, ~0, 0); vic_init(io_p2v(NOMADIK_IC_BASE + 0x20), IRQ_VIC_START + 32, ~0, 0); + + /* + * Init clocks here so that they are available for system timer + * initialization. + */ + clk_init(); } /* diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 1b2c9890e8b4..b5fc2e21961d 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c @@ -16,6 +16,7 @@ #include <asm/clkdev.h> +#include <plat/mtu.h> #include <mach/hardware.h> #include "clock.h" @@ -59,6 +60,9 @@ #define PRCM_DMACLK_MGT 0x074 #define PRCM_B2R2CLK_MGT 0x078 #define PRCM_TVCLK_MGT 0x07C +#define PRCM_TCR 0x1C8 +#define PRCM_TCR_STOPPED (1 << 16) +#define PRCM_TCR_DOZE_MODE (1 << 17) #define PRCM_UNIPROCLK_MGT 0x278 #define PRCM_SSPCLK_MGT 0x280 #define PRCM_RNGCLK_MGT 0x284 @@ -120,10 +124,95 @@ void clk_disable(struct clk *clk) } EXPORT_SYMBOL(clk_disable); +/* + * The MTU has a separate, rather complex muxing setup + * with alternative parents (peripheral cluster or + * ULP or fixed 32768 Hz) depending on settings + */ +static unsigned long clk_mtu_get_rate(struct clk *clk) +{ + void __iomem *addr = __io_address(U8500_PRCMU_BASE) + + PRCM_TCR; + u32 tcr = readl(addr); + int mtu = (int) clk->data; + /* + * One of these is selected eventually + * TODO: Replace the constant with a reference + * to the ULP source once this is modeled. + */ + unsigned long clk32k = 32768; + unsigned long mturate; + unsigned long retclk; + + /* Get the rate from the parent as a default */ + if (clk->parent_periph) + mturate = clk_get_rate(clk->parent_periph); + else if (clk->parent_cluster) + mturate = clk_get_rate(clk->parent_cluster); + else + /* We need to be connected SOMEWHERE */ + BUG(); + + /* + * Are we in doze mode? + * In this mode the parent peripheral or the fixed 32768 Hz + * clock is fed into the block. + */ + if (!(tcr & PRCM_TCR_DOZE_MODE)) { + /* + * Here we're using the clock input from the APE ULP + * clock domain. But first: are the timers stopped? + */ + if (tcr & PRCM_TCR_STOPPED) { + clk32k = 0; + mturate = 0; + } else { + /* Else default mode: 0 and 2.4 MHz */ + clk32k = 0; + if (cpu_is_u5500()) + /* DB5500 divides by 8 */ + mturate /= 8; + else if (cpu_is_u8500ed()) { + /* + * This clocking setting must not be used + * in the ED chip, it is simply not + * connected anywhere! + */ + mturate = 0; + BUG(); + } else + /* + * In this mode the ulp38m4 clock is divided + * by a factor 16, on the DB8500 typically + * 38400000 / 16 ~ 2.4 MHz. + * TODO: Replace the constant with a reference + * to the ULP source once this is modeled. + */ + mturate = 38400000 / 16; + } + } + + /* Return the clock selected for this MTU */ + if (tcr & (1 << mtu)) + retclk = clk32k; + else + retclk = mturate; + + pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk); + return retclk; +} + unsigned long clk_get_rate(struct clk *clk) { unsigned long rate; + /* + * If there is a custom getrate callback for this clock, + * it will take precedence. + */ + if (clk->get_rate) + return clk->get_rate(clk); + if (clk->ops && clk->ops->get_rate) return clk->ops->get_rate(clk); @@ -341,8 +430,9 @@ static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL); /* Peripheral Cluster #6 */ -static DEFINE_PRCC_CLK(6, mtu1_v1, 8, -1, NULL); -static DEFINE_PRCC_CLK(6, mtu0_v1, 7, -1, NULL); +/* MTU ID in data */ +static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1); +static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0); static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); @@ -357,8 +447,9 @@ static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk); /* Peripheral Cluster #7 */ static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); -static DEFINE_PRCC_CLK(7, mtu1_ed, 3, -1, NULL); -static DEFINE_PRCC_CLK(7, mtu0_ed, 2, -1, NULL); +/* MTU ID in data */ +static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1); +static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0); static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); @@ -503,15 +594,17 @@ static struct clk_lookup u8500_v1_clks[] = { CLK(uiccclk, "uicc", NULL), }; -static int __init clk_init(void) +int __init clk_init(void) { if (cpu_is_u8500ed()) { clk_prcmu_ops.enable = clk_prcmu_ed_enable; clk_prcmu_ops.disable = clk_prcmu_ed_disable; + clk_per6clk.rate = 100000000; } else if (cpu_is_u5500()) { /* Clock tree for U5500 not implemented yet */ clk_prcc_ops.enable = clk_prcc_ops.disable = NULL; clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL; + clk_per6clk.rate = 26000000; } clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); @@ -522,4 +615,3 @@ static int __init clk_init(void) return 0; } -arch_initcall(clk_init); diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h index e4f99b65026f..a05802501527 100644 --- a/arch/arm/mach-ux500/clock.h +++ b/arch/arm/mach-ux500/clock.h @@ -28,6 +28,9 @@ struct clkops { * @ops: pointer to clkops struct used to control this clock * @name: name, for debugging * @enabled: refcount. positive if enabled, zero if disabled + * @get_rate: custom callback for getting the clock rate + * @data: custom per-clock data for example for the get_rate + * callback * @rate: fixed rate for clocks which don't implement * ops->getrate * @prcmu_cg_off: address offset of the combined enable/disable register @@ -67,6 +70,8 @@ struct clk { const struct clkops *ops; const char *name; unsigned int enabled; + unsigned long (*get_rate)(struct clk *); + void *data; unsigned long rate; struct list_head list; @@ -117,9 +122,26 @@ struct clk clk_##_name = { \ .parent_periph = _kernclk \ } +#define DEFINE_PRCC_CLK_CUSTOM(_pclust, _name, _bus_en, _kernel_en, _kernclk, _callback, _data) \ +struct clk clk_##_name = { \ + .name = #_name, \ + .ops = &clk_prcc_ops, \ + .cluster = _pclust, \ + .prcc_bus = _bus_en, \ + .prcc_kernel = _kernel_en, \ + .parent_cluster = &clk_per##_pclust##clk, \ + .parent_periph = _kernclk, \ + .get_rate = _callback, \ + .data = (void *) _data \ + } + + #define CLK(_clk, _devname, _conname) \ { \ .clk = &clk_##_clk, \ .dev_id = _devname, \ .con_id = _conname, \ } + +int __init clk_db8500_ed_fixup(void); +int __init clk_init(void); diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index d81ad023963c..e0fd747e447a 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -62,6 +62,12 @@ void __init ux500_init_irq(void) { gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29); gic_cpu_init(0, __io_address(UX500_GIC_CPU_BASE)); + + /* + * Init clocks here so that they are available for system timer + * initialization. + */ + clk_init(); } #ifdef CONFIG_CACHE_L2X0 diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c index 0ff3798769ab..08aaa4a7f65f 100644 --- a/arch/arm/plat-nomadik/timer.c +++ b/arch/arm/plat-nomadik/timer.c @@ -13,7 +13,9 @@ #include <linux/irq.h> #include <linux/io.h> #include <linux/clockchips.h> +#include <linux/clk.h> #include <linux/jiffies.h> +#include <linux/err.h> #include <asm/mach/time.h> #include <plat/mtu.h> @@ -124,13 +126,25 @@ static struct irqaction nmdk_timer_irq = { void __init nmdk_timer_init(void) { unsigned long rate; - u32 cr = MTU_CRn_32BITS;; + struct clk *clk0; + struct clk *clk1; + u32 cr; + + clk0 = clk_get_sys("mtu0", NULL); + BUG_ON(IS_ERR(clk0)); + + clk1 = clk_get_sys("mtu1", NULL); + BUG_ON(IS_ERR(clk1)); + + clk_enable(clk0); + clk_enable(clk1); /* * Tick rate is 2.4MHz for Nomadik and 110MHz for ux500: * use a divide-by-16 counter if it's more than 16MHz */ - rate = CLOCK_TICK_RATE; + cr = MTU_CRn_32BITS;; + rate = clk_get_rate(clk0); if (rate > 16 << 20) { rate /= 16; cr |= MTU_CRn_PRESCALE_16; @@ -153,6 +167,14 @@ void __init nmdk_timer_init(void) nmdk_clksrc.name); /* Timer 1 is used for events, fix according to rate */ + cr = MTU_CRn_32BITS; + rate = clk_get_rate(clk1); + if (rate > 16 << 20) { + rate /= 16; + cr |= MTU_CRn_PRESCALE_16; + } else { + cr |= MTU_CRn_PRESCALE_1; + } writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */ nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift); nmdk_clkevt.max_delta_ns = -- GitLab From 3defb2476166445982a90c12d33f8947e75476c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Va=C5=A1ut?= <marek.vasut@gmail.com> Date: Wed, 26 May 2010 23:53:09 +0100 Subject: [PATCH 234/842] ARM: 6146/1: sa1111: Prevent deadlock in resume path This patch reorganises the sa1111_resume() function in a manner the spinlock happens after calling the sa1111_wake(). This fixes two bugs: 1) This function called sa1111_wake() which tried to claim the same spinlock the sa1111_resume() already claimed. This would result in certain deadlock. Original idea for this part: Russell King <rmk+kernel@arm.linux.org.uk> 2) The function didn't unlock the spinlock in case the chip didn't report correct ID. Original idea for this part: Julia Lawall <julia@diku.dk> Signed-off-by: Marek Vasut <marek.vasut@gmail.com> Cc: <stable@kernel.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/common/sa1111.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index a52a27c1d9be..6f80665f477e 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -951,8 +951,6 @@ static int sa1111_resume(struct platform_device *dev) if (!save) return 0; - spin_lock_irqsave(&sachip->lock, flags); - /* * Ensure that the SA1111 is still here. * FIXME: shouldn't do this here. @@ -969,6 +967,13 @@ static int sa1111_resume(struct platform_device *dev) * First of all, wake up the chip. */ sa1111_wake(sachip); + + /* + * Only lock for write ops. Also, sa1111_wake must be called with + * released spinlock! + */ + spin_lock_irqsave(&sachip->lock, flags); + sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN0); sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN1); -- GitLab From 84fe6c19e4a598e8071e3bd1b2c923454eae1268 Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Thu, 27 May 2010 12:31:51 +0200 Subject: [PATCH 235/842] arch/x86/kernel: Add missing spin_unlock Add a spin_unlock missing on the error path. The locks and unlocks are balanced in other functions, so it seems that the same should be the case here. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @@ expression E1; @@ * spin_lock(E1,...); <+... when != E1 if (...) { ... when != E1 * return ...; } ...+> * spin_unlock(E1,...); // </smpl> Cc: stable@kernel.org Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> --- arch/x86/kernel/amd_iommu.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index fa5a1474cd18..8a9aaa8412c9 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1487,6 +1487,7 @@ static int __attach_device(struct device *dev, struct protection_domain *domain) { struct iommu_dev_data *dev_data, *alias_data; + int ret; dev_data = get_dev_data(dev); alias_data = get_dev_data(dev_data->alias); @@ -1498,13 +1499,14 @@ static int __attach_device(struct device *dev, spin_lock(&domain->lock); /* Some sanity checks */ + ret = -EBUSY; if (alias_data->domain != NULL && alias_data->domain != domain) - return -EBUSY; + goto out_unlock; if (dev_data->domain != NULL && dev_data->domain != domain) - return -EBUSY; + goto out_unlock; /* Do real assignment */ if (dev_data->alias != dev) { @@ -1520,10 +1522,14 @@ static int __attach_device(struct device *dev, atomic_inc(&dev_data->bind); + ret = 0; + +out_unlock: + /* ready */ spin_unlock(&domain->lock); - return 0; + return ret; } /* -- GitLab From 64ffc9ff424c65adcffe7d590018cc75e2d5d42a Mon Sep 17 00:00:00 2001 From: Michal Marek <mmarek@suse.cz> Date: Thu, 27 May 2010 16:07:37 +0200 Subject: [PATCH 236/842] kbuild: Revert part of e8d400a to resolve a conflict A more complete patch in the kernel-doc tree also contains this change. Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Documentation/kbuild/makefiles.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 01351554df60..71c602d61680 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -320,7 +320,7 @@ more details, with real examples. subdir-ccflags-y, subdir-asflags-y The two flags listed above are similar to ccflags-y and as-falgs-y. The difference is that the subdir- variants has effect for the kbuild - file where they are present and all subdirectories. + file where tey are present and all subdirectories. Options specified using subdir-* are added to the commandline before the options specified using the non-subdir variants. -- GitLab From b334f2b3b68c35fd86a0cbc90ecee40e63ba2f37 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis <madman2003@gmail.com> Date: Sun, 9 May 2010 14:49:52 +0200 Subject: [PATCH 237/842] drm/nouveau: allow cursor image and position to survive suspend - This isn't triggered yet on a normal kernel, because it still does a VT switch, but it seemed like a good idea to fix this now. Tested-by: Maxim Levitsky <maximlevitsky@gmail.com> Signed-off-by: Maarten Maathuis <madman2003@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_crtc.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_drv.c | 29 ++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nv04_cursor.c | 1 + drivers/gpu/drm/nouveau/nv50_cursor.c | 1 + 4 files changed, 33 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h index 49fa7b2d257e..cb1ce2a09162 100644 --- a/drivers/gpu/drm/nouveau/nouveau_crtc.h +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h @@ -40,6 +40,8 @@ struct nouveau_crtc { int sharpness; int last_dpms; + int cursor_saved_x, cursor_saved_y; + struct { int cpp; bool blanked; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index c6079e36669d..273770432298 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -175,6 +175,13 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) nouveau_bo_unpin(nouveau_fb->nvbo); } + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + + nouveau_bo_unmap(nv_crtc->cursor.nvbo); + nouveau_bo_unpin(nv_crtc->cursor.nvbo); + } + NV_INFO(dev, "Evicting buffers...\n"); ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); @@ -314,12 +321,34 @@ nouveau_pci_resume(struct pci_dev *pdev) nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM); } + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + int ret; + + ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); + if (!ret) + ret = nouveau_bo_map(nv_crtc->cursor.nvbo); + if (ret) + NV_ERROR(dev, "Could not pin/map cursor.\n"); + } + if (dev_priv->card_type < NV_50) { nv04_display_restore(dev); NVLockVgaCrtcs(dev, false); } else nv50_display_init(dev); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + + nv_crtc->cursor.set_offset(nv_crtc, + nv_crtc->cursor.nvbo->bo.offset - + dev_priv->vm_vram_base); + + nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x, + nv_crtc->cursor_saved_y); + } + /* Force CLUT to get re-loaded during modeset */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); diff --git a/drivers/gpu/drm/nouveau/nv04_cursor.c b/drivers/gpu/drm/nouveau/nv04_cursor.c index 89a91b9d8b25..aaf3de3bc816 100644 --- a/drivers/gpu/drm/nouveau/nv04_cursor.c +++ b/drivers/gpu/drm/nouveau/nv04_cursor.c @@ -20,6 +20,7 @@ nv04_cursor_hide(struct nouveau_crtc *nv_crtc, bool update) static void nv04_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y) { + nv_crtc->cursor_saved_x = x; nv_crtc->cursor_saved_y = y; NVWriteRAMDAC(nv_crtc->base.dev, nv_crtc->index, NV_PRAMDAC_CU_START_POS, XLATE(y, 0, NV_PRAMDAC_CU_START_POS_Y) | diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c index 753e723adb3a..03ad7ab14f09 100644 --- a/drivers/gpu/drm/nouveau/nv50_cursor.c +++ b/drivers/gpu/drm/nouveau/nv50_cursor.c @@ -107,6 +107,7 @@ nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y) { struct drm_device *dev = nv_crtc->base.dev; + nv_crtc->cursor_saved_x = x; nv_crtc->cursor_saved_y = y; nv_wr32(dev, NV50_PDISPLAY_CURSOR_USER_POS(nv_crtc->index), ((y & 0xFFFF) << 16) | (x & 0xFFFF)); /* Needed to make the cursor move. */ -- GitLab From 7fc74f17e6c9b4d86371c3a947afc32bd6bc9691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= <koriakin@0x04.net> Date: Sun, 23 May 2010 11:36:04 +0000 Subject: [PATCH 238/842] drm/nouveau: Add getparam for current PTIMER time. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be useful for computing GPU-CPU latency, including GL_ARB_timer_query extension. Signed-off-by: Marcin KoÅ›cielnicki <koriakin@0x04.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_state.c | 3 +++ include/drm/nouveau_drm.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index e632339c323e..a2544ffd02cc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -913,6 +913,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, case NOUVEAU_GETPARAM_VM_VRAM_BASE: getparam->value = dev_priv->vm_vram_base; break; + case NOUVEAU_GETPARAM_PTIMER_TIME: + getparam->value = dev_priv->engine.timer.read(dev); + break; case NOUVEAU_GETPARAM_GRAPH_UNITS: /* NV40 and NV50 versions are quite different, but register * address is the same. User is supposed to know the card diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h index a6a9f4af5ebd..fe917dee723a 100644 --- a/include/drm/nouveau_drm.h +++ b/include/drm/nouveau_drm.h @@ -79,6 +79,7 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_GETPARAM_CHIPSET_ID 11 #define NOUVEAU_GETPARAM_VM_VRAM_BASE 12 #define NOUVEAU_GETPARAM_GRAPH_UNITS 13 +#define NOUVEAU_GETPARAM_PTIMER_TIME 14 struct drm_nouveau_getparam { uint64_t param; uint64_t value; -- GitLab From d13102c6b4836289138431e3fbfc08e90c925ffd Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Tue, 25 May 2010 13:47:16 +1000 Subject: [PATCH 239/842] drm/nouveau: fix POST detection for certain chipsets We totally fail at detecting un-POSTed chipsets prior to G80. This commit changes the pre-G80 POST detection to read the programmed horizontal total from CRTC 0, and assume the card isn't POSTed if it's 0. NVIDIA use some other heuristics more similar to what we do on G80, but I wasted quite a long time trying to figure out the exact specifics of what they do so we can try this for a bit instead. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_bios.c | 28 +++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e7e69ccce5c9..61d932261356 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6205,6 +6205,30 @@ nouveau_bios_i2c_devices_takedown(struct drm_device *dev) nouveau_i2c_fini(dev, entry); } +static bool +nouveau_bios_posted(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + bool was_locked; + unsigned htotal; + + if (dev_priv->chipset >= NV_50) { + if (NVReadVgaCrtc(dev, 0, 0x00) == 0 && + NVReadVgaCrtc(dev, 0, 0x1a) == 0) + return false; + return true; + } + + was_locked = NVLockVgaCrtcs(dev, false); + htotal = NVReadVgaCrtc(dev, 0, 0x06); + htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8; + htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4; + htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10; + htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11; + NVLockVgaCrtcs(dev, was_locked); + return (htotal != 0); +} + int nouveau_bios_init(struct drm_device *dev) { @@ -6239,9 +6263,7 @@ nouveau_bios_init(struct drm_device *dev) bios->execute = false; /* ... unless card isn't POSTed already */ - if (dev_priv->card_type >= NV_10 && - NVReadVgaCrtc(dev, 0, 0x00) == 0 && - NVReadVgaCrtc(dev, 0, 0x1a) == 0) { + if (!nouveau_bios_posted(dev)) { NV_INFO(dev, "Adaptor not initialised\n"); if (dev_priv->card_type < NV_50) { NV_ERROR(dev, "Unable to POST this chipset\n"); -- GitLab From f50c0b91e7718e7deda46475cfd0ea1413daed04 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Tue, 25 May 2010 13:48:07 +1000 Subject: [PATCH 240/842] drm/nv40: allow cold-booting of nv4x chipsets Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_bios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 61d932261356..620cbd9767cc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6265,7 +6265,7 @@ nouveau_bios_init(struct drm_device *dev) /* ... unless card isn't POSTed already */ if (!nouveau_bios_posted(dev)) { NV_INFO(dev, "Adaptor not initialised\n"); - if (dev_priv->card_type < NV_50) { + if (dev_priv->card_type < NV_40) { NV_ERROR(dev, "Unable to POST this chipset\n"); return -ENODEV; } -- GitLab From 73db4bedc5dde97adf59b5b5a07c6cf0ee56e668 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Wed, 26 May 2010 10:41:45 +1000 Subject: [PATCH 241/842] drm/nouveau: don't execute INIT_GPIO unless we're really running the table This resulted in accidently switching off the eDP panel on certain laptops since the default state in the GPIO table was off. Fixes rh#582621 Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_bios.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 620cbd9767cc..b3c7a87e47d9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2807,7 +2807,10 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry); - nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default); + BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n", + offset, gpio->tag, gpio->state_default); + if (bios->execute) + nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default); /* The NVIDIA binary driver doesn't appear to actually do * any of this, my VBIOS does however. -- GitLab From 23484874e6bf837704bf1fa61605d33a12b174e3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Fri, 28 May 2010 09:39:11 +1000 Subject: [PATCH 242/842] drm/nv50: fix duallink_possible calculation for DCB 4.0 cards Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_bios.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index b3c7a87e47d9..9f30fb8eafe8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5536,12 +5536,6 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, entry->bus = (conn >> 16) & 0xf; entry->location = (conn >> 20) & 0x3; entry->or = (conn >> 24) & 0xf; - /* - * Normal entries consist of a single bit, but dual link has the - * next most significant bit set too - */ - entry->duallink_possible = - ((1 << (ffs(entry->or) - 1)) * 3 == entry->or); switch (entry->type) { case OUTPUT_ANALOG: @@ -5625,6 +5619,16 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, break; } + if (dcb->version < 0x40) { + /* Normal entries consist of a single bit, but dual link has + * the next most significant bit set too + */ + entry->duallink_possible = + ((1 << (ffs(entry->or) - 1)) * 3 == entry->or); + } else { + entry->duallink_possible = (entry->sorconf.link == 3); + } + /* unsure what DCB version introduces this, 3.0? */ if (conf & 0x100000) entry->i2c_upper_default = true; -- GitLab From 2c58077541cc6859a9a9046d9c3a4d61bdbd4f18 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Fri, 28 May 2010 10:04:05 +1000 Subject: [PATCH 243/842] drm/nv50: obey dcb->duallink_possible It was once assumed that all G8x had dual-link TMDS everywhere, this isn't actually the case - especially considering passive DP->DVI converters and some HDMI connectors only support single-link. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_connector.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 7e663a79829f..bfa65629517b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -593,8 +593,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, break; case OUTPUT_TMDS: if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) || - (dev_priv->card_type < NV_50 && - !nv_encoder->dcb->duallink_possible)) + !nv_encoder->dcb->duallink_possible) max_clock = 165000; else max_clock = 330000; -- GitLab From 26099a74805eaf79f3058cc4097ebaa8cc55122c Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Fri, 28 May 2010 10:13:16 +1000 Subject: [PATCH 244/842] drm/nouveau: fix dual-link displays when plugged into single-link outputs When selecting the native mode for a display we weren't taking into account whether or not it was actually supported on that particular output. This patch modifies our native mode selection to run all modes through mode_valid() first. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_connector.c | 31 +++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index bfa65629517b..256e82bd91dd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -431,24 +431,27 @@ nouveau_connector_set_property(struct drm_connector *connector, } static struct drm_display_mode * -nouveau_connector_native_mode(struct nouveau_connector *connector) +nouveau_connector_native_mode(struct drm_connector *connector) { - struct drm_device *dev = connector->base.dev; + struct drm_connector_helper_funcs *helper = connector->helper_private; + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct drm_device *dev = connector->dev; struct drm_display_mode *mode, *largest = NULL; int high_w = 0, high_h = 0, high_v = 0; - /* Use preferred mode if there is one.. */ - list_for_each_entry(mode, &connector->base.probed_modes, head) { + list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { + if (helper->mode_valid(connector, mode) != MODE_OK) + continue; + + /* Use preferred mode if there is one.. */ if (mode->type & DRM_MODE_TYPE_PREFERRED) { NV_DEBUG_KMS(dev, "native mode from preferred\n"); return drm_mode_duplicate(dev, mode); } - } - /* Otherwise, take the resolution with the largest width, then height, - * then vertical refresh - */ - list_for_each_entry(mode, &connector->base.probed_modes, head) { + /* Otherwise, take the resolution with the largest width, then + * height, then vertical refresh + */ if (mode->hdisplay < high_w) continue; @@ -552,7 +555,7 @@ nouveau_connector_get_modes(struct drm_connector *connector) */ if (!nv_connector->native_mode) nv_connector->native_mode = - nouveau_connector_native_mode(nv_connector); + nouveau_connector_native_mode(connector); if (ret == 0 && nv_connector->native_mode) { struct drm_display_mode *mode; @@ -583,9 +586,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector, switch (nv_encoder->dcb->type) { case OUTPUT_LVDS: - BUG_ON(!nv_connector->native_mode); - if (mode->hdisplay > nv_connector->native_mode->hdisplay || - mode->vdisplay > nv_connector->native_mode->vdisplay) + if (nv_connector->native_mode && + (mode->hdisplay > nv_connector->native_mode->hdisplay || + mode->vdisplay > nv_connector->native_mode->vdisplay)) return MODE_PANEL; min_clock = 0; @@ -727,7 +730,7 @@ nouveau_connector_create_lvds(struct drm_device *dev, if (ret == 0) goto out; nv_connector->detected_encoder = nv_encoder; - nv_connector->native_mode = nouveau_connector_native_mode(nv_connector); + nv_connector->native_mode = nouveau_connector_native_mode(connector); list_for_each_entry_safe(mode, temp, &connector->probed_modes, head) drm_mode_remove(connector, mode); -- GitLab From becd214277ed41dc6f745f5f8db39d84c6c7ffc8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Sat, 29 May 2010 03:06:14 +1000 Subject: [PATCH 245/842] drm/nv50: use alternate source of SOR_MODE_CTRL for DP hack Fixes module unload+reload on Dell M4500, where the "normal" registers get reset to 0. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nv50_sor.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c index b11eaf9c5c7c..812778db76ac 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c @@ -274,7 +274,6 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = { int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) { - struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_encoder *nv_encoder = NULL; struct drm_encoder *encoder; bool dum; @@ -324,11 +323,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1); uint32_t tmp; - if (dev_priv->chipset < 0x90 || - dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0) - tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or)); - else - tmp = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or)); + tmp = nv_rd32(dev, 0x61c700 + (or * 0x800)); switch ((tmp & 0x00000f00) >> 8) { case 8: -- GitLab From 9be8ab2ea81f84c1726d79613c342141f5d19a3b Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" <justinmattock@gmail.com> Date: Wed, 26 May 2010 11:00:04 -0700 Subject: [PATCH 246/842] ath9k: Fix ath_print in xmit for hardware reset. ath_print in xmit.c should say "Reseting hardware" instead of Resetting HAL!(since HAL is being fazed out). dmesg shows: [ 8660.899624] ath: Failed to stop TX DMA in 100 msec after killing last frame [ 8660.899676] ath: Unable to stop TxDMA. Reset HAL! Signed-off-by: Justin P. Mattock <justinmattock@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3db19172b43b..09cb13c4854c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1198,7 +1198,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) int r; ath_print(common, ATH_DBG_FATAL, - "Unable to stop TxDMA. Reset HAL!\n"); + "Failed to stop TX DMA. Resetting hardware!\n"); spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); -- GitLab From 35aed2e6be2feaa227fe5c7a0b7c286c4fe71592 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:12 +0100 Subject: [PATCH 247/842] drm/i915: Only print an message if there was an error Only report an error if the GPU has actually detected one, otherwise we are just hung. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_irq.c | 38 +++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b5dba4795f6f..2479be001e40 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -692,24 +692,13 @@ void i915_destroy_error_state(struct drm_device *dev) i915_error_state_free(dev, error); } -/** - * i915_handle_error - handle an error interrupt - * @dev: drm device - * - * Do some basic checking of regsiter state at error interrupt time and - * dump it to the syslog. Also call i915_capture_error_state() to make - * sure we get a record and make it available in debugfs. Fire a uevent - * so userspace knows something bad happened (should trigger collection - * of a ring dump etc.). - */ -static void i915_handle_error(struct drm_device *dev, bool wedged) +static void i915_report_and_clear_eir(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 eir = I915_READ(EIR); - u32 pipea_stats = I915_READ(PIPEASTAT); - u32 pipeb_stats = I915_READ(PIPEBSTAT); - i915_capture_error_state(dev); + if (!eir) + return; printk(KERN_ERR "render error detected, EIR: 0x%08x\n", eir); @@ -755,6 +744,9 @@ static void i915_handle_error(struct drm_device *dev, bool wedged) } if (eir & I915_ERROR_MEMORY_REFRESH) { + u32 pipea_stats = I915_READ(PIPEASTAT); + u32 pipeb_stats = I915_READ(PIPEBSTAT); + printk(KERN_ERR "memory refresh error\n"); printk(KERN_ERR "PIPEASTAT: 0x%08x\n", pipea_stats); @@ -811,6 +803,24 @@ static void i915_handle_error(struct drm_device *dev, bool wedged) I915_WRITE(EMR, I915_READ(EMR) | eir); I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); } +} + +/** + * i915_handle_error - handle an error interrupt + * @dev: drm device + * + * Do some basic checking of regsiter state at error interrupt time and + * dump it to the syslog. Also call i915_capture_error_state() to make + * sure we get a record and make it available in debugfs. Fire a uevent + * so userspace knows something bad happened (should trigger collection + * of a ring dump etc.). + */ +static void i915_handle_error(struct drm_device *dev, bool wedged) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + i915_capture_error_state(dev); + i915_report_and_clear_eir(dev); if (wedged) { atomic_set(&dev_priv->mm.wedged, 1); -- GitLab From 7c9fd60f9764373414c0a64f500a78635b0a0a7b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan <vasanth@atheros.com> Date: Wed, 26 May 2010 19:06:53 -0700 Subject: [PATCH 248/842] ath9k: Fix bug in the way "bf_tx_aborted" of struct ath_buf is used This bug was introduced by the following commit Author: Vasanthakumar Thiagarajan <vasanth@atheros.com> Date: Thu Apr 15 17:38:46 2010 -0400 ath9k: Remove ATH9K_TX_SW_ABORTED and introduce a bool for this purpose Wrong buffer is checked for bf_tx_aborted field in ath_tx_num_badfrms(), this may result in a rate scaling with wrong feedback (number of unacked frames in this case). It is the last one in the chain of buffers for an aggregate frame that should be checked. Also it misses the initialization of this field in the buffer, this may lead to a situation where we stop the sw retransmission of failed subframes associated to this buffer. Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/ath/ath9k/xmit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 09cb13c4854c..859aa4ab0769 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1728,6 +1728,8 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, } else bf->bf_isnullfunc = false; + bf->bf_tx_aborted = false; + return 0; } @@ -1989,7 +1991,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, int nbad = 0; int isaggr = 0; - if (bf->bf_tx_aborted) + if (bf->bf_lastbf->bf_tx_aborted) return 0; isaggr = bf_isaggr(bf); -- GitLab From 468f0b44ce4b002ca7d9260f802a341854752c02 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:13 +0100 Subject: [PATCH 249/842] drm/i915: Hold the spinlock whilst resetting unpin_work along error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delay taking the mutex until we need to and ensure that we hold the spinlock when resetting unpin_work on the error path. Also defer the debugging print messages until after we have released the spinlock. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Jesse Barnes <jbarnes@virtuousgeek.org> Cc: Kristian Høgsberg <krh@bitplanet.net> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cfac4dd1d483..1845a068cca5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4667,8 +4667,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (work == NULL) return -ENOMEM; - mutex_lock(&dev->struct_mutex); - work->event = event; work->dev = crtc->dev; intel_fb = to_intel_framebuffer(crtc->fb); @@ -4678,10 +4676,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, /* We borrow the event spin lock for protecting unpin_work */ spin_lock_irqsave(&dev->event_lock, flags); if (intel_crtc->unpin_work) { - DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); spin_unlock_irqrestore(&dev->event_lock, flags); kfree(work); - mutex_unlock(&dev->struct_mutex); + + DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); return -EBUSY; } intel_crtc->unpin_work = work; @@ -4690,13 +4688,19 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; + mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(dev, obj); if (ret != 0) { - DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n", - to_intel_bo(obj)); - kfree(work); - intel_crtc->unpin_work = NULL; mutex_unlock(&dev->struct_mutex); + + spin_lock_irqsave(&dev->event_lock, flags); + intel_crtc->unpin_work = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + kfree(work); + + DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n", + to_intel_bo(obj)); return ret; } -- GitLab From c6a6368b32aa4fd145e840c8d8dac6923fae2688 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava <prarit@redhat.com> Date: Thu, 27 May 2010 14:41:20 -0400 Subject: [PATCH 250/842] libertas: fix uninitialized variable warning Fixes: drivers/net/wireless/libertas/rx.c: In function process_rxed_802_11_packet: drivers/net/wireless/libertas/rx.c:354: error: radiotap_hdr.flags may be used uninitialized in this function Signed-off-by: Prarit Bhargava <prarit@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/libertas/rx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index a115bfa9513a..7a377f5b7662 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -329,9 +329,8 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, /* create the exported radio header */ /* radiotap header */ - radiotap_hdr.hdr.it_version = 0; - /* XXX must check this value for pad */ - radiotap_hdr.hdr.it_pad = 0; + memset(&radiotap_hdr, 0, sizeof(radiotap_hdr)); + /* XXX must check radiotap_hdr.hdr.it_pad for pad */ radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); -- GitLab From 368a07d26ae99c80678a968946744fd83e7708d0 Mon Sep 17 00:00:00 2001 From: Johannes Berg <johannes@sipsolutions.net> Date: Fri, 28 May 2010 14:26:23 +0200 Subject: [PATCH 251/842] mac80211: make a function static sparse correctly complains that __ieee80211_get_channel_mode is not static. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- net/mac80211/chan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 5d218c530a4e..32be11e4c4d9 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -5,7 +5,7 @@ #include <linux/nl80211.h> #include "ieee80211_i.h" -enum ieee80211_chan_mode +static enum ieee80211_chan_mode __ieee80211_get_channel_mode(struct ieee80211_local *local, struct ieee80211_sub_if_data *ignore) { -- GitLab From b118c1e363befe3d74469f4a014ce6353097f08a Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:14 +0100 Subject: [PATCH 252/842] drm/i915: Avoid nesting of domain changes when setting display plane Nesting domain changes will cause confusion when trying to interpret the tracepoints describing the sequence of changes for the object, as well as obscuring the order of operations for the reader of the code. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_gem.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index bf703551343a..1c65f0b591fc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2914,18 +2914,16 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) return ret; } + i915_gem_object_flush_cpu_write_domain(obj); + old_write_domain = obj->write_domain; old_read_domains = obj->read_domains; - obj->read_domains &= I915_GEM_DOMAIN_GTT; - - i915_gem_object_flush_cpu_write_domain(obj); - /* It should now be out of any other write domains, and we can update * the domain values for our changes. */ BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0); - obj->read_domains |= I915_GEM_DOMAIN_GTT; + obj->read_domains = I915_GEM_DOMAIN_GTT; obj->write_domain = I915_GEM_DOMAIN_GTT; obj_priv->dirty = 1; -- GitLab From 808b24d6ed8b155aac17007788390ebfde263f30 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:15 +0100 Subject: [PATCH 253/842] drm/i915: Propagate error from unbinding an unfenceable object. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Jesse Barnes <jbarnes@virtuousgeek.org> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_gem.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1c65f0b591fc..6425c2a4b11f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3307,9 +3307,13 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, obj_priv->tiling_mode != I915_TILING_NONE; /* Check fence reg constraints and rebind if necessary */ - if (need_fence && !i915_gem_object_fence_offset_ok(obj, - obj_priv->tiling_mode)) - i915_gem_object_unbind(obj); + if (need_fence && + !i915_gem_object_fence_offset_ok(obj, + obj_priv->tiling_mode)) { + ret = i915_gem_object_unbind(obj); + if (ret) + return ret; + } /* Choose the GTT offset for our buffer and put it there. */ ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment); -- GitLab From a939406fda8ddc7de69ee9186356d09dc6daaa2c Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:16 +0100 Subject: [PATCH 254/842] drm/i915: Only print "nothing to do" debug message as required. If the FBC is already disabled, then we do not even attempt to disable FBC and so there is no point emitting a debug statement at that point, having already emitted one saying why we are disabling FBC. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1845a068cca5..e504fdb4ae31 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1248,10 +1248,11 @@ static void intel_update_fbc(struct drm_crtc *crtc, return; out_disable: - DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); /* Multiple disables should be harmless */ - if (intel_fbc_enabled(dev)) + if (intel_fbc_enabled(dev)) { + DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); intel_disable_fbc(dev); + } } static int -- GitLab From a7faf32d00529b9c501e37a31d4bf8acef4f8f59 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:17 +0100 Subject: [PATCH 255/842] drm/i915: Include pitch in set_base debug statement. Add the pitch that we about to write into the control register along with the base, offset and coordinates that go into the other control registers. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e504fdb4ae31..88a1ab7c05ce 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1396,7 +1396,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, Start = obj_priv->gtt_offset; Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); - DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); + DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", + Start, Offset, x, y, crtc->fb->pitch); I915_WRITE(dspstride, crtc->fb->pitch); if (IS_I965G(dev)) { I915_WRITE(dspbase, Offset); -- GitLab From ac0c6b5ad3b3b513e1057806d4b7627fcc0ecc27 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:18 +0100 Subject: [PATCH 256/842] drm/i915: Rebind bo if currently bound with incorrect alignment. Whilst pinning the buffer, check that that its current alignment matches the requested alignment. If it does not, rebind. This should clear up any final render errors whilst resuming, for reference: Bug 27070 - [i915] Page table errors with empty ringbuffer https://bugs.freedesktop.org/show_bug.cgi?id=27070 Bug 15502 - render error detected, EIR: 0x00000010 https://bugzilla.kernel.org/show_bug.cgi?id=15502 Bug 13844 - i915 error: "render error detected" https://bugzilla.kernel.org/show_bug.cgi?id=13844 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@kernel.org Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_gem.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6425c2a4b11f..a5ca9599b232 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4164,6 +4164,17 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT); i915_verify_inactive(dev, __FILE__, __LINE__); + + if (obj_priv->gtt_space != NULL) { + if (alignment == 0) + alignment = i915_gem_get_gtt_alignment(obj); + if (obj_priv->gtt_offset & (alignment - 1)) { + ret = i915_gem_object_unbind(obj); + if (ret) + return ret; + } + } + if (obj_priv->gtt_space == NULL) { ret = i915_gem_object_bind_to_gtt(obj, alignment); if (ret) -- GitLab From 3d1cc47037f36004b10681d3436ef0942ebb279b Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:19 +0100 Subject: [PATCH 257/842] drm/i915: Remove spurious warning "Failure to install fence" This particular warning is harmless as we emit during the normal pinning process where the batch buffer requires more fences than is available without eviction. Only if we fail to evict enough fences does this become a problem, so include the requested number of fences in the ultimate *error* message. v2: Remember to compile test even trial patches to remove warnings. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_gem.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a5ca9599b232..b87945db1021 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3327,9 +3327,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, if (need_fence) { ret = i915_gem_object_get_fence_reg(obj); if (ret != 0) { - if (ret != -EBUSY && ret != -ERESTARTSYS) - DRM_ERROR("Failure to install fence: %d\n", - ret); i915_gem_object_unpin(obj); return ret; } @@ -3815,11 +3812,19 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret != -ENOSPC || pin_tries >= 1) { if (ret != -ERESTARTSYS) { unsigned long long total_size = 0; - for (i = 0; i < args->buffer_count; i++) + int num_fences = 0; + for (i = 0; i < args->buffer_count; i++) { + obj_priv = object_list[i]->driver_private; + total_size += object_list[i]->size; - DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes: %d\n", + num_fences += + exec_list[i].flags & EXEC_OBJECT_NEEDS_FENCE && + obj_priv->tiling_mode != I915_TILING_NONE; + } + DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes, %d fences: %d\n", pinned+1, args->buffer_count, - total_size, ret); + total_size, num_fences, + ret); DRM_ERROR("%d objects [%d pinned], " "%d object bytes [%d pinned], " "%d/%d gtt bytes\n", -- GitLab From 85cd4612fdab4e837d7eea048a697c75d0477d3b Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:20 +0100 Subject: [PATCH 258/842] drm/i915: Check error code whilst moving buffer to GTT domain. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_fb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 6f53cf7fbc50..f8c76e64bb77 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -105,7 +105,11 @@ static int intelfb_create(struct intel_fbdev *ifbdev, } /* Flush everything out, we'll be doing GTT only from now on */ - i915_gem_object_set_to_gtt_domain(fbo, 1); + ret = i915_gem_object_set_to_gtt_domain(fbo, 1); + if (ret) { + DRM_ERROR("failed to bind fb: %d.\n", ret); + goto out_unpin; + } info = framebuffer_alloc(0, device); if (!info) { -- GitLab From 654fc6073f68efa3b6c466825749e73e7fbb92cd Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:21 +0100 Subject: [PATCH 259/842] drm/i915: Reject bind_to_gtt() early if object > aperture If the object is bigger than the entire aperture, reject it early before evicting everything in a vain attempt to find space. v2: Use E2BIG as suggested by Owain G. Ainsworth. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@kernel.org Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_gem.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b87945db1021..f84c8e982dcb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2648,6 +2648,14 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) return -EINVAL; } + /* If the object is bigger than the entire aperture, reject it early + * before evicting everything in a vain attempt to find space. + */ + if (obj->size > dev->gtt_total) { + DRM_ERROR("Attempting to bind an object larger than the aperture\n"); + return -E2BIG; + } + search_free: free_space = drm_mm_search_free(&dev_priv->mm.gtt_space, obj->size, alignment, 0); -- GitLab From da1fdb02d9200ff28b6f3a380d21930335fe5429 Mon Sep 17 00:00:00 2001 From: Christoph Fritz <chf.fritz@googlemail.com> Date: Fri, 28 May 2010 10:45:59 +0200 Subject: [PATCH 260/842] ssb: fix NULL ptr deref when pcihost_wrapper is used Ethernet driver b44 does register ssb by it's pcihost_wrapper and doesn't set ssb_chipcommon. A check on this value introduced with commit d53cdbb94a52a920d5420ed64d986c3523a56743 and ea2db495f92ad2cf3301623e60cb95b4062bc484 triggers: BUG: unable to handle kernel NULL pointer dereference at 00000010 IP: [<c1266c36>] ssb_is_sprom_available+0x16/0x30 Signed-off-by: Christoph Fritz <chf.fritz@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/ssb/pci.c | 9 ++++++--- drivers/ssb/sprom.c | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 989e2752cc36..6dcda86be6eb 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -625,9 +625,12 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, ssb_printk(KERN_ERR PFX "No SPROM available!\n"); return -ENODEV; } - - bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ? - SSB_SPROM_BASE1 : SSB_SPROM_BASE31; + if (bus->chipco.dev) { /* can be unavailible! */ + bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ? + SSB_SPROM_BASE1 : SSB_SPROM_BASE31; + } else { + bus->sprom_offset = SSB_SPROM_BASE1; + } buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); if (!buf) diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c index 007bc3a03486..4f7cc8d13277 100644 --- a/drivers/ssb/sprom.c +++ b/drivers/ssb/sprom.c @@ -185,6 +185,7 @@ bool ssb_is_sprom_available(struct ssb_bus *bus) /* this routine differs from specs as we do not access SPROM directly on PCMCIA */ if (bus->bustype == SSB_BUSTYPE_PCI && + bus->chipco.dev && /* can be unavailible! */ bus->chipco.dev->id.revision >= 31) return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM; -- GitLab From 68f95ba9e260516411411524c45263b5d53f393c Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 13:18:22 +0100 Subject: [PATCH 261/842] drm/i915: Cleanup after failed initialization of ringbuffers The callers expect us to cleanup any partially initialised structures before reporting the error. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_gem.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f84c8e982dcb..42866c01540d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4632,23 +4632,40 @@ i915_gem_init_ringbuffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; int ret; + dev_priv->render_ring = render_ring; + if (!I915_NEED_GFX_HWS(dev)) { dev_priv->render_ring.status_page.page_addr = dev_priv->status_page_dmah->vaddr; memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE); } + if (HAS_PIPE_CONTROL(dev)) { ret = i915_gem_init_pipe_control(dev); if (ret) return ret; } + ret = intel_init_ring_buffer(dev, &dev_priv->render_ring); - if (!ret && HAS_BSD(dev)) { + if (ret) + goto cleanup_pipe_control; + + if (HAS_BSD(dev)) { dev_priv->bsd_ring = bsd_ring; ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring); + if (ret) + goto cleanup_render_ring; } + + return 0; + +cleanup_render_ring: + intel_cleanup_ring_buffer(dev, &dev_priv->render_ring); +cleanup_pipe_control: + if (HAS_PIPE_CONTROL(dev)) + i915_gem_cleanup_pipe_control(dev); return ret; } -- GitLab From 9b8c4a0b215e603497daebe8ecbc9b1f0f035808 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 14:21:01 +0100 Subject: [PATCH 262/842] drm/i915: Avoid moving from CPU domain during pwrite We can avoid an early clflush when pwriting if we use the current CPU write domain rather than moving the object to the GTT domain for the purposes of the pwrite. This has the advantage of not flushing the presumably hot data that we want to upload into the bo, and of ascribing the clflush to the execution when profiling. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 42866c01540d..4590c78f4283 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -971,7 +971,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, if (obj_priv->phys_obj) ret = i915_gem_phys_pwrite(dev, obj, args, file_priv); else if (obj_priv->tiling_mode == I915_TILING_NONE && - dev->gtt_total != 0) { + dev->gtt_total != 0 && + obj->write_domain != I915_GEM_DOMAIN_CPU) { ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv); if (ret == -EFAULT) { ret = i915_gem_gtt_pwrite_slow(dev, obj, args, -- GitLab From 99a03df57c82ec20848d2634f652c07ac3504b98 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 14:15:34 +0100 Subject: [PATCH 263/842] drm/i915: Use non-atomic kmap for slow copy paths As we do not have a requirement to be atomic and avoid sleeping whilst performing the slow copy for shmem based pread and pwrite, we can use kmap instead, thus simplifying the code. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_gem.c | 82 ++++++++++++--------------------- 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4590c78f4283..b8e351274493 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -167,7 +167,7 @@ static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj) obj_priv->tiling_mode != I915_TILING_NONE; } -static inline int +static inline void slow_shmem_copy(struct page *dst_page, int dst_offset, struct page *src_page, @@ -176,25 +176,16 @@ slow_shmem_copy(struct page *dst_page, { char *dst_vaddr, *src_vaddr; - dst_vaddr = kmap_atomic(dst_page, KM_USER0); - if (dst_vaddr == NULL) - return -ENOMEM; - - src_vaddr = kmap_atomic(src_page, KM_USER1); - if (src_vaddr == NULL) { - kunmap_atomic(dst_vaddr, KM_USER0); - return -ENOMEM; - } + dst_vaddr = kmap(dst_page); + src_vaddr = kmap(src_page); memcpy(dst_vaddr + dst_offset, src_vaddr + src_offset, length); - kunmap_atomic(src_vaddr, KM_USER1); - kunmap_atomic(dst_vaddr, KM_USER0); - - return 0; + kunmap(src_page); + kunmap(dst_page); } -static inline int +static inline void slow_shmem_bit17_copy(struct page *gpu_page, int gpu_offset, struct page *cpu_page, @@ -214,15 +205,8 @@ slow_shmem_bit17_copy(struct page *gpu_page, cpu_page, cpu_offset, length); } - gpu_vaddr = kmap_atomic(gpu_page, KM_USER0); - if (gpu_vaddr == NULL) - return -ENOMEM; - - cpu_vaddr = kmap_atomic(cpu_page, KM_USER1); - if (cpu_vaddr == NULL) { - kunmap_atomic(gpu_vaddr, KM_USER0); - return -ENOMEM; - } + gpu_vaddr = kmap(gpu_page); + cpu_vaddr = kmap(cpu_page); /* Copy the data, XORing A6 with A17 (1). The user already knows he's * XORing with the other bits (A9 for Y, A9 and A10 for X) @@ -246,10 +230,8 @@ slow_shmem_bit17_copy(struct page *gpu_page, length -= this_length; } - kunmap_atomic(cpu_vaddr, KM_USER1); - kunmap_atomic(gpu_vaddr, KM_USER0); - - return 0; + kunmap(cpu_page); + kunmap(gpu_page); } /** @@ -425,21 +407,19 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, page_length = PAGE_SIZE - data_page_offset; if (do_bit17_swizzling) { - ret = slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index], - shmem_page_offset, - user_pages[data_page_index], - data_page_offset, - page_length, - 1); - } else { - ret = slow_shmem_copy(user_pages[data_page_index], - data_page_offset, - obj_priv->pages[shmem_page_index], + slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index], shmem_page_offset, - page_length); + user_pages[data_page_index], + data_page_offset, + page_length, + 1); + } else { + slow_shmem_copy(user_pages[data_page_index], + data_page_offset, + obj_priv->pages[shmem_page_index], + shmem_page_offset, + page_length); } - if (ret) - goto fail_put_pages; remain -= page_length; data_ptr += page_length; @@ -900,21 +880,19 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, page_length = PAGE_SIZE - data_page_offset; if (do_bit17_swizzling) { - ret = slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index], - shmem_page_offset, - user_pages[data_page_index], - data_page_offset, - page_length, - 0); - } else { - ret = slow_shmem_copy(obj_priv->pages[shmem_page_index], + slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index], shmem_page_offset, user_pages[data_page_index], data_page_offset, - page_length); + page_length, + 0); + } else { + slow_shmem_copy(obj_priv->pages[shmem_page_index], + shmem_page_offset, + user_pages[data_page_index], + data_page_offset, + page_length); } - if (ret) - goto fail_put_pages; remain -= page_length; data_ptr += page_length; -- GitLab From ab34c226812588de8f341ce48eb32c3fef5155a9 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 27 May 2010 14:15:35 +0100 Subject: [PATCH 264/842] drm/i915: Fix up address spaces in slow_kernel_write() Since we now get_user_pages() outside of the mutex prior to performing the copy, we kmap() the page inside the copy routine and so need to perform an ordinary memcpy() and not copy_from_user(). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_gem.c | 42 +++++++++++++-------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b8e351274493..9ded3dae6c87 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -509,25 +509,24 @@ fast_user_write(struct io_mapping *mapping, * page faults */ -static inline int +static inline void slow_kernel_write(struct io_mapping *mapping, loff_t gtt_base, int gtt_offset, struct page *user_page, int user_offset, int length) { - char *src_vaddr, *dst_vaddr; - unsigned long unwritten; + char __iomem *dst_vaddr; + char *src_vaddr; - dst_vaddr = io_mapping_map_atomic_wc(mapping, gtt_base); - src_vaddr = kmap_atomic(user_page, KM_USER1); - unwritten = __copy_from_user_inatomic_nocache(dst_vaddr + gtt_offset, - src_vaddr + user_offset, - length); - kunmap_atomic(src_vaddr, KM_USER1); - io_mapping_unmap_atomic(dst_vaddr); - if (unwritten) - return -EFAULT; - return 0; + dst_vaddr = io_mapping_map_wc(mapping, gtt_base); + src_vaddr = kmap(user_page); + + memcpy_toio(dst_vaddr + gtt_offset, + src_vaddr + user_offset, + length); + + kunmap(user_page); + io_mapping_unmap(dst_vaddr); } static inline int @@ -700,18 +699,11 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, if ((data_page_offset + page_length) > PAGE_SIZE) page_length = PAGE_SIZE - data_page_offset; - ret = slow_kernel_write(dev_priv->mm.gtt_mapping, - gtt_page_base, gtt_page_offset, - user_pages[data_page_index], - data_page_offset, - page_length); - - /* If we get a fault while copying data, then (presumably) our - * source page isn't available. Return the error and we'll - * retry in the slow path. - */ - if (ret) - goto out_unpin_object; + slow_kernel_write(dev_priv->mm.gtt_mapping, + gtt_page_base, gtt_page_offset, + user_pages[data_page_index], + data_page_offset, + page_length); remain -= page_length; offset += page_length; -- GitLab From ca76482e0f4b64942c704fa11c620ffd1bdd8475 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang <zhenyuw@linux.intel.com> Date: Thu, 27 May 2010 10:26:42 +0800 Subject: [PATCH 265/842] drm/i915: Fix PIPE_CONTROL command on Sandybridge Sandybridge(Gen6) has new format for PIPE_CONTROL command, the flush and post-op control are in dword 1 now. This changes command length field for difference between Ironlake and Sandybridge. I tried to test this with noop request and issue PIPE_CONTROL command for each sequence and track notify interrupts, which seems work fine. Hopefully we don't need workaround like on Ironlake for Sandybridge. Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_ringbuffer.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index f6b84fe8099a..cea4f1a8709e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -213,7 +213,7 @@ static int init_render_ring(struct drm_device *dev, #define PIPE_CONTROL_FLUSH(addr) \ do { \ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ - PIPE_CONTROL_DEPTH_STALL); \ + PIPE_CONTROL_DEPTH_STALL | 2); \ OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \ OUT_RING(0); \ OUT_RING(0); \ @@ -236,7 +236,19 @@ render_ring_add_request(struct drm_device *dev, u32 seqno; drm_i915_private_t *dev_priv = dev->dev_private; seqno = intel_ring_get_seqno(dev, ring); - if (HAS_PIPE_CONTROL(dev)) { + + if (IS_GEN6(dev)) { + BEGIN_LP_RING(6); + OUT_RING(GFX_OP_PIPE_CONTROL | 3); + OUT_RING(PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH | + PIPE_CONTROL_NOTIFY); + OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + OUT_RING(seqno); + OUT_RING(0); + OUT_RING(0); + ADVANCE_LP_RING(); + } else if (HAS_PIPE_CONTROL(dev)) { u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; /* -- GitLab From a1786bd270b08834a735e06c3d5430eeb0baf017 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang <zhenyuw@linux.intel.com> Date: Thu, 27 May 2010 10:26:43 +0800 Subject: [PATCH 266/842] drm/i915: Unmask interrupt for render engine on Sandybridge With splitted engines on Sandybridge, each engine has its own interrupt control as well. This unmasks the interrupt to properly enable pipe control notify event for render engine. Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_reg.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index af7b10853e33..64b0a3afd92b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -369,6 +369,25 @@ #define BB_ADDR 0x02140 /* 8 bytes */ #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ +/* GEN6 interrupt control */ +#define GEN6_RENDER_HWSTAM 0x2098 +#define GEN6_RENDER_IMR 0x20a8 +#define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8) +#define GEN6_RENDER_PPGTT_PAGE_FAULT (1 << 7) +#define GEN6_RENDER TIMEOUT_COUNTER_EXPIRED (1 << 6) +#define GEN6_RENDER_L3_PARITY_ERROR (1 << 5) +#define GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT (1 << 4) +#define GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR (1 << 3) +#define GEN6_RENDER_SYNC_STATUS (1 << 2) +#define GEN6_RENDER_DEBUG_INTERRUPT (1 << 1) +#define GEN6_RENDER_USER_INTERRUPT (1 << 0) + +#define GEN6_BLITTER_HWSTAM 0x22098 +#define GEN6_BLITTER_IMR 0x220a8 +#define GEN6_BLITTER_MI_FLUSH_DW_NOTIFY_INTERRUPT (1 << 26) +#define GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR (1 << 25) +#define GEN6_BLITTER_SYNC_STATUS (1 << 24) +#define GEN6_BLITTER_USER_INTERRUPT (1 << 22) /* * BSD (bit stream decoder instruction and interrupt control register defines * (G4X and Ironlake only) -- GitLab From 657a4cffde065beca7d919e867f61e7d322708b6 Mon Sep 17 00:00:00 2001 From: Eric Sandeen <sandeen@sandeen.net> Date: Fri, 30 Apr 2010 03:42:49 +0000 Subject: [PATCH 267/842] xfs: replace E2BIG with EFBIG where appropriate Many places in the xfs code return E2BIG when they really mean EFBIG; trying to grow past 16T on a 32 bit machine, for example, says "Argument list too long" rather than "File too large" which is not particularly helpful. Some of these don't make perfect sense as EFBIG either, but still better than E2BIG IMHO. Signed-off-by: Eric Sandeen <sandeen@sandeen.net> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/xfs_mount.c | 14 +++++++------- fs/xfs/xfs_rtalloc.c | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index d7bf38c8cd1c..2d811e57b332 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -268,10 +268,10 @@ xfs_sb_validate_fsb_count( #if XFS_BIG_BLKNOS /* Limited by ULONG_MAX of page cache index */ if (nblocks >> (PAGE_CACHE_SHIFT - sbp->sb_blocklog) > ULONG_MAX) - return E2BIG; + return EFBIG; #else /* Limited by UINT_MAX of sectors */ if (nblocks << (sbp->sb_blocklog - BBSHIFT) > UINT_MAX) - return E2BIG; + return EFBIG; #endif return 0; } @@ -393,7 +393,7 @@ xfs_mount_validate_sb( xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { xfs_fs_mount_cmn_err(flags, "file system too large to be mounted on this system."); - return XFS_ERROR(E2BIG); + return XFS_ERROR(EFBIG); } if (unlikely(sbp->sb_inprogress)) { @@ -1009,7 +1009,7 @@ xfs_check_sizes(xfs_mount_t *mp) d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) { cmn_err(CE_WARN, "XFS: size check 1 failed"); - return XFS_ERROR(E2BIG); + return XFS_ERROR(EFBIG); } error = xfs_read_buf(mp, mp->m_ddev_targp, d - XFS_FSS_TO_BB(mp, 1), @@ -1019,7 +1019,7 @@ xfs_check_sizes(xfs_mount_t *mp) } else { cmn_err(CE_WARN, "XFS: size check 2 failed"); if (error == ENOSPC) - error = XFS_ERROR(E2BIG); + error = XFS_ERROR(EFBIG); return error; } @@ -1027,7 +1027,7 @@ xfs_check_sizes(xfs_mount_t *mp) d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) { cmn_err(CE_WARN, "XFS: size check 3 failed"); - return XFS_ERROR(E2BIG); + return XFS_ERROR(EFBIG); } error = xfs_read_buf(mp, mp->m_logdev_targp, d - XFS_FSB_TO_BB(mp, 1), @@ -1037,7 +1037,7 @@ xfs_check_sizes(xfs_mount_t *mp) } else { cmn_err(CE_WARN, "XFS: size check 3 failed"); if (error == ENOSPC) - error = XFS_ERROR(E2BIG); + error = XFS_ERROR(EFBIG); return error; } } diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 6be05f756d59..16445518506d 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -2247,7 +2247,7 @@ xfs_rtmount_init( cmn_err(CE_WARN, "XFS: realtime mount -- %llu != %llu", (unsigned long long) XFS_BB_TO_FSB(mp, d), (unsigned long long) mp->m_sb.sb_rblocks); - return XFS_ERROR(E2BIG); + return XFS_ERROR(EFBIG); } error = xfs_read_buf(mp, mp->m_rtdev_targp, d - XFS_FSB_TO_BB(mp, 1), @@ -2256,7 +2256,7 @@ xfs_rtmount_init( cmn_err(CE_WARN, "XFS: realtime mount -- xfs_read_buf failed, returned %d", error); if (error == ENOSPC) - return XFS_ERROR(E2BIG); + return XFS_ERROR(EFBIG); return error; } xfs_buf_relse(bp); -- GitLab From 32891b292d6262d1db8e553cf3f4b38a91247b5a Mon Sep 17 00:00:00 2001 From: Eric Sandeen <sandeen@sandeen.net> Date: Fri, 30 Apr 2010 16:43:48 +0000 Subject: [PATCH 268/842] xfs: be more explicit if RT mount fails due to config Recent testers were slightly confused that a realtime mount failed due to missing CONFIG_XFS_RT; we can make that a little more obvious. V2: drop the else as suggested by Christoph Signed-off-by: Eric Sandeen <sandeen@sandeen.net> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/xfs_rtalloc.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_rtalloc.h b/fs/xfs/xfs_rtalloc.h index b2d67adb6a08..ff614c29b441 100644 --- a/fs/xfs/xfs_rtalloc.h +++ b/fs/xfs/xfs_rtalloc.h @@ -147,7 +147,16 @@ xfs_growfs_rt( # define xfs_rtfree_extent(t,b,l) (ENOSYS) # define xfs_rtpick_extent(m,t,l,rb) (ENOSYS) # define xfs_growfs_rt(mp,in) (ENOSYS) -# define xfs_rtmount_init(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS)) +static inline int /* error */ +xfs_rtmount_init( + xfs_mount_t *mp) /* file system mount structure */ +{ + if (mp->m_sb.sb_rblocks == 0) + return 0; + + cmn_err(CE_WARN, "XFS: Not built with CONFIG_XFS_RT"); + return ENOSYS; +} # define xfs_rtmount_inodes(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS)) # define xfs_rtunmount_inodes(m) #endif /* CONFIG_XFS_RT */ -- GitLab From 025101dca4480eff9da948405e872d5115030850 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig <hch@infradead.org> Date: Tue, 4 May 2010 13:53:48 +0000 Subject: [PATCH 269/842] xfs: cleanup log reservation calculactions Instead of having small helper functions calling big macros do the calculations for the log reservations directly in the functions. These are mostly 1:1 from the macros execept that the macros kept the quota calculations in their callers. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/xfs_trans.c | 446 ++++++++++++++++++++++++++++++++++++++++----- fs/xfs/xfs_trans.h | 411 ----------------------------------------- 2 files changed, 400 insertions(+), 457 deletions(-) diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index ce558efa2ea0..28547dfce037 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -48,134 +48,489 @@ kmem_zone_t *xfs_trans_zone; + /* - * Reservation functions here avoid a huge stack in xfs_trans_init - * due to register overflow from temporaries in the calculations. + * Various log reservation values. + * + * These are based on the size of the file system block because that is what + * most transactions manipulate. Each adds in an additional 128 bytes per + * item logged to try to account for the overhead of the transaction mechanism. + * + * Note: Most of the reservations underestimate the number of allocation + * groups into which they could free extents in the xfs_bmap_finish() call. + * This is because the number in the worst case is quite high and quite + * unusual. In order to fix this we need to change xfs_bmap_finish() to free + * extents in only a single AG at a time. This will require changes to the + * EFI code as well, however, so that the EFI for the extents not freed is + * logged again in each transaction. See SGI PV #261917. + * + * Reservation functions here avoid a huge stack in xfs_trans_init due to + * register overflow from temporaries in the calculations. + */ + + +/* + * In a write transaction we can allocate a maximum of 2 + * extents. This gives: + * the inode getting the new extents: inode size + * the inode's bmap btree: max depth * block size + * the agfs of the ags from which the extents are allocated: 2 * sector + * the superblock free block counter: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + * And the bmap_finish transaction can free bmap blocks in a join: + * the agfs of the ags containing the blocks: 2 * sector size + * the agfls of the ags containing the blocks: 2 * sector size + * the super block free block counter: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint -xfs_calc_write_reservation(xfs_mount_t *mp) +xfs_calc_write_reservation( + struct xfs_mount *mp) { - return XFS_CALC_WRITE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + MAX((mp->m_sb.sb_inodesize + + XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + + 2 * mp->m_sb.sb_sectsize + + mp->m_sb.sb_sectsize + + XFS_ALLOCFREE_LOG_RES(mp, 2) + + 128 * (4 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + + XFS_ALLOCFREE_LOG_COUNT(mp, 2))), + (2 * mp->m_sb.sb_sectsize + + 2 * mp->m_sb.sb_sectsize + + mp->m_sb.sb_sectsize + + XFS_ALLOCFREE_LOG_RES(mp, 2) + + 128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))); } +/* + * In truncating a file we free up to two extents at once. We can modify: + * the inode being truncated: inode size + * the inode's bmap btree: (max depth + 1) * block size + * And the bmap_finish transaction can free the blocks and bmap blocks: + * the agf for each of the ags: 4 * sector size + * the agfl for each of the ags: 4 * sector size + * the super block to reflect the freed blocks: sector size + * worst case split in allocation btrees per extent assuming 4 extents: + * 4 exts * 2 trees * (2 * max depth - 1) * block size + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (max depth - 1) * block size + */ STATIC uint -xfs_calc_itruncate_reservation(xfs_mount_t *mp) +xfs_calc_itruncate_reservation( + struct xfs_mount *mp) { - return XFS_CALC_ITRUNCATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + MAX((mp->m_sb.sb_inodesize + + XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1) + + 128 * (2 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK))), + (4 * mp->m_sb.sb_sectsize + + 4 * mp->m_sb.sb_sectsize + + mp->m_sb.sb_sectsize + + XFS_ALLOCFREE_LOG_RES(mp, 4) + + 128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)) + + 128 * 5 + + XFS_ALLOCFREE_LOG_RES(mp, 1) + + 128 * (2 + XFS_IALLOC_BLOCKS(mp) + mp->m_in_maxlevels + + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))); } +/* + * In renaming a files we can modify: + * the four inodes involved: 4 * inode size + * the two directory btrees: 2 * (max depth + v2) * dir block size + * the two directory bmap btrees: 2 * max depth * block size + * And the bmap_finish transaction can free dir and bmap blocks (two sets + * of bmap blocks) giving: + * the agf for the ags in which the blocks live: 3 * sector size + * the agfl for the ags in which the blocks live: 3 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size + */ STATIC uint -xfs_calc_rename_reservation(xfs_mount_t *mp) +xfs_calc_rename_reservation( + struct xfs_mount *mp) { - return XFS_CALC_RENAME_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + MAX((4 * mp->m_sb.sb_inodesize + + 2 * XFS_DIROP_LOG_RES(mp) + + 128 * (4 + 2 * XFS_DIROP_LOG_COUNT(mp))), + (3 * mp->m_sb.sb_sectsize + + 3 * mp->m_sb.sb_sectsize + + mp->m_sb.sb_sectsize + + XFS_ALLOCFREE_LOG_RES(mp, 3) + + 128 * (7 + XFS_ALLOCFREE_LOG_COUNT(mp, 3)))); } +/* + * For creating a link to an inode: + * the parent directory inode: inode size + * the linked inode: inode size + * the directory btree could split: (max depth + v2) * dir block size + * the directory bmap btree could join or split: (max depth + v2) * blocksize + * And the bmap_finish transaction can free some bmap blocks giving: + * the agf for the ag in which the blocks live: sector size + * the agfl for the ag in which the blocks live: sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 trees * (2 * max depth - 1) * block size + */ STATIC uint -xfs_calc_link_reservation(xfs_mount_t *mp) +xfs_calc_link_reservation( + struct xfs_mount *mp) { - return XFS_CALC_LINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + MAX((mp->m_sb.sb_inodesize + + mp->m_sb.sb_inodesize + + XFS_DIROP_LOG_RES(mp) + + 128 * (2 + XFS_DIROP_LOG_COUNT(mp))), + (mp->m_sb.sb_sectsize + + mp->m_sb.sb_sectsize + + mp->m_sb.sb_sectsize + + XFS_ALLOCFREE_LOG_RES(mp, 1) + + 128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))); } +/* + * For removing a directory entry we can modify: + * the parent directory inode: inode size + * the removed inode: inode size + * the directory btree could join: (max depth + v2) * dir block size + * the directory bmap btree could join or split: (max depth + v2) * blocksize + * And the bmap_finish transaction can free the dir and bmap blocks giving: + * the agf for the ag in which the blocks live: 2 * sector size + * the agfl for the ag in which the blocks live: 2 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ STATIC uint -xfs_calc_remove_reservation(xfs_mount_t *mp) +xfs_calc_remove_reservation( + struct xfs_mount *mp) { - return XFS_CALC_REMOVE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + MAX((mp->m_sb.sb_inodesize + + mp->m_sb.sb_inodesize + + XFS_DIROP_LOG_RES(mp) + + 128 * (2 + XFS_DIROP_LOG_COUNT(mp))), + (2 * mp->m_sb.sb_sectsize + + 2 * mp->m_sb.sb_sectsize + + mp->m_sb.sb_sectsize + + XFS_ALLOCFREE_LOG_RES(mp, 2) + + 128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))); } +/* + * For symlink we can modify: + * the parent directory inode: inode size + * the new inode: inode size + * the inode btree entry: 1 block + * the directory btree: (max depth + v2) * dir block size + * the directory inode's bmap btree: (max depth + v2) * block size + * the blocks for the symlink: 1 kB + * Or in the first xact we allocate some inodes giving: + * the agi and agf of the ag getting the new inodes: 2 * sectorsize + * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (2 * max depth - 1) * block size + */ STATIC uint -xfs_calc_symlink_reservation(xfs_mount_t *mp) +xfs_calc_symlink_reservation( + struct xfs_mount *mp) { - return XFS_CALC_SYMLINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + MAX((mp->m_sb.sb_inodesize + + mp->m_sb.sb_inodesize + + XFS_FSB_TO_B(mp, 1) + + XFS_DIROP_LOG_RES(mp) + + 1024 + + 128 * (4 + XFS_DIROP_LOG_COUNT(mp))), + (2 * mp->m_sb.sb_sectsize + + XFS_FSB_TO_B(mp, XFS_IALLOC_BLOCKS(mp)) + + XFS_FSB_TO_B(mp, mp->m_in_maxlevels) + + XFS_ALLOCFREE_LOG_RES(mp, 1) + + 128 * (2 + XFS_IALLOC_BLOCKS(mp) + mp->m_in_maxlevels + + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))); } +/* + * For create we can modify: + * the parent directory inode: inode size + * the new inode: inode size + * the inode btree entry: block size + * the superblock for the nlink flag: sector size + * the directory btree: (max depth + v2) * dir block size + * the directory inode's bmap btree: (max depth + v2) * block size + * Or in the first xact we allocate some inodes giving: + * the agi and agf of the ag getting the new inodes: 2 * sectorsize + * the superblock for the nlink flag: sector size + * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (max depth - 1) * block size + */ STATIC uint -xfs_calc_create_reservation(xfs_mount_t *mp) +xfs_calc_create_reservation( + struct xfs_mount *mp) { - return XFS_CALC_CREATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + MAX((mp->m_sb.sb_inodesize + + mp->m_sb.sb_inodesize + + mp->m_sb.sb_sectsize + + XFS_FSB_TO_B(mp, 1) + + XFS_DIROP_LOG_RES(mp) + + 128 * (3 + XFS_DIROP_LOG_COUNT(mp))), + (3 * mp->m_sb.sb_sectsize + + XFS_FSB_TO_B(mp, XFS_IALLOC_BLOCKS(mp)) + + XFS_FSB_TO_B(mp, mp->m_in_maxlevels) + + XFS_ALLOCFREE_LOG_RES(mp, 1) + + 128 * (2 + XFS_IALLOC_BLOCKS(mp) + mp->m_in_maxlevels + + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))); } +/* + * Making a new directory is the same as creating a new file. + */ STATIC uint -xfs_calc_mkdir_reservation(xfs_mount_t *mp) +xfs_calc_mkdir_reservation( + struct xfs_mount *mp) { - return XFS_CALC_MKDIR_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return xfs_calc_create_reservation(mp); } +/* + * In freeing an inode we can modify: + * the inode being freed: inode size + * the super block free inode counter: sector size + * the agi hash list and counters: sector size + * the inode btree entry: block size + * the on disk inode before ours in the agi hash list: inode cluster size + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (max depth - 1) * block size + */ STATIC uint -xfs_calc_ifree_reservation(xfs_mount_t *mp) +xfs_calc_ifree_reservation( + struct xfs_mount *mp) { - return XFS_CALC_IFREE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + mp->m_sb.sb_inodesize + + mp->m_sb.sb_sectsize + + mp->m_sb.sb_sectsize + + XFS_FSB_TO_B(mp, 1) + + MAX((__uint16_t)XFS_FSB_TO_B(mp, 1), + XFS_INODE_CLUSTER_SIZE(mp)) + + 128 * 5 + + XFS_ALLOCFREE_LOG_RES(mp, 1) + + 128 * (2 + XFS_IALLOC_BLOCKS(mp) + mp->m_in_maxlevels + + XFS_ALLOCFREE_LOG_COUNT(mp, 1)); } +/* + * When only changing the inode we log the inode and possibly the superblock + * We also add a bit of slop for the transaction stuff. + */ STATIC uint -xfs_calc_ichange_reservation(xfs_mount_t *mp) +xfs_calc_ichange_reservation( + struct xfs_mount *mp) { - return XFS_CALC_ICHANGE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + mp->m_sb.sb_inodesize + + mp->m_sb.sb_sectsize + + 512; + } +/* + * Growing the data section of the filesystem. + * superblock + * agi and agf + * allocation btrees + */ STATIC uint -xfs_calc_growdata_reservation(xfs_mount_t *mp) +xfs_calc_growdata_reservation( + struct xfs_mount *mp) { - return XFS_CALC_GROWDATA_LOG_RES(mp); + return mp->m_sb.sb_sectsize * 3 + + XFS_ALLOCFREE_LOG_RES(mp, 1) + + 128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1)); } +/* + * Growing the rt section of the filesystem. + * In the first set of transactions (ALLOC) we allocate space to the + * bitmap or summary files. + * superblock: sector size + * agf of the ag from which the extent is allocated: sector size + * bmap btree for bitmap/summary inode: max depth * blocksize + * bitmap/summary inode: inode size + * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize + */ STATIC uint -xfs_calc_growrtalloc_reservation(xfs_mount_t *mp) +xfs_calc_growrtalloc_reservation( + struct xfs_mount *mp) { - return XFS_CALC_GROWRTALLOC_LOG_RES(mp); + return 2 * mp->m_sb.sb_sectsize + + XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + + mp->m_sb.sb_inodesize + + XFS_ALLOCFREE_LOG_RES(mp, 1) + + 128 * (3 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + + XFS_ALLOCFREE_LOG_COUNT(mp, 1)); } +/* + * Growing the rt section of the filesystem. + * In the second set of transactions (ZERO) we zero the new metadata blocks. + * one bitmap/summary block: blocksize + */ STATIC uint -xfs_calc_growrtzero_reservation(xfs_mount_t *mp) +xfs_calc_growrtzero_reservation( + struct xfs_mount *mp) { - return XFS_CALC_GROWRTZERO_LOG_RES(mp); + return mp->m_sb.sb_blocksize + 128; } +/* + * Growing the rt section of the filesystem. + * In the third set of transactions (FREE) we update metadata without + * allocating any new blocks. + * superblock: sector size + * bitmap inode: inode size + * summary inode: inode size + * one bitmap block: blocksize + * summary blocks: new summary size + */ STATIC uint -xfs_calc_growrtfree_reservation(xfs_mount_t *mp) +xfs_calc_growrtfree_reservation( + struct xfs_mount *mp) { - return XFS_CALC_GROWRTFREE_LOG_RES(mp); + return mp->m_sb.sb_sectsize + + 2 * mp->m_sb.sb_inodesize + + mp->m_sb.sb_blocksize + + mp->m_rsumsize + + 128 * 5; } +/* + * Logging the inode modification timestamp on a synchronous write. + * inode + */ STATIC uint -xfs_calc_swrite_reservation(xfs_mount_t *mp) +xfs_calc_swrite_reservation( + struct xfs_mount *mp) { - return XFS_CALC_SWRITE_LOG_RES(mp); + return mp->m_sb.sb_inodesize + 128; } +/* + * Logging the inode mode bits when writing a setuid/setgid file + * inode + */ STATIC uint xfs_calc_writeid_reservation(xfs_mount_t *mp) { - return XFS_CALC_WRITEID_LOG_RES(mp); + return mp->m_sb.sb_inodesize + 128; } +/* + * Converting the inode from non-attributed to attributed. + * the inode being converted: inode size + * agf block and superblock (for block allocation) + * the new block (directory sized) + * bmap blocks for the new directory block + * allocation btrees + */ STATIC uint -xfs_calc_addafork_reservation(xfs_mount_t *mp) +xfs_calc_addafork_reservation( + struct xfs_mount *mp) { - return XFS_CALC_ADDAFORK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + mp->m_sb.sb_inodesize + + mp->m_sb.sb_sectsize * 2 + + mp->m_dirblksize + + XFS_FSB_TO_B(mp, XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) + + XFS_ALLOCFREE_LOG_RES(mp, 1) + + 128 * (4 + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1 + + XFS_ALLOCFREE_LOG_COUNT(mp, 1)); } +/* + * Removing the attribute fork of a file + * the inode being truncated: inode size + * the inode's bmap btree: max depth * block size + * And the bmap_finish transaction can free the blocks and bmap blocks: + * the agf for each of the ags: 4 * sector size + * the agfl for each of the ags: 4 * sector size + * the super block to reflect the freed blocks: sector size + * worst case split in allocation btrees per extent assuming 4 extents: + * 4 exts * 2 trees * (2 * max depth - 1) * block size + */ STATIC uint -xfs_calc_attrinval_reservation(xfs_mount_t *mp) +xfs_calc_attrinval_reservation( + struct xfs_mount *mp) { - return XFS_CALC_ATTRINVAL_LOG_RES(mp); + return MAX((mp->m_sb.sb_inodesize + + XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + + 128 * (1 + XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))), + (4 * mp->m_sb.sb_sectsize + + 4 * mp->m_sb.sb_sectsize + + mp->m_sb.sb_sectsize + + XFS_ALLOCFREE_LOG_RES(mp, 4) + + 128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)))); } +/* + * Setting an attribute. + * the inode getting the attribute + * the superblock for allocations + * the agfs extents are allocated from + * the attribute btree * max depth + * the inode allocation btree + * Since attribute transaction space is dependent on the size of the attribute, + * the calculation is done partially at mount time and partially at runtime. + */ STATIC uint -xfs_calc_attrset_reservation(xfs_mount_t *mp) +xfs_calc_attrset_reservation( + struct xfs_mount *mp) { - return XFS_CALC_ATTRSET_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + mp->m_sb.sb_inodesize + + mp->m_sb.sb_sectsize + + XFS_FSB_TO_B(mp, XFS_DA_NODE_MAXDEPTH) + + 128 * (2 + XFS_DA_NODE_MAXDEPTH); } +/* + * Removing an attribute. + * the inode: inode size + * the attribute btree could join: max depth * block size + * the inode bmap btree could join or split: max depth * block size + * And the bmap_finish transaction can free the attr blocks freed giving: + * the agf for the ag in which the blocks live: 2 * sector size + * the agfl for the ag in which the blocks live: 2 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ STATIC uint -xfs_calc_attrrm_reservation(xfs_mount_t *mp) +xfs_calc_attrrm_reservation( + struct xfs_mount *mp) { - return XFS_CALC_ATTRRM_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp); + return XFS_DQUOT_LOGRES(mp) + + MAX((mp->m_sb.sb_inodesize + + XFS_FSB_TO_B(mp, XFS_DA_NODE_MAXDEPTH) + + XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + + 128 * (1 + XFS_DA_NODE_MAXDEPTH + + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK))), + (2 * mp->m_sb.sb_sectsize + + 2 * mp->m_sb.sb_sectsize + + mp->m_sb.sb_sectsize + + XFS_ALLOCFREE_LOG_RES(mp, 2) + + 128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))); } +/* + * Clearing a bad agino number in an agi hash bucket. + */ STATIC uint -xfs_calc_clear_agi_bucket_reservation(xfs_mount_t *mp) +xfs_calc_clear_agi_bucket_reservation( + struct xfs_mount *mp) { - return XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp); + return mp->m_sb.sb_sectsize + 128; } /* @@ -184,11 +539,10 @@ xfs_calc_clear_agi_bucket_reservation(xfs_mount_t *mp) */ void xfs_trans_init( - xfs_mount_t *mp) + struct xfs_mount *mp) { - xfs_trans_reservations_t *resp; + struct xfs_trans_reservations *resp = &mp->m_reservations; - resp = &(mp->m_reservations); resp->tr_write = xfs_calc_write_reservation(mp); resp->tr_itruncate = xfs_calc_itruncate_reservation(mp); resp->tr_rename = xfs_calc_rename_reservation(mp); diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 8c69e7824f68..e639e8e9a2a9 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -299,24 +299,6 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp) #define XFS_TRANS_SB_REXTSLOG 0x00002000 -/* - * Various log reservation values. - * These are based on the size of the file system block - * because that is what most transactions manipulate. - * Each adds in an additional 128 bytes per item logged to - * try to account for the overhead of the transaction mechanism. - * - * Note: - * Most of the reservations underestimate the number of allocation - * groups into which they could free extents in the xfs_bmap_finish() - * call. This is because the number in the worst case is quite high - * and quite unusual. In order to fix this we need to change - * xfs_bmap_finish() to free extents in only a single AG at a time. - * This will require changes to the EFI code as well, however, so that - * the EFI for the extents not freed is logged again in each transaction. - * See bug 261917. - */ - /* * Per-extent log reservation for the allocation btree changes * involved in freeing or allocating an extent. @@ -341,429 +323,36 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp) (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \ XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1) -/* - * In a write transaction we can allocate a maximum of 2 - * extents. This gives: - * the inode getting the new extents: inode size - * the inode's bmap btree: max depth * block size - * the agfs of the ags from which the extents are allocated: 2 * sector - * the superblock free block counter: sector size - * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size - * And the bmap_finish transaction can free bmap blocks in a join: - * the agfs of the ags containing the blocks: 2 * sector size - * the agfls of the ags containing the blocks: 2 * sector size - * the super block free block counter: sector size - * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size - */ -#define XFS_CALC_WRITE_LOG_RES(mp) \ - (MAX( \ - ((mp)->m_sb.sb_inodesize + \ - XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + \ - (2 * (mp)->m_sb.sb_sectsize) + \ - (mp)->m_sb.sb_sectsize + \ - XFS_ALLOCFREE_LOG_RES(mp, 2) + \ - (128 * (4 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))),\ - ((2 * (mp)->m_sb.sb_sectsize) + \ - (2 * (mp)->m_sb.sb_sectsize) + \ - (mp)->m_sb.sb_sectsize + \ - XFS_ALLOCFREE_LOG_RES(mp, 2) + \ - (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) #define XFS_WRITE_LOG_RES(mp) ((mp)->m_reservations.tr_write) - -/* - * In truncating a file we free up to two extents at once. We can modify: - * the inode being truncated: inode size - * the inode's bmap btree: (max depth + 1) * block size - * And the bmap_finish transaction can free the blocks and bmap blocks: - * the agf for each of the ags: 4 * sector size - * the agfl for each of the ags: 4 * sector size - * the super block to reflect the freed blocks: sector size - * worst case split in allocation btrees per extent assuming 4 extents: - * 4 exts * 2 trees * (2 * max depth - 1) * block size - * the inode btree: max depth * blocksize - * the allocation btrees: 2 trees * (max depth - 1) * block size - */ -#define XFS_CALC_ITRUNCATE_LOG_RES(mp) \ - (MAX( \ - ((mp)->m_sb.sb_inodesize + \ - XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1) + \ - (128 * (2 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)))), \ - ((4 * (mp)->m_sb.sb_sectsize) + \ - (4 * (mp)->m_sb.sb_sectsize) + \ - (mp)->m_sb.sb_sectsize + \ - XFS_ALLOCFREE_LOG_RES(mp, 4) + \ - (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4))) + \ - (128 * 5) + \ - XFS_ALLOCFREE_LOG_RES(mp, 1) + \ - (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \ - XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) - #define XFS_ITRUNCATE_LOG_RES(mp) ((mp)->m_reservations.tr_itruncate) - -/* - * In renaming a files we can modify: - * the four inodes involved: 4 * inode size - * the two directory btrees: 2 * (max depth + v2) * dir block size - * the two directory bmap btrees: 2 * max depth * block size - * And the bmap_finish transaction can free dir and bmap blocks (two sets - * of bmap blocks) giving: - * the agf for the ags in which the blocks live: 3 * sector size - * the agfl for the ags in which the blocks live: 3 * sector size - * the superblock for the free block count: sector size - * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size - */ -#define XFS_CALC_RENAME_LOG_RES(mp) \ - (MAX( \ - ((4 * (mp)->m_sb.sb_inodesize) + \ - (2 * XFS_DIROP_LOG_RES(mp)) + \ - (128 * (4 + 2 * XFS_DIROP_LOG_COUNT(mp)))), \ - ((3 * (mp)->m_sb.sb_sectsize) + \ - (3 * (mp)->m_sb.sb_sectsize) + \ - (mp)->m_sb.sb_sectsize + \ - XFS_ALLOCFREE_LOG_RES(mp, 3) + \ - (128 * (7 + XFS_ALLOCFREE_LOG_COUNT(mp, 3)))))) - #define XFS_RENAME_LOG_RES(mp) ((mp)->m_reservations.tr_rename) - -/* - * For creating a link to an inode: - * the parent directory inode: inode size - * the linked inode: inode size - * the directory btree could split: (max depth + v2) * dir block size - * the directory bmap btree could join or split: (max depth + v2) * blocksize - * And the bmap_finish transaction can free some bmap blocks giving: - * the agf for the ag in which the blocks live: sector size - * the agfl for the ag in which the blocks live: sector size - * the superblock for the free block count: sector size - * the allocation btrees: 2 trees * (2 * max depth - 1) * block size - */ -#define XFS_CALC_LINK_LOG_RES(mp) \ - (MAX( \ - ((mp)->m_sb.sb_inodesize + \ - (mp)->m_sb.sb_inodesize + \ - XFS_DIROP_LOG_RES(mp) + \ - (128 * (2 + XFS_DIROP_LOG_COUNT(mp)))), \ - ((mp)->m_sb.sb_sectsize + \ - (mp)->m_sb.sb_sectsize + \ - (mp)->m_sb.sb_sectsize + \ - XFS_ALLOCFREE_LOG_RES(mp, 1) + \ - (128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) - #define XFS_LINK_LOG_RES(mp) ((mp)->m_reservations.tr_link) - -/* - * For removing a directory entry we can modify: - * the parent directory inode: inode size - * the removed inode: inode size - * the directory btree could join: (max depth + v2) * dir block size - * the directory bmap btree could join or split: (max depth + v2) * blocksize - * And the bmap_finish transaction can free the dir and bmap blocks giving: - * the agf for the ag in which the blocks live: 2 * sector size - * the agfl for the ag in which the blocks live: 2 * sector size - * the superblock for the free block count: sector size - * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size - */ -#define XFS_CALC_REMOVE_LOG_RES(mp) \ - (MAX( \ - ((mp)->m_sb.sb_inodesize + \ - (mp)->m_sb.sb_inodesize + \ - XFS_DIROP_LOG_RES(mp) + \ - (128 * (2 + XFS_DIROP_LOG_COUNT(mp)))), \ - ((2 * (mp)->m_sb.sb_sectsize) + \ - (2 * (mp)->m_sb.sb_sectsize) + \ - (mp)->m_sb.sb_sectsize + \ - XFS_ALLOCFREE_LOG_RES(mp, 2) + \ - (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) - #define XFS_REMOVE_LOG_RES(mp) ((mp)->m_reservations.tr_remove) - -/* - * For symlink we can modify: - * the parent directory inode: inode size - * the new inode: inode size - * the inode btree entry: 1 block - * the directory btree: (max depth + v2) * dir block size - * the directory inode's bmap btree: (max depth + v2) * block size - * the blocks for the symlink: 1 kB - * Or in the first xact we allocate some inodes giving: - * the agi and agf of the ag getting the new inodes: 2 * sectorsize - * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize - * the inode btree: max depth * blocksize - * the allocation btrees: 2 trees * (2 * max depth - 1) * block size - */ -#define XFS_CALC_SYMLINK_LOG_RES(mp) \ - (MAX( \ - ((mp)->m_sb.sb_inodesize + \ - (mp)->m_sb.sb_inodesize + \ - XFS_FSB_TO_B(mp, 1) + \ - XFS_DIROP_LOG_RES(mp) + \ - 1024 + \ - (128 * (4 + XFS_DIROP_LOG_COUNT(mp)))), \ - (2 * (mp)->m_sb.sb_sectsize + \ - XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \ - XFS_FSB_TO_B((mp), (mp)->m_in_maxlevels) + \ - XFS_ALLOCFREE_LOG_RES(mp, 1) + \ - (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \ - XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) - #define XFS_SYMLINK_LOG_RES(mp) ((mp)->m_reservations.tr_symlink) - -/* - * For create we can modify: - * the parent directory inode: inode size - * the new inode: inode size - * the inode btree entry: block size - * the superblock for the nlink flag: sector size - * the directory btree: (max depth + v2) * dir block size - * the directory inode's bmap btree: (max depth + v2) * block size - * Or in the first xact we allocate some inodes giving: - * the agi and agf of the ag getting the new inodes: 2 * sectorsize - * the superblock for the nlink flag: sector size - * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize - * the inode btree: max depth * blocksize - * the allocation btrees: 2 trees * (max depth - 1) * block size - */ -#define XFS_CALC_CREATE_LOG_RES(mp) \ - (MAX( \ - ((mp)->m_sb.sb_inodesize + \ - (mp)->m_sb.sb_inodesize + \ - (mp)->m_sb.sb_sectsize + \ - XFS_FSB_TO_B(mp, 1) + \ - XFS_DIROP_LOG_RES(mp) + \ - (128 * (3 + XFS_DIROP_LOG_COUNT(mp)))), \ - (3 * (mp)->m_sb.sb_sectsize + \ - XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \ - XFS_FSB_TO_B((mp), (mp)->m_in_maxlevels) + \ - XFS_ALLOCFREE_LOG_RES(mp, 1) + \ - (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \ - XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) - #define XFS_CREATE_LOG_RES(mp) ((mp)->m_reservations.tr_create) - -/* - * Making a new directory is the same as creating a new file. - */ -#define XFS_CALC_MKDIR_LOG_RES(mp) XFS_CALC_CREATE_LOG_RES(mp) - #define XFS_MKDIR_LOG_RES(mp) ((mp)->m_reservations.tr_mkdir) - -/* - * In freeing an inode we can modify: - * the inode being freed: inode size - * the super block free inode counter: sector size - * the agi hash list and counters: sector size - * the inode btree entry: block size - * the on disk inode before ours in the agi hash list: inode cluster size - * the inode btree: max depth * blocksize - * the allocation btrees: 2 trees * (max depth - 1) * block size - */ -#define XFS_CALC_IFREE_LOG_RES(mp) \ - ((mp)->m_sb.sb_inodesize + \ - (mp)->m_sb.sb_sectsize + \ - (mp)->m_sb.sb_sectsize + \ - XFS_FSB_TO_B((mp), 1) + \ - MAX((__uint16_t)XFS_FSB_TO_B((mp), 1), XFS_INODE_CLUSTER_SIZE(mp)) + \ - (128 * 5) + \ - XFS_ALLOCFREE_LOG_RES(mp, 1) + \ - (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \ - XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) - - #define XFS_IFREE_LOG_RES(mp) ((mp)->m_reservations.tr_ifree) - -/* - * When only changing the inode we log the inode and possibly the superblock - * We also add a bit of slop for the transaction stuff. - */ -#define XFS_CALC_ICHANGE_LOG_RES(mp) ((mp)->m_sb.sb_inodesize + \ - (mp)->m_sb.sb_sectsize + 512) - #define XFS_ICHANGE_LOG_RES(mp) ((mp)->m_reservations.tr_ichange) - -/* - * Growing the data section of the filesystem. - * superblock - * agi and agf - * allocation btrees - */ -#define XFS_CALC_GROWDATA_LOG_RES(mp) \ - ((mp)->m_sb.sb_sectsize * 3 + \ - XFS_ALLOCFREE_LOG_RES(mp, 1) + \ - (128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) - #define XFS_GROWDATA_LOG_RES(mp) ((mp)->m_reservations.tr_growdata) - -/* - * Growing the rt section of the filesystem. - * In the first set of transactions (ALLOC) we allocate space to the - * bitmap or summary files. - * superblock: sector size - * agf of the ag from which the extent is allocated: sector size - * bmap btree for bitmap/summary inode: max depth * blocksize - * bitmap/summary inode: inode size - * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize - */ -#define XFS_CALC_GROWRTALLOC_LOG_RES(mp) \ - (2 * (mp)->m_sb.sb_sectsize + \ - XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + \ - (mp)->m_sb.sb_inodesize + \ - XFS_ALLOCFREE_LOG_RES(mp, 1) + \ - (128 * \ - (3 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + \ - XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) - #define XFS_GROWRTALLOC_LOG_RES(mp) ((mp)->m_reservations.tr_growrtalloc) - -/* - * Growing the rt section of the filesystem. - * In the second set of transactions (ZERO) we zero the new metadata blocks. - * one bitmap/summary block: blocksize - */ -#define XFS_CALC_GROWRTZERO_LOG_RES(mp) \ - ((mp)->m_sb.sb_blocksize + 128) - #define XFS_GROWRTZERO_LOG_RES(mp) ((mp)->m_reservations.tr_growrtzero) - -/* - * Growing the rt section of the filesystem. - * In the third set of transactions (FREE) we update metadata without - * allocating any new blocks. - * superblock: sector size - * bitmap inode: inode size - * summary inode: inode size - * one bitmap block: blocksize - * summary blocks: new summary size - */ -#define XFS_CALC_GROWRTFREE_LOG_RES(mp) \ - ((mp)->m_sb.sb_sectsize + \ - 2 * (mp)->m_sb.sb_inodesize + \ - (mp)->m_sb.sb_blocksize + \ - (mp)->m_rsumsize + \ - (128 * 5)) - #define XFS_GROWRTFREE_LOG_RES(mp) ((mp)->m_reservations.tr_growrtfree) - -/* - * Logging the inode modification timestamp on a synchronous write. - * inode - */ -#define XFS_CALC_SWRITE_LOG_RES(mp) \ - ((mp)->m_sb.sb_inodesize + 128) - #define XFS_SWRITE_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) - /* * Logging the inode timestamps on an fsync -- same as SWRITE * as long as SWRITE logs the entire inode core */ #define XFS_FSYNC_TS_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) - -/* - * Logging the inode mode bits when writing a setuid/setgid file - * inode - */ -#define XFS_CALC_WRITEID_LOG_RES(mp) \ - ((mp)->m_sb.sb_inodesize + 128) - #define XFS_WRITEID_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) - -/* - * Converting the inode from non-attributed to attributed. - * the inode being converted: inode size - * agf block and superblock (for block allocation) - * the new block (directory sized) - * bmap blocks for the new directory block - * allocation btrees - */ -#define XFS_CALC_ADDAFORK_LOG_RES(mp) \ - ((mp)->m_sb.sb_inodesize + \ - (mp)->m_sb.sb_sectsize * 2 + \ - (mp)->m_dirblksize + \ - XFS_FSB_TO_B(mp, (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1)) + \ - XFS_ALLOCFREE_LOG_RES(mp, 1) + \ - (128 * (4 + (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) + \ - XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) - #define XFS_ADDAFORK_LOG_RES(mp) ((mp)->m_reservations.tr_addafork) - -/* - * Removing the attribute fork of a file - * the inode being truncated: inode size - * the inode's bmap btree: max depth * block size - * And the bmap_finish transaction can free the blocks and bmap blocks: - * the agf for each of the ags: 4 * sector size - * the agfl for each of the ags: 4 * sector size - * the super block to reflect the freed blocks: sector size - * worst case split in allocation btrees per extent assuming 4 extents: - * 4 exts * 2 trees * (2 * max depth - 1) * block size - */ -#define XFS_CALC_ATTRINVAL_LOG_RES(mp) \ - (MAX( \ - ((mp)->m_sb.sb_inodesize + \ - XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + \ - (128 * (1 + XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)))), \ - ((4 * (mp)->m_sb.sb_sectsize) + \ - (4 * (mp)->m_sb.sb_sectsize) + \ - (mp)->m_sb.sb_sectsize + \ - XFS_ALLOCFREE_LOG_RES(mp, 4) + \ - (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)))))) - #define XFS_ATTRINVAL_LOG_RES(mp) ((mp)->m_reservations.tr_attrinval) - -/* - * Setting an attribute. - * the inode getting the attribute - * the superblock for allocations - * the agfs extents are allocated from - * the attribute btree * max depth - * the inode allocation btree - * Since attribute transaction space is dependent on the size of the attribute, - * the calculation is done partially at mount time and partially at runtime. - */ -#define XFS_CALC_ATTRSET_LOG_RES(mp) \ - ((mp)->m_sb.sb_inodesize + \ - (mp)->m_sb.sb_sectsize + \ - XFS_FSB_TO_B((mp), XFS_DA_NODE_MAXDEPTH) + \ - (128 * (2 + XFS_DA_NODE_MAXDEPTH))) - #define XFS_ATTRSET_LOG_RES(mp, ext) \ ((mp)->m_reservations.tr_attrset + \ (ext * (mp)->m_sb.sb_sectsize) + \ (ext * XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))) + \ (128 * (ext + (ext * XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))))) - -/* - * Removing an attribute. - * the inode: inode size - * the attribute btree could join: max depth * block size - * the inode bmap btree could join or split: max depth * block size - * And the bmap_finish transaction can free the attr blocks freed giving: - * the agf for the ag in which the blocks live: 2 * sector size - * the agfl for the ag in which the blocks live: 2 * sector size - * the superblock for the free block count: sector size - * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size - */ -#define XFS_CALC_ATTRRM_LOG_RES(mp) \ - (MAX( \ - ((mp)->m_sb.sb_inodesize + \ - XFS_FSB_TO_B((mp), XFS_DA_NODE_MAXDEPTH) + \ - XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + \ - (128 * (1 + XFS_DA_NODE_MAXDEPTH + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)))), \ - ((2 * (mp)->m_sb.sb_sectsize) + \ - (2 * (mp)->m_sb.sb_sectsize) + \ - (mp)->m_sb.sb_sectsize + \ - XFS_ALLOCFREE_LOG_RES(mp, 2) + \ - (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) - #define XFS_ATTRRM_LOG_RES(mp) ((mp)->m_reservations.tr_attrrm) - -/* - * Clearing a bad agino number in an agi hash bucket. - */ -#define XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp) \ - ((mp)->m_sb.sb_sectsize + 128) - #define XFS_CLEAR_AGI_BUCKET_LOG_RES(mp) ((mp)->m_reservations.tr_clearagi) -- GitLab From fdc07f44c891d3fdee7722a03e3881614a293b3c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig <hch@infradead.org> Date: Mon, 10 May 2010 17:28:14 +0000 Subject: [PATCH 270/842] xfs: clean up xlog_align Add suggested cleanups to commit 29db3370a1369541d58d692fbfb168b8a0bd7f41 from review that didn't end up being commited. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/xfs_log_recover.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 14a69aec2c0b..ed0684cc50ee 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -132,15 +132,10 @@ xlog_align( int nbblks, xfs_buf_t *bp) { - xfs_daddr_t offset; - xfs_caddr_t ptr; + xfs_daddr_t offset = blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1); - offset = blk_no & ((xfs_daddr_t) log->l_sectBBsize - 1); - ptr = XFS_BUF_PTR(bp) + BBTOB(offset); - - ASSERT(ptr + BBTOB(nbblks) <= XFS_BUF_PTR(bp) + XFS_BUF_SIZE(bp)); - - return ptr; + ASSERT(BBTOB(offset + nbblks) <= XFS_BUF_SIZE(bp)); + return XFS_BUF_PTR(bp) + BBTOB(offset); } -- GitLab From 07f1a4f5e89cd4e6c79d67d41e8a18c451214ae2 Mon Sep 17 00:00:00 2001 From: Dave Chinner <dchinner@redhat.com> Date: Fri, 21 May 2010 05:47:59 +0000 Subject: [PATCH 271/842] xfs: Check new inode size is OK before preallocating The new xfsqa test 228 tries to preallocate more space than the filesystem contains. it should fail, but instead triggers an assert about lock flags. The failure is due to the size extension failing in vmtruncate() due to rlimit being set. Check this before we start the preallocation to avoid allocating space that will never be used. Also the path through xfs_vn_allocate already holds the IO lock, so it should not be present in the lock flags when the setattr fails. Hence the assert needs to take this into account. This will prevent other such callers from hitting this incorrect ASSERT. (Fixed a reference to "newsize" to read "new_size". -Alex) Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/linux-2.6/xfs_iops.c | 16 +++++++++++++--- fs/xfs/xfs_vnodeops.c | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 9c8019c78c92..44f0b2de153e 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -585,11 +585,20 @@ xfs_vn_fallocate( bf.l_len = len; xfs_ilock(ip, XFS_IOLOCK_EXCL); + + /* check the new inode size is valid before allocating */ + if (!(mode & FALLOC_FL_KEEP_SIZE) && + offset + len > i_size_read(inode)) { + new_size = offset + len; + error = inode_newsize_ok(inode, new_size); + if (error) + goto out_unlock; + } + error = -xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf, 0, XFS_ATTR_NOLOCK); - if (!error && !(mode & FALLOC_FL_KEEP_SIZE) && - offset + len > i_size_read(inode)) - new_size = offset + len; + if (error) + goto out_unlock; /* Change file size if needed */ if (new_size) { @@ -600,6 +609,7 @@ xfs_vn_fallocate( error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK); } +out_unlock: xfs_iunlock(ip, XFS_IOLOCK_EXCL); out_error: return error; diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 9d376be0ea38..a06bd62504fc 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -267,7 +267,7 @@ xfs_setattr( if (code) { ASSERT(tp == NULL); lock_flags &= ~XFS_ILOCK_EXCL; - ASSERT(lock_flags == XFS_IOLOCK_EXCL); + ASSERT(lock_flags == XFS_IOLOCK_EXCL || !need_iolock); goto error_return; } tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); -- GitLab From 292ec4cf3536a5ed8809e8823341b203e497bbaf Mon Sep 17 00:00:00 2001 From: Huang Weiyi <weiyi.huang@gmail.com> Date: Sat, 22 May 2010 17:13:20 +0000 Subject: [PATCH 272/842] xfs: xfs_trace.c: remove duplicated #include Remove duplicated #include('s) in fs/xfs/linux-2.6/xfs_trace.c Signed-off-by: Huang Weiyi <weiyi.huang@gmail.com> Reviewed-by: Dave Chinner <david@fromorbit.com> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/linux-2.6/xfs_trace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/xfs/linux-2.6/xfs_trace.c b/fs/xfs/linux-2.6/xfs_trace.c index 207fa77f63ae..d12be8470cba 100644 --- a/fs/xfs/linux-2.6/xfs_trace.c +++ b/fs/xfs/linux-2.6/xfs_trace.c @@ -50,7 +50,6 @@ #include "quota/xfs_dquot_item.h" #include "quota/xfs_dquot.h" #include "xfs_log_recover.h" -#include "xfs_buf_item.h" #include "xfs_inode_item.h" /* -- GitLab From f8adb4d574cf8c67f8391367136edc5469258fdc Mon Sep 17 00:00:00 2001 From: Li Zefan <lizf@cn.fujitsu.com> Date: Mon, 24 May 2010 08:25:57 +0000 Subject: [PATCH 273/842] xfs: convert more trace events to DEFINE_EVENT Use DECLARE_EVENT_CLASS, and save ~15K: text data bss dec hex filename 171949 43028 48 215025 347f1 fs/xfs/linux-2.6/xfs_trace.o.orig 156521 43028 36 199585 30ba1 fs/xfs/linux-2.6/xfs_trace.o No change in functionality. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/linux-2.6/xfs_trace.h | 356 ++++++++++++++++++----------------- 1 file changed, 188 insertions(+), 168 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/linux-2.6/xfs_trace.h index ff6bc797baf2..73d5aa117384 100644 --- a/fs/xfs/linux-2.6/xfs_trace.h +++ b/fs/xfs/linux-2.6/xfs_trace.h @@ -82,33 +82,6 @@ DECLARE_EVENT_CLASS(xfs_attr_list_class, ) ) -#define DEFINE_PERAG_REF_EVENT(name) \ -TRACE_EVENT(name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, \ - unsigned long caller_ip), \ - TP_ARGS(mp, agno, refcount, caller_ip), \ - TP_STRUCT__entry( \ - __field(dev_t, dev) \ - __field(xfs_agnumber_t, agno) \ - __field(int, refcount) \ - __field(unsigned long, caller_ip) \ - ), \ - TP_fast_assign( \ - __entry->dev = mp->m_super->s_dev; \ - __entry->agno = agno; \ - __entry->refcount = refcount; \ - __entry->caller_ip = caller_ip; \ - ), \ - TP_printk("dev %d:%d agno %u refcount %d caller %pf", \ - MAJOR(__entry->dev), MINOR(__entry->dev), \ - __entry->agno, \ - __entry->refcount, \ - (char *)__entry->caller_ip) \ -); - -DEFINE_PERAG_REF_EVENT(xfs_perag_get) -DEFINE_PERAG_REF_EVENT(xfs_perag_put) - #define DEFINE_ATTR_LIST_EVENT(name) \ DEFINE_EVENT(xfs_attr_list_class, name, \ TP_PROTO(struct xfs_attr_list_context *ctx), \ @@ -122,6 +95,37 @@ DEFINE_ATTR_LIST_EVENT(xfs_attr_list_add); DEFINE_ATTR_LIST_EVENT(xfs_attr_list_wrong_blk); DEFINE_ATTR_LIST_EVENT(xfs_attr_list_notfound); +DECLARE_EVENT_CLASS(xfs_perag_class, + TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, + unsigned long caller_ip), + TP_ARGS(mp, agno, refcount, caller_ip), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_agnumber_t, agno) + __field(int, refcount) + __field(unsigned long, caller_ip) + ), + TP_fast_assign( + __entry->dev = mp->m_super->s_dev; + __entry->agno = agno; + __entry->refcount = refcount; + __entry->caller_ip = caller_ip; + ), + TP_printk("dev %d:%d agno %u refcount %d caller %pf", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->agno, + __entry->refcount, + (char *)__entry->caller_ip) +); + +#define DEFINE_PERAG_REF_EVENT(name) \ +DEFINE_EVENT(xfs_perag_class, name, \ + TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, \ + unsigned long caller_ip), \ + TP_ARGS(mp, agno, refcount, caller_ip)) +DEFINE_PERAG_REF_EVENT(xfs_perag_get); +DEFINE_PERAG_REF_EVENT(xfs_perag_put); + TRACE_EVENT(xfs_attr_list_node_descend, TP_PROTO(struct xfs_attr_list_context *ctx, struct xfs_da_node_entry *btree), @@ -775,165 +779,181 @@ DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_enter); DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_exit); DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_sub); -#define DEFINE_RW_EVENT(name) \ -TRACE_EVENT(name, \ - TP_PROTO(struct xfs_inode *ip, size_t count, loff_t offset, int flags), \ - TP_ARGS(ip, count, offset, flags), \ - TP_STRUCT__entry( \ - __field(dev_t, dev) \ - __field(xfs_ino_t, ino) \ - __field(xfs_fsize_t, size) \ - __field(xfs_fsize_t, new_size) \ - __field(loff_t, offset) \ - __field(size_t, count) \ - __field(int, flags) \ - ), \ - TP_fast_assign( \ - __entry->dev = VFS_I(ip)->i_sb->s_dev; \ - __entry->ino = ip->i_ino; \ - __entry->size = ip->i_d.di_size; \ - __entry->new_size = ip->i_new_size; \ - __entry->offset = offset; \ - __entry->count = count; \ - __entry->flags = flags; \ - ), \ - TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " \ - "offset 0x%llx count 0x%zx ioflags %s", \ - MAJOR(__entry->dev), MINOR(__entry->dev), \ - __entry->ino, \ - __entry->size, \ - __entry->new_size, \ - __entry->offset, \ - __entry->count, \ - __print_flags(__entry->flags, "|", XFS_IO_FLAGS)) \ +DECLARE_EVENT_CLASS(xfs_file_class, + TP_PROTO(struct xfs_inode *ip, size_t count, loff_t offset, int flags), + TP_ARGS(ip, count, offset, flags), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(xfs_fsize_t, size) + __field(xfs_fsize_t, new_size) + __field(loff_t, offset) + __field(size_t, count) + __field(int, flags) + ), + TP_fast_assign( + __entry->dev = VFS_I(ip)->i_sb->s_dev; + __entry->ino = ip->i_ino; + __entry->size = ip->i_d.di_size; + __entry->new_size = ip->i_new_size; + __entry->offset = offset; + __entry->count = count; + __entry->flags = flags; + ), + TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " + "offset 0x%llx count 0x%zx ioflags %s", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->size, + __entry->new_size, + __entry->offset, + __entry->count, + __print_flags(__entry->flags, "|", XFS_IO_FLAGS)) ) + +#define DEFINE_RW_EVENT(name) \ +DEFINE_EVENT(xfs_file_class, name, \ + TP_PROTO(struct xfs_inode *ip, size_t count, loff_t offset, int flags), \ + TP_ARGS(ip, count, offset, flags)) DEFINE_RW_EVENT(xfs_file_read); DEFINE_RW_EVENT(xfs_file_buffered_write); DEFINE_RW_EVENT(xfs_file_direct_write); DEFINE_RW_EVENT(xfs_file_splice_read); DEFINE_RW_EVENT(xfs_file_splice_write); - -#define DEFINE_PAGE_EVENT(name) \ -TRACE_EVENT(name, \ - TP_PROTO(struct inode *inode, struct page *page, unsigned long off), \ - TP_ARGS(inode, page, off), \ - TP_STRUCT__entry( \ - __field(dev_t, dev) \ - __field(xfs_ino_t, ino) \ - __field(pgoff_t, pgoff) \ - __field(loff_t, size) \ - __field(unsigned long, offset) \ - __field(int, delalloc) \ - __field(int, unmapped) \ - __field(int, unwritten) \ - ), \ - TP_fast_assign( \ - int delalloc = -1, unmapped = -1, unwritten = -1; \ - \ - if (page_has_buffers(page)) \ - xfs_count_page_state(page, &delalloc, \ - &unmapped, &unwritten); \ - __entry->dev = inode->i_sb->s_dev; \ - __entry->ino = XFS_I(inode)->i_ino; \ - __entry->pgoff = page_offset(page); \ - __entry->size = i_size_read(inode); \ - __entry->offset = off; \ - __entry->delalloc = delalloc; \ - __entry->unmapped = unmapped; \ - __entry->unwritten = unwritten; \ - ), \ - TP_printk("dev %d:%d ino 0x%llx pgoff 0x%lx size 0x%llx offset %lx " \ - "delalloc %d unmapped %d unwritten %d", \ - MAJOR(__entry->dev), MINOR(__entry->dev), \ - __entry->ino, \ - __entry->pgoff, \ - __entry->size, \ - __entry->offset, \ - __entry->delalloc, \ - __entry->unmapped, \ - __entry->unwritten) \ +DECLARE_EVENT_CLASS(xfs_page_class, + TP_PROTO(struct inode *inode, struct page *page, unsigned long off), + TP_ARGS(inode, page, off), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(pgoff_t, pgoff) + __field(loff_t, size) + __field(unsigned long, offset) + __field(int, delalloc) + __field(int, unmapped) + __field(int, unwritten) + ), + TP_fast_assign( + int delalloc = -1, unmapped = -1, unwritten = -1; + + if (page_has_buffers(page)) + xfs_count_page_state(page, &delalloc, + &unmapped, &unwritten); + __entry->dev = inode->i_sb->s_dev; + __entry->ino = XFS_I(inode)->i_ino; + __entry->pgoff = page_offset(page); + __entry->size = i_size_read(inode); + __entry->offset = off; + __entry->delalloc = delalloc; + __entry->unmapped = unmapped; + __entry->unwritten = unwritten; + ), + TP_printk("dev %d:%d ino 0x%llx pgoff 0x%lx size 0x%llx offset %lx " + "delalloc %d unmapped %d unwritten %d", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->pgoff, + __entry->size, + __entry->offset, + __entry->delalloc, + __entry->unmapped, + __entry->unwritten) ) + +#define DEFINE_PAGE_EVENT(name) \ +DEFINE_EVENT(xfs_page_class, name, \ + TP_PROTO(struct inode *inode, struct page *page, unsigned long off), \ + TP_ARGS(inode, page, off)) DEFINE_PAGE_EVENT(xfs_writepage); DEFINE_PAGE_EVENT(xfs_releasepage); DEFINE_PAGE_EVENT(xfs_invalidatepage); -#define DEFINE_IOMAP_EVENT(name) \ -TRACE_EVENT(name, \ - TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count, \ - int flags, struct xfs_bmbt_irec *irec), \ - TP_ARGS(ip, offset, count, flags, irec), \ - TP_STRUCT__entry( \ - __field(dev_t, dev) \ - __field(xfs_ino_t, ino) \ - __field(loff_t, size) \ - __field(loff_t, new_size) \ - __field(loff_t, offset) \ - __field(size_t, count) \ - __field(int, flags) \ - __field(xfs_fileoff_t, startoff) \ - __field(xfs_fsblock_t, startblock) \ - __field(xfs_filblks_t, blockcount) \ - ), \ - TP_fast_assign( \ - __entry->dev = VFS_I(ip)->i_sb->s_dev; \ - __entry->ino = ip->i_ino; \ - __entry->size = ip->i_d.di_size; \ - __entry->new_size = ip->i_new_size; \ - __entry->offset = offset; \ - __entry->count = count; \ - __entry->flags = flags; \ - __entry->startoff = irec ? irec->br_startoff : 0; \ - __entry->startblock = irec ? irec->br_startblock : 0; \ - __entry->blockcount = irec ? irec->br_blockcount : 0; \ - ), \ - TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " \ - "offset 0x%llx count %zd flags %s " \ - "startoff 0x%llx startblock %lld blockcount 0x%llx", \ - MAJOR(__entry->dev), MINOR(__entry->dev), \ - __entry->ino, \ - __entry->size, \ - __entry->new_size, \ - __entry->offset, \ - __entry->count, \ - __print_flags(__entry->flags, "|", BMAPI_FLAGS), \ - __entry->startoff, \ - (__int64_t)__entry->startblock, \ - __entry->blockcount) \ +DECLARE_EVENT_CLASS(xfs_iomap_class, + TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count, + int flags, struct xfs_bmbt_irec *irec), + TP_ARGS(ip, offset, count, flags, irec), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(loff_t, size) + __field(loff_t, new_size) + __field(loff_t, offset) + __field(size_t, count) + __field(int, flags) + __field(xfs_fileoff_t, startoff) + __field(xfs_fsblock_t, startblock) + __field(xfs_filblks_t, blockcount) + ), + TP_fast_assign( + __entry->dev = VFS_I(ip)->i_sb->s_dev; + __entry->ino = ip->i_ino; + __entry->size = ip->i_d.di_size; + __entry->new_size = ip->i_new_size; + __entry->offset = offset; + __entry->count = count; + __entry->flags = flags; + __entry->startoff = irec ? irec->br_startoff : 0; + __entry->startblock = irec ? irec->br_startblock : 0; + __entry->blockcount = irec ? irec->br_blockcount : 0; + ), + TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " + "offset 0x%llx count %zd flags %s " + "startoff 0x%llx startblock %lld blockcount 0x%llx", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->size, + __entry->new_size, + __entry->offset, + __entry->count, + __print_flags(__entry->flags, "|", BMAPI_FLAGS), + __entry->startoff, + (__int64_t)__entry->startblock, + __entry->blockcount) ) + +#define DEFINE_IOMAP_EVENT(name) \ +DEFINE_EVENT(xfs_iomap_class, name, \ + TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count, \ + int flags, struct xfs_bmbt_irec *irec), \ + TP_ARGS(ip, offset, count, flags, irec)) DEFINE_IOMAP_EVENT(xfs_iomap_enter); DEFINE_IOMAP_EVENT(xfs_iomap_found); DEFINE_IOMAP_EVENT(xfs_iomap_alloc); -#define DEFINE_SIMPLE_IO_EVENT(name) \ -TRACE_EVENT(name, \ - TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count), \ - TP_ARGS(ip, offset, count), \ - TP_STRUCT__entry( \ - __field(dev_t, dev) \ - __field(xfs_ino_t, ino) \ - __field(loff_t, size) \ - __field(loff_t, new_size) \ - __field(loff_t, offset) \ - __field(size_t, count) \ - ), \ - TP_fast_assign( \ - __entry->dev = VFS_I(ip)->i_sb->s_dev; \ - __entry->ino = ip->i_ino; \ - __entry->size = ip->i_d.di_size; \ - __entry->new_size = ip->i_new_size; \ - __entry->offset = offset; \ - __entry->count = count; \ - ), \ - TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " \ - "offset 0x%llx count %zd", \ - MAJOR(__entry->dev), MINOR(__entry->dev), \ - __entry->ino, \ - __entry->size, \ - __entry->new_size, \ - __entry->offset, \ - __entry->count) \ +DECLARE_EVENT_CLASS(xfs_simple_io_class, + TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count), + TP_ARGS(ip, offset, count), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(loff_t, size) + __field(loff_t, new_size) + __field(loff_t, offset) + __field(size_t, count) + ), + TP_fast_assign( + __entry->dev = VFS_I(ip)->i_sb->s_dev; + __entry->ino = ip->i_ino; + __entry->size = ip->i_d.di_size; + __entry->new_size = ip->i_new_size; + __entry->offset = offset; + __entry->count = count; + ), + TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " + "offset 0x%llx count %zd", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->size, + __entry->new_size, + __entry->offset, + __entry->count) ); + +#define DEFINE_SIMPLE_IO_EVENT(name) \ +DEFINE_EVENT(xfs_simple_io_class, name, \ + TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count), \ + TP_ARGS(ip, offset, count)) DEFINE_SIMPLE_IO_EVENT(xfs_delalloc_enospc); DEFINE_SIMPLE_IO_EVENT(xfs_unwritten_convert); -- GitLab From 3bd0946eb157e26240ca858d1a42738b095dc6f3 Mon Sep 17 00:00:00 2001 From: Huang Weiyi <weiyi.huang@gmail.com> Date: Tue, 25 May 2010 22:15:26 +0000 Subject: [PATCH 274/842] xfs: remove duplicated #include Remove duplicated #include('s) in fs/xfs/linux-2.6/xfs_quotaops.c Signed-off-by: Huang Weiyi <weiyi.huang@gmail.com> Reviewed-by: Dave Chinner <david@fromorbit.com> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/linux-2.6/xfs_quotaops.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/xfs/linux-2.6/xfs_quotaops.c b/fs/xfs/linux-2.6/xfs_quotaops.c index 2e73688dae9c..a184793f2399 100644 --- a/fs/xfs/linux-2.6/xfs_quotaops.c +++ b/fs/xfs/linux-2.6/xfs_quotaops.c @@ -23,7 +23,6 @@ #include "xfs_ag.h" #include "xfs_mount.h" #include "xfs_quota.h" -#include "xfs_log.h" #include "xfs_trans.h" #include "xfs_bmap_btree.h" #include "xfs_inode.h" -- GitLab From 38e712ab3d28d79725eaade02fe8aba51abac196 Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Wed, 26 May 2010 15:57:23 +0000 Subject: [PATCH 275/842] fs/xfs/quota: Add missing mutex_unlock Add a mutex_unlock missing on the error path. The use of this lock is balanced elsewhere in the file. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @@ expression E1; @@ * mutex_lock(E1,...); <+... when != E1 if (...) { ... when != E1 * return ...; } ...+> * mutex_unlock(E1,...); // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/quota/xfs_qm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 38e764146644..2d8b7bc792c9 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -249,8 +249,10 @@ xfs_qm_hold_quotafs_ref( if (!xfs_Gqm) { xfs_Gqm = xfs_Gqm_init(); - if (!xfs_Gqm) + if (!xfs_Gqm) { + mutex_unlock(&xfs_Gqm_lock); return ENOMEM; + } } /* -- GitLab From 9b98b6f3e1534bba2efcd5b16318945cf2218d99 Mon Sep 17 00:00:00 2001 From: Dave Chinner <dchinner@redhat.com> Date: Thu, 27 May 2010 01:58:13 +0000 Subject: [PATCH 276/842] xfs: fix might_sleep() warning when initialising per-ag tree The use of radix_tree_preload() only works if the radix tree was initialised without the __GFP_WAIT flag. The per-ag tree uses GFP_NOFS, so does not trigger allocation of new tree nodes from the preloaded array. Hence it enters the allocator with a spinlock held and triggers the might_sleep() warnings. Reported-by; Chris Mason <chris.mason@oracle.com> Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/xfs_mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 2d811e57b332..ef1233b09683 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1254,7 +1254,7 @@ xfs_mountfs( * Allocate and initialize the per-ag data. */ spin_lock_init(&mp->m_perag_lock); - INIT_RADIX_TREE(&mp->m_perag_tree, GFP_NOFS); + INIT_RADIX_TREE(&mp->m_perag_tree, GFP_ATOMIC); error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi); if (error) { cmn_err(CE_WARN, "XFS: Failed per-ag init: %d", error); -- GitLab From fb3b504adeee942e55393396fea8fdf406acf037 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig <hch@infradead.org> Date: Fri, 28 May 2010 19:03:10 +0000 Subject: [PATCH 277/842] xfs: fix access to upper inodes without inode64 If a filesystem is mounted without the inode64 mount option we should still be able to access inodes not fitting into 32 bits, just not created new ones. For this to work we need to make sure the inode cache radix tree is initialized for all allocation groups, not just those we plan to allocate inodes from. This patch makes sure we initialize the inode cache radix tree for all allocation groups, and also cleans xfs_initialize_perag up a bit to separate the inode32 logical from the general perag structure setup. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com> --- fs/xfs/linux-2.6/xfs_sync.c | 9 ------- fs/xfs/xfs_ag.h | 1 - fs/xfs/xfs_iget.c | 3 --- fs/xfs/xfs_inode.c | 2 -- fs/xfs/xfs_mount.c | 52 +++++++++++++++---------------------- 5 files changed, 21 insertions(+), 46 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 3884e20bc14e..ef7f0218bccb 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -164,10 +164,6 @@ xfs_inode_ag_iterator( struct xfs_perag *pag; pag = xfs_perag_get(mp, ag); - if (!pag->pag_ici_init) { - xfs_perag_put(pag); - continue; - } error = xfs_inode_ag_walk(mp, pag, execute, flags, tag, exclusive, &nr); xfs_perag_put(pag); @@ -867,12 +863,7 @@ xfs_reclaim_inode_shrink( down_read(&xfs_mount_list_lock); list_for_each_entry(mp, &xfs_mount_list, m_mplist) { for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { - pag = xfs_perag_get(mp, ag); - if (!pag->pag_ici_init) { - xfs_perag_put(pag); - continue; - } reclaimable += pag->pag_ici_reclaimable; xfs_perag_put(pag); } diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index 401f364ad36c..4917d4eed4ed 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h @@ -227,7 +227,6 @@ typedef struct xfs_perag { atomic_t pagf_fstrms; /* # of filestreams active in this AG */ - int pag_ici_init; /* incore inode cache initialised */ rwlock_t pag_ici_lock; /* incore inode lock */ struct radix_tree_root pag_ici_root; /* incore inode cache root */ int pag_ici_reclaimable; /* reclaimable inodes */ diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 6845db90818f..f44a367907a8 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -382,9 +382,6 @@ xfs_iget( /* get the perag structure and ensure that it's inode capable */ pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino)); - if (!pag->pagi_inodeok) - return EINVAL; - ASSERT(pag->pag_ici_init); agino = XFS_INO_TO_AGINO(mp, ino); again: diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 8cd6e8d8fe9c..6ba7765026f6 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2649,8 +2649,6 @@ xfs_iflush_cluster( int i; pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); - ASSERT(pag->pagi_inodeok); - ASSERT(pag->pag_ici_init); inodes_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog; ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *); diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index ef1233b09683..d59f4e8bedcf 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -413,17 +413,6 @@ xfs_mount_validate_sb( return 0; } -STATIC void -xfs_initialize_perag_icache( - xfs_perag_t *pag) -{ - if (!pag->pag_ici_init) { - rwlock_init(&pag->pag_ici_lock); - INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC); - pag->pag_ici_init = 1; - } -} - int xfs_initialize_perag( xfs_mount_t *mp, @@ -436,13 +425,8 @@ xfs_initialize_perag( xfs_agino_t agino; xfs_ino_t ino; xfs_sb_t *sbp = &mp->m_sb; - xfs_ino_t max_inum = XFS_MAXINUMBER_32; int error = -ENOMEM; - /* Check to see if the filesystem can overflow 32 bit inodes */ - agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); - ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); - /* * Walk the current per-ag tree so we don't try to initialise AGs * that already exist (growfs case). Allocate and insert all the @@ -456,11 +440,18 @@ xfs_initialize_perag( } if (!first_initialised) first_initialised = index; + pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL); if (!pag) goto out_unwind; + pag->pag_agno = index; + pag->pag_mount = mp; + rwlock_init(&pag->pag_ici_lock); + INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC); + if (radix_tree_preload(GFP_NOFS)) goto out_unwind; + spin_lock(&mp->m_perag_lock); if (radix_tree_insert(&mp->m_perag_tree, index, pag)) { BUG(); @@ -469,25 +460,26 @@ xfs_initialize_perag( error = -EEXIST; goto out_unwind; } - pag->pag_agno = index; - pag->pag_mount = mp; spin_unlock(&mp->m_perag_lock); radix_tree_preload_end(); } - /* Clear the mount flag if no inode can overflow 32 bits - * on this filesystem, or if specifically requested.. + /* + * If we mount with the inode64 option, or no inode overflows + * the legacy 32-bit address space clear the inode32 option. */ - if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > max_inum) { + agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); + ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); + + if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > XFS_MAXINUMBER_32) mp->m_flags |= XFS_MOUNT_32BITINODES; - } else { + else mp->m_flags &= ~XFS_MOUNT_32BITINODES; - } - /* If we can overflow then setup the ag headers accordingly */ if (mp->m_flags & XFS_MOUNT_32BITINODES) { - /* Calculate how much should be reserved for inodes to - * meet the max inode percentage. + /* + * Calculate how much should be reserved for inodes to meet + * the max inode percentage. */ if (mp->m_maxicount) { __uint64_t icount; @@ -500,30 +492,28 @@ xfs_initialize_perag( } else { max_metadata = agcount; } + for (index = 0; index < agcount; index++) { ino = XFS_AGINO_TO_INO(mp, index, agino); - if (ino > max_inum) { + if (ino > XFS_MAXINUMBER_32) { index++; break; } - /* This ag is preferred for inodes */ pag = xfs_perag_get(mp, index); pag->pagi_inodeok = 1; if (index < max_metadata) pag->pagf_metadata = 1; - xfs_initialize_perag_icache(pag); xfs_perag_put(pag); } } else { - /* Setup default behavior for smaller filesystems */ for (index = 0; index < agcount; index++) { pag = xfs_perag_get(mp, index); pag->pagi_inodeok = 1; - xfs_initialize_perag_icache(pag); xfs_perag_put(pag); } } + if (maxagi) *maxagi = index; return 0; -- GitLab From d5a64513c6a171262082c250592c062e97a2c693 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" <rjw@sisk.pl> Date: Fri, 9 Apr 2010 01:39:40 +0200 Subject: [PATCH 278/842] ACPI / EC / PM: Fix race between EC transactions and system suspend There still is a race that may result in suspending the system in the middle of an EC transaction in progress, which leads to problems (like the kernel thinking that the ACPI global lock is held during resume while in fact it's not). To remove the race condition, modify the ACPI platform suspend and hibernate callbacks so that EC transactions are blocked right after executing the _PTS global control method and are allowed to happen again right after the low-level wakeup. Introduce acpi_pm_freeze() that will disable GPEs, wait until the event queues are empty and block EC transactions. Use it wherever GPEs are disabled in preparation for switching local interrupts off. Introduce acpi_pm_thaw() that will allow EC transactions to happen again and enable runtime GPEs. Use it to balance acpi_pm_freeze() wherever necessary. In addition to that use acpi_ec_resume_transactions_early() to unblock EC transactions as early as reasonably possible during resume. Also unblock EC transactions in acpi_hibernation_finish() and in the analogous suspend routine to make sure that the EC transactions are enabled in all error paths. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=14668 Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Reported-and-tested-by: Maxim Levitsky <maximlevitsky@gmail.com> Signed-off-by: Len Brown <len.brown@intel.com> --- drivers/acpi/ec.c | 10 ++++++++ drivers/acpi/internal.h | 1 + drivers/acpi/sleep.c | 55 ++++++++++++++++++++++------------------- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index f2234db85da0..2c2b73a2a7c2 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -485,6 +485,16 @@ void acpi_ec_resume_transactions(void) mutex_unlock(&ec->lock); } +void acpi_ec_resume_transactions_early(void) +{ + /* + * Allow transactions to happen again (this function is called from + * atomic context during wakeup, so we don't need to acquire the mutex). + */ + if (first_ec) + clear_bit(EC_FLAGS_FROZEN, &first_ec->flags); +} + static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) { int result; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index e28411367239..0ec48c7efa9b 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -51,6 +51,7 @@ int acpi_ec_ecdt_probe(void); int acpi_boot_ec_enable(void); void acpi_ec_suspend_transactions(void); void acpi_ec_resume_transactions(void); +void acpi_ec_resume_transactions_early(void); /*-------------------------------------------------------------------------- Suspend/Resume diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index baa76bbf244a..24741ac65897 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -110,11 +110,13 @@ void __init acpi_old_suspend_ordering(void) } /** - * acpi_pm_disable_gpes - Disable the GPEs. + * acpi_pm_freeze - Disable the GPEs and suspend EC transactions. */ -static int acpi_pm_disable_gpes(void) +static int acpi_pm_freeze(void) { acpi_disable_all_gpes(); + acpi_os_wait_events_complete(NULL); + acpi_ec_suspend_transactions(); return 0; } @@ -142,7 +144,8 @@ static int acpi_pm_prepare(void) int error = __acpi_pm_prepare(); if (!error) - acpi_disable_all_gpes(); + acpi_pm_freeze(); + return error; } @@ -275,6 +278,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state) * acpi_leave_sleep_state will reenable specific GPEs later */ acpi_disable_all_gpes(); + /* Allow EC transactions to happen. */ + acpi_ec_resume_transactions_early(); local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); @@ -286,6 +291,12 @@ static int acpi_suspend_enter(suspend_state_t pm_state) return ACPI_SUCCESS(status) ? 0 : -EFAULT; } +static void acpi_suspend_finish(void) +{ + acpi_ec_resume_transactions(); + acpi_pm_finish(); +} + static int acpi_suspend_state_valid(suspend_state_t pm_state) { u32 acpi_state; @@ -307,7 +318,7 @@ static struct platform_suspend_ops acpi_suspend_ops = { .begin = acpi_suspend_begin, .prepare_late = acpi_pm_prepare, .enter = acpi_suspend_enter, - .wake = acpi_pm_finish, + .wake = acpi_suspend_finish, .end = acpi_pm_end, }; @@ -333,9 +344,9 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state) static struct platform_suspend_ops acpi_suspend_ops_old = { .valid = acpi_suspend_state_valid, .begin = acpi_suspend_begin_old, - .prepare_late = acpi_pm_disable_gpes, + .prepare_late = acpi_pm_freeze, .enter = acpi_suspend_enter, - .wake = acpi_pm_finish, + .wake = acpi_suspend_finish, .end = acpi_pm_end, .recover = acpi_pm_finish, }; @@ -586,6 +597,7 @@ static int acpi_hibernation_enter(void) static void acpi_hibernation_finish(void) { hibernate_nvs_free(); + acpi_ec_resume_transactions(); acpi_pm_finish(); } @@ -606,17 +618,11 @@ static void acpi_hibernation_leave(void) } /* Restore the NVS memory area */ hibernate_nvs_restore(); + /* Allow EC transactions to happen. */ + acpi_ec_resume_transactions_early(); } -static int acpi_pm_pre_restore(void) -{ - acpi_disable_all_gpes(); - acpi_os_wait_events_complete(NULL); - acpi_ec_suspend_transactions(); - return 0; -} - -static void acpi_pm_restore_cleanup(void) +static void acpi_pm_thaw(void) { acpi_ec_resume_transactions(); acpi_enable_all_runtime_gpes(); @@ -630,8 +636,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops = { .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave, - .pre_restore = acpi_pm_pre_restore, - .restore_cleanup = acpi_pm_restore_cleanup, + .pre_restore = acpi_pm_freeze, + .restore_cleanup = acpi_pm_thaw, }; /** @@ -663,12 +669,9 @@ static int acpi_hibernation_begin_old(void) static int acpi_hibernation_pre_snapshot_old(void) { - int error = acpi_pm_disable_gpes(); - - if (!error) - hibernate_nvs_save(); - - return error; + acpi_pm_freeze(); + hibernate_nvs_save(); + return 0; } /* @@ -680,11 +683,11 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = { .end = acpi_pm_end, .pre_snapshot = acpi_hibernation_pre_snapshot_old, .finish = acpi_hibernation_finish, - .prepare = acpi_pm_disable_gpes, + .prepare = acpi_pm_freeze, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave, - .pre_restore = acpi_pm_pre_restore, - .restore_cleanup = acpi_pm_restore_cleanup, + .pre_restore = acpi_pm_freeze, + .restore_cleanup = acpi_pm_thaw, .recover = acpi_pm_finish, }; #endif /* CONFIG_HIBERNATION */ -- GitLab From fe955682d2153b35dffcf1673dff0491096a3f0a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" <rjw@sisk.pl> Date: Fri, 9 Apr 2010 01:40:38 +0200 Subject: [PATCH 279/842] ACPI / EC / PM: Fix names of functions that block/unblock EC transactions The names of the functions used for blocking/unblocking EC transactions during suspend/hibernation suggest that the transactions are suspended and resumed by them, while in fact they are disabled and enabled. Rename the functions (and the flag used by them) to better reflect what they really do. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Len Brown <len.brown@intel.com> --- drivers/acpi/ec.c | 16 ++++++++-------- drivers/acpi/internal.h | 6 +++--- drivers/acpi/sleep.c | 12 ++++++------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 2c2b73a2a7c2..3f01f065b533 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -79,7 +79,7 @@ enum { EC_FLAGS_GPE_STORM, /* GPE storm detected */ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and * OpReg are installed */ - EC_FLAGS_FROZEN, /* Transactions are suspended */ + EC_FLAGS_BLOCKED, /* Transactions are blocked */ }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ @@ -293,7 +293,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) if (t->rdata) memset(t->rdata, 0, t->rlen); mutex_lock(&ec->lock); - if (test_bit(EC_FLAGS_FROZEN, &ec->flags)) { + if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) { status = -EINVAL; goto unlock; } @@ -459,7 +459,7 @@ int ec_transaction(u8 command, EXPORT_SYMBOL(ec_transaction); -void acpi_ec_suspend_transactions(void) +void acpi_ec_block_transactions(void) { struct acpi_ec *ec = first_ec; @@ -468,11 +468,11 @@ void acpi_ec_suspend_transactions(void) mutex_lock(&ec->lock); /* Prevent transactions from being carried out */ - set_bit(EC_FLAGS_FROZEN, &ec->flags); + set_bit(EC_FLAGS_BLOCKED, &ec->flags); mutex_unlock(&ec->lock); } -void acpi_ec_resume_transactions(void) +void acpi_ec_unblock_transactions(void) { struct acpi_ec *ec = first_ec; @@ -481,18 +481,18 @@ void acpi_ec_resume_transactions(void) mutex_lock(&ec->lock); /* Allow transactions to be carried out again */ - clear_bit(EC_FLAGS_FROZEN, &ec->flags); + clear_bit(EC_FLAGS_BLOCKED, &ec->flags); mutex_unlock(&ec->lock); } -void acpi_ec_resume_transactions_early(void) +void acpi_ec_unblock_transactions_early(void) { /* * Allow transactions to happen again (this function is called from * atomic context during wakeup, so we don't need to acquire the mutex). */ if (first_ec) - clear_bit(EC_FLAGS_FROZEN, &first_ec->flags); + clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags); } static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 0ec48c7efa9b..f8f190ec066e 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -49,9 +49,9 @@ void acpi_early_processor_set_pdc(void); int acpi_ec_init(void); int acpi_ec_ecdt_probe(void); int acpi_boot_ec_enable(void); -void acpi_ec_suspend_transactions(void); -void acpi_ec_resume_transactions(void); -void acpi_ec_resume_transactions_early(void); +void acpi_ec_block_transactions(void); +void acpi_ec_unblock_transactions(void); +void acpi_ec_unblock_transactions_early(void); /*-------------------------------------------------------------------------- Suspend/Resume diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 24741ac65897..504a55edac49 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -116,7 +116,7 @@ static int acpi_pm_freeze(void) { acpi_disable_all_gpes(); acpi_os_wait_events_complete(NULL); - acpi_ec_suspend_transactions(); + acpi_ec_block_transactions(); return 0; } @@ -279,7 +279,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) */ acpi_disable_all_gpes(); /* Allow EC transactions to happen. */ - acpi_ec_resume_transactions_early(); + acpi_ec_unblock_transactions_early(); local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); @@ -293,7 +293,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) static void acpi_suspend_finish(void) { - acpi_ec_resume_transactions(); + acpi_ec_unblock_transactions(); acpi_pm_finish(); } @@ -597,7 +597,7 @@ static int acpi_hibernation_enter(void) static void acpi_hibernation_finish(void) { hibernate_nvs_free(); - acpi_ec_resume_transactions(); + acpi_ec_unblock_transactions(); acpi_pm_finish(); } @@ -619,12 +619,12 @@ static void acpi_hibernation_leave(void) /* Restore the NVS memory area */ hibernate_nvs_restore(); /* Allow EC transactions to happen. */ - acpi_ec_resume_transactions_early(); + acpi_ec_unblock_transactions_early(); } static void acpi_pm_thaw(void) { - acpi_ec_resume_transactions(); + acpi_ec_unblock_transactions(); acpi_enable_all_runtime_gpes(); } -- GitLab From 6057fd78a8dcce6269f029b967051d5a2e9b0895 Mon Sep 17 00:00:00 2001 From: Brian Haley <brian.haley@hp.com> Date: Fri, 28 May 2010 23:02:35 -0700 Subject: [PATCH 280/842] IPv6: fix Mobile IPv6 regression Commit f4f914b5 (net: ipv6 bind to device issue) caused a regression with Mobile IPv6 when it changed the meaning of fl->oif to become a strict requirement of the route lookup. Instead, only force strict mode when sk->sk_bound_dev_if is set on the calling socket, getting the intended behavior and fixing the regression. Tested-by: Arnaud Ebalard <arno@natisbad.org> Signed-off-by: Brian Haley <brian.haley@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv6/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 294cbe8b0725..252d76199c41 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -814,7 +814,7 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, { int flags = 0; - if (fl->oif || rt6_need_strict(&fl->fl6_dst)) + if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl->fl6_dst)) flags |= RT6_LOOKUP_F_IFACE; if (!ipv6_addr_any(&fl->fl6_src)) -- GitLab From 5b0daa3474d52bed906c4d5e92b44e10148c6972 Mon Sep 17 00:00:00 2001 From: Changli Gao <xiaosuo@gmail.com> Date: Sat, 29 May 2010 00:12:13 -0700 Subject: [PATCH 281/842] skb: make skb_recycle_check() return a bool value Signed-off-by: Changli Gao <xiaosuo@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- include/linux/skbuff.h | 2 +- net/core/skbuff.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7cdfb4d52847..bf243fc54959 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -501,7 +501,7 @@ static inline struct sk_buff *alloc_skb_fclone(unsigned int size, return __alloc_skb(size, priority, 1, -1); } -extern int skb_recycle_check(struct sk_buff *skb, int skb_size); +extern bool skb_recycle_check(struct sk_buff *skb, int skb_size); extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src); extern struct sk_buff *skb_clone(struct sk_buff *skb, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4c11000a96aa..4667d4d7c162 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -482,22 +482,22 @@ EXPORT_SYMBOL(consume_skb); * reference count dropping and cleans up the skbuff as if it * just came from __alloc_skb(). */ -int skb_recycle_check(struct sk_buff *skb, int skb_size) +bool skb_recycle_check(struct sk_buff *skb, int skb_size) { struct skb_shared_info *shinfo; if (irqs_disabled()) - return 0; + return false; if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE) - return 0; + return false; skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD); if (skb_end_pointer(skb) - skb->head < skb_size) - return 0; + return false; if (skb_shared(skb) || skb_cloned(skb)) - return 0; + return false; skb_release_head_state(skb); @@ -509,7 +509,7 @@ int skb_recycle_check(struct sk_buff *skb, int skb_size) skb->data = skb->head + NET_SKB_PAD; skb_reset_tail_pointer(skb); - return 1; + return true; } EXPORT_SYMBOL(skb_recycle_check); -- GitLab From 32f6249ba7d63d5d86dae930d63ca70ec11d59af Mon Sep 17 00:00:00 2001 From: Mark Ware <mware@elphinstone.net> Date: Sat, 29 May 2010 00:16:28 -0700 Subject: [PATCH 282/842] fs_enet: Adjust BDs after tx error This patch fixes an occasional transmit lockup in the mac-fcc which occurs after a tx error. The test scenario had the local port set to autoneg and the other end fixed at 100FD, resulting in a large number of late collisions. According to the MPC8280RM 30.10.1.3 (also 8272RM 29.10.1.3), after a tx error occurs, TBPTR may sometimes point beyond BDs still marked as ready. This patch walks back through the BDs and points TBPTR to the earliest one marked as ready. Tested on a custom board with a MPC8280. Signed-off-by: Mark Ware <mware@elphinstone.net> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/fs_enet/mac-fcc.c | 49 ++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 714da967fa19..0ae65a2f1ab9 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -504,17 +504,54 @@ static int get_regs_len(struct net_device *dev) } /* Some transmit errors cause the transmitter to shut - * down. We now issue a restart transmit. Since the - * errors close the BD and update the pointers, the restart - * _should_ pick up without having to reset any of our - * pointers either. Also, To workaround 8260 device erratum - * CPM37, we must disable and then re-enable the transmitter - * following a Late Collision, Underrun, or Retry Limit error. + * down. We now issue a restart transmit. + * Also, to workaround 8260 device erratum CPM37, we must + * disable and then re-enable the transmitterfollowing a + * Late Collision, Underrun, or Retry Limit error. + * In addition, tbptr may point beyond BDs beyond still marked + * as ready due to internal pipelining, so we need to look back + * through the BDs and adjust tbptr to point to the last BD + * marked as ready. This may result in some buffers being + * retransmitted. */ static void tx_restart(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); fcc_t __iomem *fccp = fep->fcc.fccp; + const struct fs_platform_info *fpi = fep->fpi; + fcc_enet_t __iomem *ep = fep->fcc.ep; + cbd_t __iomem *curr_tbptr; + cbd_t __iomem *recheck_bd; + cbd_t __iomem *prev_bd; + cbd_t __iomem *last_tx_bd; + + last_tx_bd = fep->tx_bd_base + (fpi->tx_ring * sizeof(cbd_t)); + + /* get the current bd held in TBPTR and scan back from this point */ + recheck_bd = curr_tbptr = (cbd_t __iomem *) + ((R32(ep, fen_genfcc.fcc_tbptr) - fep->ring_mem_addr) + + fep->ring_base); + + prev_bd = (recheck_bd == fep->tx_bd_base) ? last_tx_bd : recheck_bd - 1; + + /* Move through the bds in reverse, look for the earliest buffer + * that is not ready. Adjust TBPTR to the following buffer */ + while ((CBDR_SC(prev_bd) & BD_ENET_TX_READY) != 0) { + /* Go back one buffer */ + recheck_bd = prev_bd; + + /* update the previous buffer */ + prev_bd = (prev_bd == fep->tx_bd_base) ? last_tx_bd : prev_bd - 1; + + /* We should never see all bds marked as ready, check anyway */ + if (recheck_bd == curr_tbptr) + break; + } + /* Now update the TBPTR and dirty flag to the current buffer */ + W32(ep, fen_genfcc.fcc_tbptr, + (uint) (((void *)recheck_bd - fep->ring_base) + + fep->ring_mem_addr)); + fep->dirty_tx = recheck_bd; C32(fccp, fcc_gfmr, FCC_GFMR_ENT); udelay(10); -- GitLab From e72e9f3814cb8c1076d627c29cec90b005838ac3 Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Wed, 26 May 2010 05:55:10 +0000 Subject: [PATCH 283/842] drivers/isdn/hardware/mISDN: Add missing spin_unlock Add a spin_unlock missing on the error path. The return value of write_reg seems to be completely ignored, so it seems that the lock should be released in every case. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @@ expression E1; @@ * spin_lock(E1,...); <+... when != E1 if (...) { ... when != E1 * return ...; } ...+> * spin_unlock(E1,...); // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/isdn/hardware/mISDN/hfcsusb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index b3b7e2879bac..8700474747e8 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -97,8 +97,10 @@ static int write_reg(struct hfcsusb *hw, __u8 reg, __u8 val) hw->name, __func__, reg, val); spin_lock(&hw->ctrl_lock); - if (hw->ctrl_cnt >= HFC_CTRL_BUFSIZE) + if (hw->ctrl_cnt >= HFC_CTRL_BUFSIZE) { + spin_unlock(&hw->ctrl_lock); return 1; + } buf = &hw->ctrl_buff[hw->ctrl_in_idx]; buf->hfcs_reg = reg; buf->reg_val = val; -- GitLab From 5daf47bb4e708fde32c1856a0d049e3c3d03c36c Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Wed, 26 May 2010 05:54:21 +0000 Subject: [PATCH 284/842] net/rds: Add missing mutex_unlock Add a mutex_unlock missing on the error path. In each case, whenever the label out is reached from elsewhere in the function, mutex is not locked. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @@ expression E1; @@ * mutex_lock(E1); <+... when != E1 if (...) { ... when != E1 * return ...; } ...+> * mutex_unlock(E1); // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Reviewed-by: Zach Brown <zach.brown@oracle.com> Acked-by: Andy Grover <andy.grover@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/rds/ib_cm.c | 1 + net/rds/iw_cm.c | 1 + 2 files changed, 2 insertions(+) diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 10ed0d55f759..f68832798db2 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -475,6 +475,7 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id, err = rds_ib_setup_qp(conn); if (err) { rds_ib_conn_error(conn, "rds_ib_setup_qp failed (%d)\n", err); + mutex_unlock(&conn->c_cm_lock); goto out; } diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c index a9d951b4fbae..b5dd6ac39be8 100644 --- a/net/rds/iw_cm.c +++ b/net/rds/iw_cm.c @@ -452,6 +452,7 @@ int rds_iw_cm_handle_connect(struct rdma_cm_id *cm_id, err = rds_iw_setup_qp(conn); if (err) { rds_iw_conn_error(conn, "rds_iw_setup_qp failed (%d)\n", err); + mutex_unlock(&conn->c_cm_lock); goto out; } -- GitLab From 2892d9c2d925e0d72a7a529852942e2592a970f8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Wed, 26 May 2010 04:46:35 +0000 Subject: [PATCH 285/842] be2net: add unlock on error path The unlock accidentally got removed from the error path in dd131e76e5: "be2net: Bug fix to avoid disabling bottom half during firmware upgrade." Signed-off-by: Dan Carpenter <error27@gmail.com> Acked-by: Sarveshwar Bandi <sarveshwarb@serverengines.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/benet/be_cmds.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 9d11dbf5e4da..a4a9cf762441 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1429,7 +1429,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, wrb = wrb_from_mccq(adapter); if (!wrb) { status = -EBUSY; - goto err; + goto err_unlock; } req = cmd->va; sge = nonembedded_sgl(wrb); @@ -1457,7 +1457,10 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, else status = adapter->flash_status; -err: + return status; + +err_unlock: + spin_unlock_bh(&adapter->mcc_lock); return status; } -- GitLab From c196b02ce60d7b1f9bc62a62c5706d4d58fbfc5a Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Wed, 26 May 2010 04:47:39 +0000 Subject: [PATCH 286/842] be2net: remove superfluous externs This fixes some sparse warnings: drivers/net/benet/be_cmds.c:1503:12: warning: function 'be_cmd_enable_magic_wol' with external linkage has definition drivers/net/benet/be_cmds.c:1668:12: warning: function 'be_cmd_get_seeprom_data' with external linkage has definition Signed-off-by: Dan Carpenter <error27@gmail.com> Acked-by: Sarveshwar Bandi <sarveshwarb@serverengines.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/benet/be_cmds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index a4a9cf762441..9e305d7fb4bd 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1500,7 +1500,7 @@ err: return status; } -extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, +int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, struct be_dma_mem *nonemb_cmd) { struct be_mcc_wrb *wrb; @@ -1665,7 +1665,7 @@ err: return status; } -extern int be_cmd_get_seeprom_data(struct be_adapter *adapter, +int be_cmd_get_seeprom_data(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) { struct be_mcc_wrb *wrb; -- GitLab From 97dc875f90a7b88a9fa476c256345c0d40fcdf6c Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Wed, 26 May 2010 05:16:48 +0000 Subject: [PATCH 287/842] caif: unlock on error path in cfserl_receive() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was an spin_unlock missing on the error path. The spin_lock was tucked in with the declarations so it was hard to spot. I added a new line. Signed-off-by: Dan Carpenter <error27@gmail.com> Acked-by: Sjur Brændeland <sjurbren@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/caif/cfserl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c index cb4325a3dc83..965c5baace40 100644 --- a/net/caif/cfserl.c +++ b/net/caif/cfserl.c @@ -59,16 +59,18 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt) u8 stx = CFSERL_STX; int ret; u16 expectlen = 0; + caif_assert(newpkt != NULL); spin_lock(&layr->sync); if (layr->incomplete_frm != NULL) { - layr->incomplete_frm = cfpkt_append(layr->incomplete_frm, newpkt, expectlen); pkt = layr->incomplete_frm; - if (pkt == NULL) + if (pkt == NULL) { + spin_unlock(&layr->sync); return -ENOMEM; + } } else { pkt = newpkt; } -- GitLab From 7dfde179c38056b91d51e60f3d50902387f27c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= <remi.denis-courmont@nokia.com> Date: Wed, 26 May 2010 00:44:44 +0000 Subject: [PATCH 288/842] Phonet: listening socket lock protects the connected socket list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The accept()'d socket need to be unhashed while the (listen()'ing) socket lock is held. This fixes a race condition that could lead to an OOPS. Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/phonet/pep.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 7b048a35ca58..94d72e85a475 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -1045,12 +1045,12 @@ static void pep_sock_unhash(struct sock *sk) lock_sock(sk); if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) { skparent = pn->listener; - sk_del_node_init(sk); release_sock(sk); - sk = skparent; pn = pep_sk(skparent); - lock_sock(sk); + lock_sock(skparent); + sk_del_node_init(sk); + sk = skparent; } /* Unhash a listening sock only when it is closed * and all of its active connected pipes are closed. */ -- GitLab From 2903037400a26e7c0cc93ab75a7d62abfacdf485 Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Sat, 29 May 2010 00:20:48 -0700 Subject: [PATCH 289/842] net: fix sk_forward_alloc corruptions As David found out, sock_queue_err_skb() should be called with socket lock hold, or we risk sk_forward_alloc corruption, since we use non atomic operations to update this field. This patch adds bh_lock_sock()/bh_unlock_sock() pair to three spots. (BH already disabled) 1) skb_tstamp_tx() 2) Before calling ip_icmp_error(), in __udp4_lib_err() 3) Before calling ipv6_icmp_error(), in __udp6_lib_err() Reported-by: Anton Blanchard <anton@samba.org> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/core/skbuff.c | 4 ++++ net/ipv4/udp.c | 2 ++ net/ipv6/udp.c | 6 ++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4667d4d7c162..f2913ae2b52c 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2992,7 +2992,11 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, memset(serr, 0, sizeof(*serr)); serr->ee.ee_errno = ENOMSG; serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; + + bh_lock_sock(sk); err = sock_queue_err_skb(sk, skb); + bh_unlock_sock(sk); + if (err) kfree_skb(skb); } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index b9d0d409516f..acdc9be833cc 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -634,7 +634,9 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) if (!harderr || sk->sk_state != TCP_ESTABLISHED) goto out; } else { + bh_lock_sock(sk); ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *)(uh+1)); + bh_unlock_sock(sk); } sk->sk_err = err; sk->sk_error_report(sk); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 87be58673b55..3048f906c042 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -466,9 +466,11 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (sk->sk_state != TCP_ESTABLISHED && !np->recverr) goto out; - if (np->recverr) + if (np->recverr) { + bh_lock_sock(sk); ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); - + bh_unlock_sock(sk); + } sk->sk_err = err; sk->sk_error_report(sk); out: -- GitLab From a7fed9f7369bfcfabed7aca1d608d286f2dfa7f6 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: Mon, 31 May 2010 11:49:00 +1000 Subject: [PATCH 290/842] powerpc: Don't export cvt_fd & _df when CONFIG_PPC_FPU is not set Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> --- arch/powerpc/kernel/ppc_ksyms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index bc9f39d2598b..3b4dcc82a4c1 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -101,7 +101,7 @@ EXPORT_SYMBOL(pci_dram_offset); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); -#ifndef CONFIG_BOOKE +#ifdef CONFIG_PPC_FPU EXPORT_SYMBOL_GPL(cvt_df); EXPORT_SYMBOL_GPL(cvt_fd); #endif -- GitLab From 600ae40df788d282523b1b86624b83f7a11a97cb Mon Sep 17 00:00:00 2001 From: Tobias Klauser <tklauser@distanz.ch> Date: Thu, 20 May 2010 10:31:46 +0200 Subject: [PATCH 291/842] [ARM] pxa/palmtc: storage class should be before const qualifier The C99 specification states in section 6.11.5: The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature. Signed-off-by: Tobias Klauser <tklauser@distanz.ch> Acked-by: Marek Vasut <marek.vasut@gmail.com> Signed-off-by: Eric Miao <eric.y.miao@gmail.com> --- arch/arm/mach-pxa/palmtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c index 033b567e50bb..ce1104d1bc17 100644 --- a/arch/arm/mach-pxa/palmtc.c +++ b/arch/arm/mach-pxa/palmtc.c @@ -263,11 +263,11 @@ const struct matrix_keymap_data palmtc_keymap_data = { .keymap_size = ARRAY_SIZE(palmtc_matrix_keys), }; -const static unsigned int palmtc_keypad_row_gpios[] = { +static const unsigned int palmtc_keypad_row_gpios[] = { 0, 9, 10, 11 }; -const static unsigned int palmtc_keypad_col_gpios[] = { +static const unsigned int palmtc_keypad_col_gpios[] = { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 79, 80 }; -- GitLab From d30e5d897c3da7c2d17c8112331b66ed953eec78 Mon Sep 17 00:00:00 2001 From: Marek Vasut <marek.vasut@gmail.com> Date: Fri, 28 May 2010 04:42:59 +0200 Subject: [PATCH 292/842] [ARM] pxa/spitz: Correctly register WM8750 This patch registers the WM8750 codec on a proper place on the SPITZ machine after the WM8750 driver was converted to new API. Signed-off-by: Marek Vasut <marek.vasut@gmail.com> Signed-off-by: Eric Miao <eric.y.miao@gmail.com> --- arch/arm/mach-pxa/spitz.c | 3 +++ sound/soc/pxa/spitz.c | 36 ------------------------------------ 2 files changed, 3 insertions(+), 36 deletions(-) diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 4d2413ed0ffa..c1048a35f187 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -818,6 +818,9 @@ static struct i2c_board_info akita_i2c_board_info[] = { .type = "max7310", .addr = 0x18, .platform_data = &akita_ioexp, + }, { + .type = "wm8750", + .addr = 0x1b, }, }; diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 1941a357e8c4..d256f5f313b5 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -328,38 +328,6 @@ static struct snd_soc_device spitz_snd_devdata = { .codec_dev = &soc_codec_dev_wm8750, }; -/* - * FIXME: This is a temporary bodge to avoid cross-tree merge issues. - * New drivers should register the wm8750 I2C device in the machine - * setup code (under arch/arm for ARM systems). - */ -static int wm8750_i2c_register(void) -{ - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = 0x1b; - strlcpy(info.type, "wm8750", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(0); - if (!adapter) { - printk(KERN_ERR "can't get i2c adapter 0\n"); - return -ENODEV; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - printk(KERN_ERR "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - return -ENODEV; - } - - return 0; -} - static struct platform_device *spitz_snd_device; static int __init spitz_init(void) @@ -369,10 +337,6 @@ static int __init spitz_init(void) if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita())) return -ENODEV; - ret = wm8750_i2c_setup(); - if (ret != 0) - return ret; - spitz_snd_device = platform_device_alloc("soc-audio", -1); if (!spitz_snd_device) return -ENOMEM; -- GitLab From 1238c684325d9710544af6f0d11bf7cd6efd5925 Mon Sep 17 00:00:00 2001 From: Yusuke Goda <yusuke.goda.sx@renesas.com> Date: Tue, 27 Apr 2010 10:15:32 +0000 Subject: [PATCH 293/842] sh: Add support MMCIF for ecovec This patch adds MMCIF platform data for the Ecovec board. Signed-off-by: Yusuke Goda <yusuke.goda.sx@renesas.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/boards/mach-ecovec24/setup.c | 86 +++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 3845258242ac..778eb7cb9873 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -12,6 +12,8 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/mfd/sh_mobile_sdhi.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sh_mmcif.h> #include <linux/mtd/physmap.h> #include <linux/gpio.h> #include <linux/interrupt.h> @@ -435,7 +437,7 @@ static struct i2c_board_info ts_i2c_clients = { }; #ifdef CONFIG_MFD_SH_MOBILE_SDHI -/* SHDI0 */ +/* SDHI0 */ static void sdhi0_set_pwr(struct platform_device *pdev, int state) { gpio_set_value(GPIO_PTB6, state); @@ -473,7 +475,8 @@ static struct platform_device sdhi0_device = { }, }; -/* SHDI1 */ +#if !defined(CONFIG_MMC_SH_MMCIF) +/* SDHI1 */ static void sdhi1_set_pwr(struct platform_device *pdev, int state) { gpio_set_value(GPIO_PTB7, state); @@ -510,6 +513,7 @@ static struct platform_device sdhi1_device = { .hwblk_id = HWBLK_SDHI1, }, }; +#endif /* CONFIG_MMC_SH_MMCIF */ #else @@ -818,6 +822,58 @@ static struct platform_device vou_device = { }, }; +#if defined(CONFIG_MMC_SH_MMCIF) +/* SH_MMCIF */ +static void mmcif_set_pwr(struct platform_device *pdev, int state) +{ + gpio_set_value(GPIO_PTB7, state); +} + +static void mmcif_down_pwr(struct platform_device *pdev) +{ + gpio_set_value(GPIO_PTB7, 0); +} + +static struct resource sh_mmcif_resources[] = { + [0] = { + .name = "SH_MMCIF", + .start = 0xA4CA0000, + .end = 0xA4CA00FF, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* MMC2I */ + .start = 29, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* MMC3I */ + .start = 30, + .flags = IORESOURCE_IRQ, + }, +}; + +struct sh_mmcif_plat_data sh_mmcif_plat = { + .set_pwr = mmcif_set_pwr, + .down_pwr = mmcif_down_pwr, + .sup_pclk = 0, /* SH7724: Max Pclk/2 */ + .caps = MMC_CAP_4_BIT_DATA | + MMC_CAP_8_BIT_DATA | + MMC_CAP_NEEDS_POLL, + .ocr = MMC_VDD_32_33 | MMC_VDD_33_34, +}; + +static struct platform_device sh_mmcif_device = { + .name = "sh_mmcif", + .id = 0, + .dev = { + .platform_data = &sh_mmcif_plat, + }, + .num_resources = ARRAY_SIZE(sh_mmcif_resources), + .resource = sh_mmcif_resources, +}; +#endif + static struct platform_device *ecovec_devices[] __initdata = { &heartbeat_device, &nor_flash_device, @@ -830,7 +886,9 @@ static struct platform_device *ecovec_devices[] __initdata = { &keysc_device, #ifdef CONFIG_MFD_SH_MOBILE_SDHI &sdhi0_device, +#if !defined(CONFIG_MMC_SH_MMCIF) &sdhi1_device, +#endif #else &msiof0_device, #endif @@ -840,6 +898,9 @@ static struct platform_device *ecovec_devices[] __initdata = { &fsi_device, &irda_device, &vou_device, +#if defined(CONFIG_MMC_SH_MMCIF) + &sh_mmcif_device, +#endif }; #ifdef CONFIG_I2C @@ -1133,6 +1194,7 @@ static int __init arch_setup(void) gpio_request(GPIO_PTB6, NULL); gpio_direction_output(GPIO_PTB6, 0); +#if !defined(CONFIG_MMC_SH_MMCIF) /* enable SDHI1 on CN12 (needs DS2.6,7 set to ON,OFF) */ gpio_request(GPIO_FN_SDHI1CD, NULL); gpio_request(GPIO_FN_SDHI1WP, NULL); @@ -1147,6 +1209,7 @@ static int __init arch_setup(void) /* I/O buffer drive ability is high for SDHI1 */ __raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA); +#endif /* CONFIG_MMC_SH_MMCIF */ #else /* enable MSIOF0 on CN11 (needs DS2.4 set to OFF) */ gpio_request(GPIO_FN_MSIOF0_TXD, NULL); @@ -1222,6 +1285,25 @@ static int __init arch_setup(void) gpio_request(GPIO_PTU5, NULL); gpio_direction_output(GPIO_PTU5, 0); +#if defined(CONFIG_MMC_SH_MMCIF) + /* enable MMCIF (needs DS2.6,7 set to OFF,ON) */ + gpio_request(GPIO_FN_MMC_D7, NULL); + gpio_request(GPIO_FN_MMC_D6, NULL); + gpio_request(GPIO_FN_MMC_D5, NULL); + gpio_request(GPIO_FN_MMC_D4, NULL); + gpio_request(GPIO_FN_MMC_D3, NULL); + gpio_request(GPIO_FN_MMC_D2, NULL); + gpio_request(GPIO_FN_MMC_D1, NULL); + gpio_request(GPIO_FN_MMC_D0, NULL); + gpio_request(GPIO_FN_MMC_CLK, NULL); + gpio_request(GPIO_FN_MMC_CMD, NULL); + gpio_request(GPIO_PTB7, NULL); + gpio_direction_output(GPIO_PTB7, 0); + + /* I/O buffer drive ability is high for MMCIF */ + __raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA); +#endif + /* enable I2C device */ i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices)); -- GitLab From b34bce45530ca897aea35915e0e42eb3c8047b52 Mon Sep 17 00:00:00 2001 From: Magnus Damm <damm@opensource.se> Date: Tue, 18 May 2010 14:42:40 +0000 Subject: [PATCH 294/842] sh: allow romImage data between head.S and the zero page Extend the romImage code to allow putting data between the head.S file and the empty_zero_page. Needed in the case of more advanced loader code in a separate C file. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/boot/romimage/head.S | 12 +++++++++--- arch/sh/boot/romimage/vmlinux.scr | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/sh/boot/romimage/head.S b/arch/sh/boot/romimage/head.S index 93e779a405ec..65b8256d81cb 100644 --- a/arch/sh/boot/romimage/head.S +++ b/arch/sh/boot/romimage/head.S @@ -13,7 +13,9 @@ romstart: #include <mach/romimage.h> /* copy the empty_zero_page contents to where vmlinux expects it */ - mova empty_zero_page_src, r0 + mova extra_data_pos, r0 + mov.l extra_data_size, r1 + add r1, r0 mov.l empty_zero_page_dst, r1 mov #(PAGE_SHIFT - 4), r4 mov #1, r3 @@ -37,7 +39,9 @@ romstart: mov #PAGE_SHIFT, r4 mov #1, r1 shld r4, r1 - mova empty_zero_page_src, r0 + mova extra_data_pos, r0 + add r1, r0 + mov.l extra_data_size, r1 add r1, r0 jmp @r0 nop @@ -45,4 +49,6 @@ romstart: .align 2 empty_zero_page_dst: .long _text -empty_zero_page_src: +extra_data_pos: +extra_data_size: + .long zero_page_pos - extra_data_pos diff --git a/arch/sh/boot/romimage/vmlinux.scr b/arch/sh/boot/romimage/vmlinux.scr index 287c08f8b4bb..ea27298a99a7 100644 --- a/arch/sh/boot/romimage/vmlinux.scr +++ b/arch/sh/boot/romimage/vmlinux.scr @@ -1,6 +1,7 @@ SECTIONS { .text : { + zero_page_pos = .; *(.data) } } -- GitLab From 487d9fc5016529d7d77dfe35b666fd3a090e2953 Mon Sep 17 00:00:00 2001 From: Magnus Damm <damm@opensource.se> Date: Tue, 18 May 2010 14:42:51 +0000 Subject: [PATCH 295/842] sh: prepare MMCIF driver header file Update the MMCIF driver to include register information and register access functions in the header file. The MMCIF boot code builds on top of this. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- drivers/mmc/host/sh_mmcif.c | 125 ++++++++++++++--------------------- include/linux/mmc/sh_mmcif.h | 32 +++++++++ 2 files changed, 82 insertions(+), 75 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index eb97830c0344..5d3f824bb5a3 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -30,25 +30,6 @@ #define DRIVER_NAME "sh_mmcif" #define DRIVER_VERSION "2010-04-28" -#define MMCIF_CE_CMD_SET 0x00000000 -#define MMCIF_CE_ARG 0x00000008 -#define MMCIF_CE_ARG_CMD12 0x0000000C -#define MMCIF_CE_CMD_CTRL 0x00000010 -#define MMCIF_CE_BLOCK_SET 0x00000014 -#define MMCIF_CE_CLK_CTRL 0x00000018 -#define MMCIF_CE_BUF_ACC 0x0000001C -#define MMCIF_CE_RESP3 0x00000020 -#define MMCIF_CE_RESP2 0x00000024 -#define MMCIF_CE_RESP1 0x00000028 -#define MMCIF_CE_RESP0 0x0000002C -#define MMCIF_CE_RESP_CMD12 0x00000030 -#define MMCIF_CE_DATA 0x00000034 -#define MMCIF_CE_INT 0x00000040 -#define MMCIF_CE_INT_MASK 0x00000044 -#define MMCIF_CE_HOST_STS1 0x00000048 -#define MMCIF_CE_HOST_STS2 0x0000004C -#define MMCIF_CE_VERSION 0x0000007C - /* CE_CMD_SET */ #define CMD_MASK 0x3f000000 #define CMD_SET_RTYP_NO ((0 << 23) | (0 << 22)) @@ -207,27 +188,17 @@ struct sh_mmcif_host { wait_queue_head_t intr_wait; }; -static inline u32 sh_mmcif_readl(struct sh_mmcif_host *host, unsigned int reg) -{ - return readl(host->addr + reg); -} - -static inline void sh_mmcif_writel(struct sh_mmcif_host *host, - unsigned int reg, u32 val) -{ - writel(val, host->addr + reg); -} static inline void sh_mmcif_bitset(struct sh_mmcif_host *host, unsigned int reg, u32 val) { - writel(val | sh_mmcif_readl(host, reg), host->addr + reg); + writel(val | readl(host->addr + reg), host->addr + reg); } static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host, unsigned int reg, u32 val) { - writel(~val & sh_mmcif_readl(host, reg), host->addr + reg); + writel(~val & readl(host->addr + reg), host->addr + reg); } @@ -253,10 +224,10 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) { u32 tmp; - tmp = 0x010f0000 & sh_mmcif_readl(host, MMCIF_CE_CLK_CTRL); + tmp = 0x010f0000 & sh_mmcif_readl(host->addr, MMCIF_CE_CLK_CTRL); - sh_mmcif_writel(host, MMCIF_CE_VERSION, SOFT_RST_ON); - sh_mmcif_writel(host, MMCIF_CE_VERSION, SOFT_RST_OFF); + sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_ON); + sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_OFF); sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29); /* byte swap on */ @@ -271,12 +242,10 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) host->sd_error = 0; host->wait_int = 0; - state1 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS1); - state2 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS2); - pr_debug("%s: ERR HOST_STS1 = %08x\n", \ - DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS1)); - pr_debug("%s: ERR HOST_STS2 = %08x\n", \ - DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS2)); + state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1); + state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2); + pr_debug("%s: ERR HOST_STS1 = %08x\n", DRIVER_NAME, state1); + pr_debug("%s: ERR HOST_STS2 = %08x\n", DRIVER_NAME, state2); if (state1 & STS1_CMDSEQ) { sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); @@ -288,7 +257,7 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) "command sequence timeout err\n"); return -EIO; } - if (!(sh_mmcif_readl(host, MMCIF_CE_HOST_STS1) + if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) & STS1_CMDSEQ)) break; mdelay(1); @@ -330,9 +299,9 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host, host->wait_int = 0; blocksize = (BLOCK_SIZE_MASK & - sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3; + sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; for (i = 0; i < blocksize / 4; i++) - *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA); + *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); /* buffer read end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); @@ -353,7 +322,8 @@ static int sh_mmcif_multi_read(struct sh_mmcif_host *host, long time; u32 blocksize, i, j, sec, *p; - blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET); + blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, + MMCIF_CE_BLOCK_SET); for (j = 0; j < data->sg_len; j++) { p = sg_virt(data->sg); host->wait_int = 0; @@ -370,7 +340,8 @@ static int sh_mmcif_multi_read(struct sh_mmcif_host *host, host->wait_int = 0; for (i = 0; i < blocksize / 4; i++) - *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA); + *p++ = sh_mmcif_readl(host->addr, + MMCIF_CE_DATA); } if (j < data->sg_len - 1) data->sg++; @@ -397,9 +368,9 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host, host->wait_int = 0; blocksize = (BLOCK_SIZE_MASK & - sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3; + sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; for (i = 0; i < blocksize / 4; i++) - sh_mmcif_writel(host, MMCIF_CE_DATA, *p++); + sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); /* buffer write end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); @@ -421,7 +392,8 @@ static int sh_mmcif_multi_write(struct sh_mmcif_host *host, long time; u32 i, sec, j, blocksize, *p; - blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET); + blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, + MMCIF_CE_BLOCK_SET); for (j = 0; j < data->sg_len; j++) { p = sg_virt(data->sg); @@ -439,7 +411,8 @@ static int sh_mmcif_multi_write(struct sh_mmcif_host *host, host->wait_int = 0; for (i = 0; i < blocksize / 4; i++) - sh_mmcif_writel(host, MMCIF_CE_DATA, *p++); + sh_mmcif_writel(host->addr, + MMCIF_CE_DATA, *p++); } if (j < data->sg_len - 1) data->sg++; @@ -451,18 +424,18 @@ static void sh_mmcif_get_response(struct sh_mmcif_host *host, struct mmc_command *cmd) { if (cmd->flags & MMC_RSP_136) { - cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP3); - cmd->resp[1] = sh_mmcif_readl(host, MMCIF_CE_RESP2); - cmd->resp[2] = sh_mmcif_readl(host, MMCIF_CE_RESP1); - cmd->resp[3] = sh_mmcif_readl(host, MMCIF_CE_RESP0); + cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP3); + cmd->resp[1] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP2); + cmd->resp[2] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP1); + cmd->resp[3] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0); } else - cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP0); + cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0); } static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, struct mmc_command *cmd) { - cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP_CMD12); + cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP_CMD12); } static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, @@ -596,18 +569,19 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; if (host->data) { - sh_mmcif_writel(host, MMCIF_CE_BLOCK_SET, 0); - sh_mmcif_writel(host, MMCIF_CE_BLOCK_SET, mrq->data->blksz); + sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0); + sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, + mrq->data->blksz); } opc = sh_mmcif_set_cmd(host, mrq, cmd, opc); - sh_mmcif_writel(host, MMCIF_CE_INT, 0xD80430C0); - sh_mmcif_writel(host, MMCIF_CE_INT_MASK, mask); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0); + sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask); /* set arg */ - sh_mmcif_writel(host, MMCIF_CE_ARG, cmd->arg); + sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg); host->wait_int = 0; /* set cmd */ - sh_mmcif_writel(host, MMCIF_CE_CMD_SET, opc); + sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc); time = wait_event_interruptible_timeout(host->intr_wait, host->wait_int == 1 || host->sd_error == 1, host->timeout); @@ -752,43 +726,44 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) u32 state = 0; int err = 0; - state = sh_mmcif_readl(host, MMCIF_CE_INT); + state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); if (state & INT_RBSYE) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~(INT_RBSYE | INT_CRSPE)); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, + ~(INT_RBSYE | INT_CRSPE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE); } else if (state & INT_CRSPE) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_CRSPE); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_CRSPE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE); } else if (state & INT_BUFREN) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFREN); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFREN); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); } else if (state & INT_BUFWEN) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFWEN); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFWEN); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); } else if (state & INT_CMD12DRE) { - sh_mmcif_writel(host, MMCIF_CE_INT, + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE | INT_BUFRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); } else if (state & INT_BUFRE) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFRE); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFRE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); } else if (state & INT_DTRANE) { - sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_DTRANE); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_DTRANE); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); } else if (state & INT_CMD12RBE) { - sh_mmcif_writel(host, MMCIF_CE_INT, + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12RBE | INT_CMD12CRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); } else if (state & INT_ERR_STS) { /* err interrupts */ - sh_mmcif_writel(host, MMCIF_CE_INT, ~state); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); err = 1; } else { pr_debug("%s: Not support int\n", DRIVER_NAME); - sh_mmcif_writel(host, MMCIF_CE_INT, ~state); + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); err = 1; } @@ -894,12 +869,12 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) goto clean_up2; } - sh_mmcif_writel(host, MMCIF_CE_INT_MASK, MASK_ALL); + sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); sh_mmcif_detect(host->mmc); pr_info("%s: driver version %s\n", DRIVER_NAME, DRIVER_VERSION); pr_debug("%s: chip ver H'%04x\n", DRIVER_NAME, - sh_mmcif_readl(host, MMCIF_CE_VERSION) & 0x0000ffff); + sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); return ret; clean_up2: @@ -917,7 +892,7 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev) struct sh_mmcif_host *host = platform_get_drvdata(pdev); int irq[2]; - sh_mmcif_writel(host, MMCIF_CE_INT_MASK, MASK_ALL); + sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); irq[0] = platform_get_irq(pdev, 0); irq[1] = platform_get_irq(pdev, 1); diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h index aafe832f18aa..e079c6beeb98 100644 --- a/include/linux/mmc/sh_mmcif.h +++ b/include/linux/mmc/sh_mmcif.h @@ -14,6 +14,9 @@ #ifndef __SH_MMCIF_H__ #define __SH_MMCIF_H__ +#include <linux/platform_device.h> +#include <linux/io.h> + /* * MMCIF : CE_CLK_CTRL [19:16] * 1000 : Peripheral clock / 512 @@ -36,4 +39,33 @@ struct sh_mmcif_plat_data { u32 ocr; }; +#define MMCIF_CE_CMD_SET 0x00000000 +#define MMCIF_CE_ARG 0x00000008 +#define MMCIF_CE_ARG_CMD12 0x0000000C +#define MMCIF_CE_CMD_CTRL 0x00000010 +#define MMCIF_CE_BLOCK_SET 0x00000014 +#define MMCIF_CE_CLK_CTRL 0x00000018 +#define MMCIF_CE_BUF_ACC 0x0000001C +#define MMCIF_CE_RESP3 0x00000020 +#define MMCIF_CE_RESP2 0x00000024 +#define MMCIF_CE_RESP1 0x00000028 +#define MMCIF_CE_RESP0 0x0000002C +#define MMCIF_CE_RESP_CMD12 0x00000030 +#define MMCIF_CE_DATA 0x00000034 +#define MMCIF_CE_INT 0x00000040 +#define MMCIF_CE_INT_MASK 0x00000044 +#define MMCIF_CE_HOST_STS1 0x00000048 +#define MMCIF_CE_HOST_STS2 0x0000004C +#define MMCIF_CE_VERSION 0x0000007C + +extern inline u32 sh_mmcif_readl(void __iomem *addr, int reg) +{ + return readl(addr + reg); +} + +extern inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val) +{ + writel(val, addr + reg); +} + #endif /* __SH_MMCIF_H__ */ -- GitLab From 8a768952ca8cb5cad98cfa343e6fb131e3bbdc3e Mon Sep 17 00:00:00 2001 From: Magnus Damm <damm@opensource.se> Date: Tue, 18 May 2010 14:43:04 +0000 Subject: [PATCH 296/842] sh: add boot code to MMCIF driver header This patch adds a set of MMCIF functions for the romImage boot loader that allows the kernel to be booted directly from an MMC card. Thanks to Jeremy Baker for the initial prototype. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- include/linux/mmc/sh_mmcif.h | 129 +++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h index e079c6beeb98..d4a2ebbdab4b 100644 --- a/include/linux/mmc/sh_mmcif.h +++ b/include/linux/mmc/sh_mmcif.h @@ -68,4 +68,133 @@ extern inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val) writel(val, addr + reg); } +#define SH_MMCIF_BBS 512 /* boot block size */ + +extern inline void sh_mmcif_boot_cmd_send(void __iomem *base, + unsigned long cmd, unsigned long arg) +{ + sh_mmcif_writel(base, MMCIF_CE_INT, 0); + sh_mmcif_writel(base, MMCIF_CE_ARG, arg); + sh_mmcif_writel(base, MMCIF_CE_CMD_SET, cmd); +} + +extern inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask) +{ + unsigned long tmp; + int cnt; + + for (cnt = 0; cnt < 1000000; cnt++) { + tmp = sh_mmcif_readl(base, MMCIF_CE_INT); + if (tmp & mask) { + sh_mmcif_writel(base, MMCIF_CE_INT, tmp & ~mask); + return 0; + } + } + + return -1; +} + +extern inline int sh_mmcif_boot_cmd(void __iomem *base, + unsigned long cmd, unsigned long arg) +{ + sh_mmcif_boot_cmd_send(base, cmd, arg); + return sh_mmcif_boot_cmd_poll(base, 0x00010000); +} + +extern inline int sh_mmcif_boot_do_read_single(void __iomem *base, + unsigned int block_nr, + unsigned long *buf) +{ + int k; + + /* CMD13 - Status */ + sh_mmcif_boot_cmd(base, 0x0d400000, 0x00010000); + + if (sh_mmcif_readl(base, MMCIF_CE_RESP0) != 0x0900) + return -1; + + /* CMD17 - Read */ + sh_mmcif_boot_cmd(base, 0x11480000, block_nr * SH_MMCIF_BBS); + if (sh_mmcif_boot_cmd_poll(base, 0x00100000) < 0) + return -1; + + for (k = 0; k < (SH_MMCIF_BBS / 4); k++) + buf[k] = sh_mmcif_readl(base, MMCIF_CE_DATA); + + return 0; +} + +extern inline int sh_mmcif_boot_do_read(void __iomem *base, + unsigned long first_block, + unsigned long nr_blocks, + void *buf) +{ + unsigned long k; + int ret = 0; + + /* CMD16 - Set the block size */ + sh_mmcif_boot_cmd(base, 0x10400000, SH_MMCIF_BBS); + + for (k = 0; !ret && k < nr_blocks; k++) + ret = sh_mmcif_boot_do_read_single(base, first_block + k, + buf + (k * SH_MMCIF_BBS)); + + return ret; +} + +extern inline void sh_mmcif_boot_init(void __iomem *base) +{ + unsigned long tmp; + + /* reset */ + tmp = sh_mmcif_readl(base, MMCIF_CE_VERSION); + sh_mmcif_writel(base, MMCIF_CE_VERSION, tmp | 0x80000000); + sh_mmcif_writel(base, MMCIF_CE_VERSION, tmp & ~0x80000000); + + /* byte swap */ + sh_mmcif_writel(base, MMCIF_CE_BUF_ACC, 0x00010000); + + /* Set block size in MMCIF hardware */ + sh_mmcif_writel(base, MMCIF_CE_BLOCK_SET, SH_MMCIF_BBS); + + /* Enable the clock, set it to Bus clock/256 (about 325Khz)*/ + sh_mmcif_writel(base, MMCIF_CE_CLK_CTRL, 0x01072fff); + + /* CMD0 */ + sh_mmcif_boot_cmd(base, 0x00000040, 0); + + /* CMD1 - Get OCR */ + do { + sh_mmcif_boot_cmd(base, 0x01405040, 0x40300000); /* CMD1 */ + } while ((sh_mmcif_readl(base, MMCIF_CE_RESP0) & 0x80000000) + != 0x80000000); + + /* CMD2 - Get CID */ + sh_mmcif_boot_cmd(base, 0x02806040, 0); + + /* CMD3 - Set card relative address */ + sh_mmcif_boot_cmd(base, 0x03400040, 0x00010000); +} + +extern inline void sh_mmcif_boot_slurp(void __iomem *base, + unsigned char *buf, + unsigned long no_bytes) +{ + unsigned long tmp; + + /* In data transfer mode: Set clock to Bus clock/4 (about 20Mhz) */ + sh_mmcif_writel(base, MMCIF_CE_CLK_CTRL, 0x01012fff); + + /* CMD9 - Get CSD */ + sh_mmcif_boot_cmd(base, 0x09806000, 0x00010000); + + /* CMD7 - Select the card */ + sh_mmcif_boot_cmd(base, 0x07400000, 0x00010000); + + tmp = no_bytes / SH_MMCIF_BBS; + tmp += (no_bytes % SH_MMCIF_BBS) ? 1 : 0; + + sh_mmcif_boot_do_read(base, 512, tmp, buf); +} + #endif /* __SH_MMCIF_H__ */ -- GitLab From 4705b2e8047221142af2ed5e37f54ac4c7f80a7d Mon Sep 17 00:00:00 2001 From: Magnus Damm <damm@opensource.se> Date: Tue, 18 May 2010 14:43:15 +0000 Subject: [PATCH 297/842] sh: add romImage MMCIF boot for sh7724 and Ecovec V2 This patch is V2 of the MMCIF romImage boot support for sh7724 and the Ecovec board. With this patch applied and CONFIG_ROMIMAGE_MMCIF selected the romImage kernel image can be written to a MMC card and booted directly by the sh7724 cpu. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/Kconfig | 11 +++ arch/sh/boot/romimage/Makefile | 13 ++-- arch/sh/boot/romimage/head.S | 30 ++++++++ arch/sh/boot/romimage/mmcif-sh7724.c | 72 +++++++++++++++++++ arch/sh/boot/romimage/vmlinux.scr | 1 + arch/sh/include/cpu-sh4/cpu/sh7724.h | 1 + arch/sh/include/mach-common/mach/romimage.h | 10 +++ arch/sh/include/mach-ecovec24/mach/romimage.h | 27 +++++++ arch/sh/include/mach-kfr2r09/mach/romimage.h | 10 +++ 9 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 arch/sh/boot/romimage/mmcif-sh7724.c diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index c5ee4ce60b57..22d25113d76a 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -776,6 +776,17 @@ config ENTRY_OFFSET default "0x00010000" if PAGE_SIZE_64KB default "0x00000000" +config ROMIMAGE_MMCIF + bool "Include MMCIF loader in romImage (EXPERIMENTAL)" + depends on CPU_SUBTYPE_SH7724 && EXPERIMENTAL + help + Say Y here to include experimental MMCIF loading code in + romImage. With this enabled it is possible to write the romImage + kernel image to an MMC card and boot the kernel straight from + the reset vector. At reset the processor Mask ROM will load the + first part of the romImage which in turn loads the rest the kernel + image to RAM using the MMCIF hardware block. + choice prompt "Kernel command line" optional diff --git a/arch/sh/boot/romimage/Makefile b/arch/sh/boot/romimage/Makefile index f473a24a2d92..2216ee57f251 100644 --- a/arch/sh/boot/romimage/Makefile +++ b/arch/sh/boot/romimage/Makefile @@ -1,16 +1,21 @@ # # linux/arch/sh/boot/romimage/Makefile # -# create an image suitable for burning to flash from zImage +# create an romImage file suitable for burning to flash/mmc from zImage # targets := vmlinux head.o zeropage.bin piggy.o +load-y := 0 -OBJECTS = $(obj)/head.o -LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext 0 -e romstart \ +mmcif-load-$(CONFIG_CPU_SUBTYPE_SH7724) := 0xe5200000 # ILRAM +mmcif-obj-$(CONFIG_CPU_SUBTYPE_SH7724) := $(obj)/mmcif-sh7724.o +load-$(CONFIG_ROMIMAGE_MMCIF) := $(mmcif-load-y) +obj-$(CONFIG_ROMIMAGE_MMCIF) := $(mmcif-obj-y) + +LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext $(load-y) -e romstart \ -T $(obj)/../../kernel/vmlinux.lds -$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE +$(obj)/vmlinux: $(obj)/head.o $(obj-y) $(obj)/piggy.o FORCE $(call if_changed,ld) @: diff --git a/arch/sh/boot/romimage/head.S b/arch/sh/boot/romimage/head.S index 65b8256d81cb..4671d1b82150 100644 --- a/arch/sh/boot/romimage/head.S +++ b/arch/sh/boot/romimage/head.S @@ -12,6 +12,36 @@ romstart: /* include board specific setup code */ #include <mach/romimage.h> +#ifdef CONFIG_ROMIMAGE_MMCIF + /* load the romImage to above the empty zero page */ + mov.l empty_zero_page_dst, r4 + mov.l empty_zero_page_dst_adj, r5 + add r5, r4 + mov.l bytes_to_load, r5 + mov.l loader_function, r7 + jsr @r7 + mov r4, r15 + + mov.l empty_zero_page_dst, r4 + mov.l empty_zero_page_dst_adj, r5 + add r5, r4 + mov.l loaded_code_offs, r5 + add r5, r4 + jmp @r4 + nop + + .balign 4 +empty_zero_page_dst_adj: + .long PAGE_SIZE +bytes_to_load: + .long end_data - romstart +loader_function: + .long mmcif_loader +loaded_code_offs: + .long loaded_code - romstart +loaded_code: +#endif /* CONFIG_ROMIMAGE_MMCIF */ + /* copy the empty_zero_page contents to where vmlinux expects it */ mova extra_data_pos, r0 mov.l extra_data_size, r1 diff --git a/arch/sh/boot/romimage/mmcif-sh7724.c b/arch/sh/boot/romimage/mmcif-sh7724.c new file mode 100644 index 000000000000..14863d7292cb --- /dev/null +++ b/arch/sh/boot/romimage/mmcif-sh7724.c @@ -0,0 +1,72 @@ +/* + * sh7724 MMCIF loader + * + * Copyright (C) 2010 Magnus Damm + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/mmc/sh_mmcif.h> +#include <mach/romimage.h> + +#define MMCIF_BASE (void __iomem *)0xa4ca0000 + +#define MSTPCR2 0xa4150038 +#define PTWCR 0xa4050146 +#define PTXCR 0xa4050148 +#define PSELA 0xa405014e +#define PSELE 0xa4050156 +#define HIZCRC 0xa405015c +#define DRVCRA 0xa405018a + +enum { MMCIF_PROGRESS_ENTER, MMCIF_PROGRESS_INIT, + MMCIF_PROGRESS_LOAD, MMCIF_PROGRESS_DONE }; + +/* SH7724 specific MMCIF loader + * + * loads the romImage from an MMC card starting from block 512 + * use the following line to write the romImage to an MMC card + * # dd if=arch/sh/boot/romImage of=/dev/sdx bs=512 seek=512 + */ +asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes) +{ + mmcif_update_progress(MMCIF_PROGRESS_ENTER); + + /* enable clock to the MMCIF hardware block */ + __raw_writel(__raw_readl(MSTPCR2) & ~0x20000000, MSTPCR2); + + /* setup pins D7-D0 */ + __raw_writew(0x0000, PTWCR); + + /* setup pins MMC_CLK, MMC_CMD */ + __raw_writew(__raw_readw(PTXCR) & ~0x000f, PTXCR); + + /* select D3-D0 pin function */ + __raw_writew(__raw_readw(PSELA) & ~0x2000, PSELA); + + /* select D7-D4 pin function */ + __raw_writew(__raw_readw(PSELE) & ~0x3000, PSELE); + + /* disable Hi-Z for the MMC pins */ + __raw_writew(__raw_readw(HIZCRC) & ~0x0620, HIZCRC); + + /* high drive capability for MMC pins */ + __raw_writew(__raw_readw(DRVCRA) | 0x3000, DRVCRA); + + mmcif_update_progress(MMCIF_PROGRESS_INIT); + + /* setup MMCIF hardware */ + sh_mmcif_boot_init(MMCIF_BASE); + + mmcif_update_progress(MMCIF_PROGRESS_LOAD); + + /* load kernel via MMCIF interface */ + sh_mmcif_boot_slurp(MMCIF_BASE, buf, no_bytes); + + /* disable clock to the MMCIF hardware block */ + __raw_writel(__raw_readl(MSTPCR2) | 0x20000000, MSTPCR2); + + mmcif_update_progress(MMCIF_PROGRESS_DONE); +} diff --git a/arch/sh/boot/romimage/vmlinux.scr b/arch/sh/boot/romimage/vmlinux.scr index ea27298a99a7..590394e2f5f2 100644 --- a/arch/sh/boot/romimage/vmlinux.scr +++ b/arch/sh/boot/romimage/vmlinux.scr @@ -3,5 +3,6 @@ SECTIONS .text : { zero_page_pos = .; *(.data) + end_data = .; } } diff --git a/arch/sh/include/cpu-sh4/cpu/sh7724.h b/arch/sh/include/cpu-sh4/cpu/sh7724.h index fbbf550cc529..4c27b68789b3 100644 --- a/arch/sh/include/cpu-sh4/cpu/sh7724.h +++ b/arch/sh/include/cpu-sh4/cpu/sh7724.h @@ -9,6 +9,7 @@ * MD3: BSC - Area0 Bus Width (16/32-bit) [CS0BCR.9,10] * MD5: BSC - Endian Mode (L: Big, H: Little) [CMNCR.3] * MD8: Test Mode + * BOOT: FBR - Boot Mode (L: MMCIF, H: Area0) */ /* Pin Function Controller: diff --git a/arch/sh/include/mach-common/mach/romimage.h b/arch/sh/include/mach-common/mach/romimage.h index 267e24112d82..08fb42269ecd 100644 --- a/arch/sh/include/mach-common/mach/romimage.h +++ b/arch/sh/include/mach-common/mach/romimage.h @@ -1 +1,11 @@ +#ifdef __ASSEMBLY__ + /* do nothing here by default */ + +#else /* __ASSEMBLY__ */ + +extern inline void mmcif_update_progress(int nr) +{ +} + +#endif /* __ASSEMBLY__ */ diff --git a/arch/sh/include/mach-ecovec24/mach/romimage.h b/arch/sh/include/mach-ecovec24/mach/romimage.h index 1c8787ecb1c1..1dcf5e6c8d83 100644 --- a/arch/sh/include/mach-ecovec24/mach/romimage.h +++ b/arch/sh/include/mach-ecovec24/mach/romimage.h @@ -1,3 +1,5 @@ +#ifdef __ASSEMBLY__ + /* EcoVec board specific boot code: * converts the "partner-jet-script.txt" script into assembly * the assembly code is the first code to be executed in the romImage @@ -18,3 +20,28 @@ .align 2 1 : .long 0xa8000000 2 : + +#else /* __ASSEMBLY__ */ + +/* Ecovec board specific information: + * + * Set the following to enable MMCIF boot from the MMC card in CN12: + * + * DS1.5 = OFF (SH BOOT pin set to L) + * DS2.6 = OFF (Select MMCIF on CN12 instead of SDHI1) + * DS2.7 = ON (Select MMCIF on CN12 instead of SDHI1) + * + */ +#define HIZCRA 0xa4050158 +#define PGDR 0xa405012c + +extern inline void mmcif_update_progress(int nr) +{ + /* disable Hi-Z for LED pins */ + __raw_writew(__raw_readw(HIZCRA) & ~(1 << 1), HIZCRA); + + /* update progress on LED4, LED5, LED6 and LED7 */ + __raw_writeb(1 << (nr - 1), PGDR); +} + +#endif /* __ASSEMBLY__ */ diff --git a/arch/sh/include/mach-kfr2r09/mach/romimage.h b/arch/sh/include/mach-kfr2r09/mach/romimage.h index a110823f2bde..976256a323f2 100644 --- a/arch/sh/include/mach-kfr2r09/mach/romimage.h +++ b/arch/sh/include/mach-kfr2r09/mach/romimage.h @@ -1,3 +1,5 @@ +#ifdef __ASSEMBLY__ + /* kfr2r09 board specific boot code: * converts the "partner-jet-script.txt" script into assembly * the assembly code is the first code to be executed in the romImage @@ -18,3 +20,11 @@ .align 2 1: .long 0xa8000000 2: + +#else /* __ASSEMBLY__ */ + +extern inline void mmcif_update_progress(int nr) +{ +} + +#endif /* __ASSEMBLY__ */ -- GitLab From 54e88fad223c4e1d94289611a90c7fe3ebe5631b Mon Sep 17 00:00:00 2001 From: "Amit K. Arora" <aarora@linux.vnet.ibm.com> Date: Tue, 25 May 2010 18:53:46 +0530 Subject: [PATCH 298/842] sched: Make sure timers have migrated before killing the migration_thread Problem: In a stress test where some heavy tests were running along with regular CPU offlining and onlining, a hang was observed. The system seems to be hung at a point where migration_call() tries to kill the migration_thread of the dying CPU, which just got moved to the current CPU. This migration thread does not get a chance to run (and die) since rt_throttled is set to 1 on current, and it doesn't get cleared as the hrtimer which is supposed to reset the rt bandwidth (sched_rt_period_timer) is tied to the CPU which we just marked dead! Solution: This patch pushes the killing of migration thread to "CPU_POST_DEAD" event. By then all the timers (including sched_rt_period_timer) should have got migrated (along with other callbacks). Signed-off-by: Amit Arora <aarora@in.ibm.com> Signed-off-by: Gautham R Shenoy <ego@in.ibm.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Thomas Gleixner <tglx@linutronix.de> LKML-Reference: <20100525132346.GA14986@amitarora.in.ibm.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- kernel/stop_machine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index b4e7431e7c78..70f8d90331e9 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -321,7 +321,7 @@ static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb, #ifdef CONFIG_HOTPLUG_CPU case CPU_UP_CANCELED: - case CPU_DEAD: + case CPU_POST_DEAD: { struct cpu_stop_work *work; -- GitLab From ac9721f3f54b27a16c7e1afb2481e7ee95a70318 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra <a.p.zijlstra@chello.nl> Date: Thu, 27 May 2010 12:54:41 +0200 Subject: [PATCH 299/842] perf_events: Fix races and clean up perf_event and perf_mmap_data interaction In order to move toward separate buffer objects, rework the whole perf_mmap_data construct to be a more self-sufficient entity, one with its own lifetime rules. This greatly sanitizes the whole output redirection code, which was riddled with bugs and races. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: <stable@kernel.org> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- include/linux/perf_event.h | 5 +- kernel/perf_event.c | 224 +++++++++++++++++++++---------------- 2 files changed, 129 insertions(+), 100 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index fb6c91eac7e3..490698590d6e 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -585,6 +585,7 @@ enum perf_event_active_state { struct file; struct perf_mmap_data { + atomic_t refcount; struct rcu_head rcu_head; #ifdef CONFIG_PERF_USE_VMALLOC struct work_struct work; @@ -592,7 +593,6 @@ struct perf_mmap_data { #endif int nr_pages; /* nr of data pages */ int writable; /* are we writable */ - int nr_locked; /* nr pages mlocked */ atomic_t poll; /* POLL_ for wakeups */ @@ -643,7 +643,6 @@ struct perf_event { int nr_siblings; int group_flags; struct perf_event *group_leader; - struct perf_event *output; const struct pmu *pmu; enum perf_event_active_state state; @@ -704,6 +703,8 @@ struct perf_event { /* mmap bits */ struct mutex mmap_mutex; atomic_t mmap_count; + int mmap_locked; + struct user_struct *mmap_user; struct perf_mmap_data *data; /* poll related */ diff --git a/kernel/perf_event.c b/kernel/perf_event.c index bd7ce8ca5bb9..848d49a043e9 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1841,6 +1841,7 @@ static void free_event_rcu(struct rcu_head *head) } static void perf_pending_sync(struct perf_event *event); +static void perf_mmap_data_put(struct perf_mmap_data *data); static void free_event(struct perf_event *event) { @@ -1856,9 +1857,9 @@ static void free_event(struct perf_event *event) atomic_dec(&nr_task_events); } - if (event->output) { - fput(event->output->filp); - event->output = NULL; + if (event->data) { + perf_mmap_data_put(event->data); + event->data = NULL; } if (event->destroy) @@ -2175,7 +2176,27 @@ unlock: return ret; } -static int perf_event_set_output(struct perf_event *event, int output_fd); +static const struct file_operations perf_fops; + +static struct perf_event *perf_fget_light(int fd, int *fput_needed) +{ + struct file *file; + + file = fget_light(fd, fput_needed); + if (!file) + return ERR_PTR(-EBADF); + + if (file->f_op != &perf_fops) { + fput_light(file, *fput_needed); + *fput_needed = 0; + return ERR_PTR(-EBADF); + } + + return file->private_data; +} + +static int perf_event_set_output(struct perf_event *event, + struct perf_event *output_event); static int perf_event_set_filter(struct perf_event *event, void __user *arg); static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -2202,7 +2223,23 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return perf_event_period(event, (u64 __user *)arg); case PERF_EVENT_IOC_SET_OUTPUT: - return perf_event_set_output(event, arg); + { + struct perf_event *output_event = NULL; + int fput_needed = 0; + int ret; + + if (arg != -1) { + output_event = perf_fget_light(arg, &fput_needed); + if (IS_ERR(output_event)) + return PTR_ERR(output_event); + } + + ret = perf_event_set_output(event, output_event); + if (output_event) + fput_light(output_event->filp, fput_needed); + + return ret; + } case PERF_EVENT_IOC_SET_FILTER: return perf_event_set_filter(event, (void __user *)arg); @@ -2335,8 +2372,6 @@ perf_mmap_data_alloc(struct perf_event *event, int nr_pages) unsigned long size; int i; - WARN_ON(atomic_read(&event->mmap_count)); - size = sizeof(struct perf_mmap_data); size += nr_pages * sizeof(void *); @@ -2452,8 +2487,6 @@ perf_mmap_data_alloc(struct perf_event *event, int nr_pages) unsigned long size; void *all_buf; - WARN_ON(atomic_read(&event->mmap_count)); - size = sizeof(struct perf_mmap_data); size += sizeof(void *); @@ -2536,7 +2569,7 @@ perf_mmap_data_init(struct perf_event *event, struct perf_mmap_data *data) if (!data->watermark) data->watermark = max_size / 2; - + atomic_set(&data->refcount, 1); rcu_assign_pointer(event->data, data); } @@ -2548,13 +2581,26 @@ static void perf_mmap_data_free_rcu(struct rcu_head *rcu_head) perf_mmap_data_free(data); } -static void perf_mmap_data_release(struct perf_event *event) +static struct perf_mmap_data *perf_mmap_data_get(struct perf_event *event) { - struct perf_mmap_data *data = event->data; + struct perf_mmap_data *data; + + rcu_read_lock(); + data = rcu_dereference(event->data); + if (data) { + if (!atomic_inc_not_zero(&data->refcount)) + data = NULL; + } + rcu_read_unlock(); + + return data; +} - WARN_ON(atomic_read(&event->mmap_count)); +static void perf_mmap_data_put(struct perf_mmap_data *data) +{ + if (!atomic_dec_and_test(&data->refcount)) + return; - rcu_assign_pointer(event->data, NULL); call_rcu(&data->rcu_head, perf_mmap_data_free_rcu); } @@ -2569,15 +2615,18 @@ static void perf_mmap_close(struct vm_area_struct *vma) { struct perf_event *event = vma->vm_file->private_data; - WARN_ON_ONCE(event->ctx->parent_ctx); if (atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) { unsigned long size = perf_data_size(event->data); - struct user_struct *user = current_user(); + struct user_struct *user = event->mmap_user; + struct perf_mmap_data *data = event->data; atomic_long_sub((size >> PAGE_SHIFT) + 1, &user->locked_vm); - vma->vm_mm->locked_vm -= event->data->nr_locked; - perf_mmap_data_release(event); + vma->vm_mm->locked_vm -= event->mmap_locked; + rcu_assign_pointer(event->data, NULL); mutex_unlock(&event->mmap_mutex); + + perf_mmap_data_put(data); + free_uid(user); } } @@ -2629,13 +2678,10 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) WARN_ON_ONCE(event->ctx->parent_ctx); mutex_lock(&event->mmap_mutex); - if (event->output) { - ret = -EINVAL; - goto unlock; - } - - if (atomic_inc_not_zero(&event->mmap_count)) { - if (nr_pages != event->data->nr_pages) + if (event->data) { + if (event->data->nr_pages == nr_pages) + atomic_inc(&event->data->refcount); + else ret = -EINVAL; goto unlock; } @@ -2667,21 +2713,23 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) WARN_ON(event->data); data = perf_mmap_data_alloc(event, nr_pages); - ret = -ENOMEM; - if (!data) + if (!data) { + ret = -ENOMEM; goto unlock; + } - ret = 0; perf_mmap_data_init(event, data); - - atomic_set(&event->mmap_count, 1); - atomic_long_add(user_extra, &user->locked_vm); - vma->vm_mm->locked_vm += extra; - event->data->nr_locked = extra; if (vma->vm_flags & VM_WRITE) event->data->writable = 1; + atomic_long_add(user_extra, &user->locked_vm); + event->mmap_locked = extra; + event->mmap_user = get_current_user(); + vma->vm_mm->locked_vm += event->mmap_locked; + unlock: + if (!ret) + atomic_inc(&event->mmap_count); mutex_unlock(&event->mmap_mutex); vma->vm_flags |= VM_RESERVED; @@ -2993,7 +3041,6 @@ int perf_output_begin(struct perf_output_handle *handle, struct perf_event *event, unsigned int size, int nmi, int sample) { - struct perf_event *output_event; struct perf_mmap_data *data; unsigned long tail, offset, head; int have_lost; @@ -3010,10 +3057,6 @@ int perf_output_begin(struct perf_output_handle *handle, if (event->parent) event = event->parent; - output_event = rcu_dereference(event->output); - if (output_event) - event = output_event; - data = rcu_dereference(event->data); if (!data) goto out; @@ -4912,39 +4955,17 @@ err_size: goto out; } -static int perf_event_set_output(struct perf_event *event, int output_fd) +static int +perf_event_set_output(struct perf_event *event, struct perf_event *output_event) { - struct perf_event *output_event = NULL; - struct file *output_file = NULL; - struct perf_event *old_output; - int fput_needed = 0; + struct perf_mmap_data *data = NULL, *old_data = NULL; int ret = -EINVAL; - /* - * Don't allow output of inherited per-task events. This would - * create performance issues due to cross cpu access. - */ - if (event->cpu == -1 && event->attr.inherit) - return -EINVAL; - - if (!output_fd) + if (!output_event) goto set; - output_file = fget_light(output_fd, &fput_needed); - if (!output_file) - return -EBADF; - - if (output_file->f_op != &perf_fops) - goto out; - - output_event = output_file->private_data; - - /* Don't chain output fds */ - if (output_event->output) - goto out; - - /* Don't set an output fd when we already have an output channel */ - if (event->data) + /* don't allow circular references */ + if (event == output_event) goto out; /* @@ -4959,26 +4980,28 @@ static int perf_event_set_output(struct perf_event *event, int output_fd) if (output_event->cpu == -1 && output_event->ctx != event->ctx) goto out; - atomic_long_inc(&output_file->f_count); - set: mutex_lock(&event->mmap_mutex); - old_output = event->output; - rcu_assign_pointer(event->output, output_event); - mutex_unlock(&event->mmap_mutex); + /* Can't redirect output if we've got an active mmap() */ + if (atomic_read(&event->mmap_count)) + goto unlock; - if (old_output) { - /* - * we need to make sure no existing perf_output_*() - * is still referencing this event. - */ - synchronize_rcu(); - fput(old_output->filp); + if (output_event) { + /* get the buffer we want to redirect to */ + data = perf_mmap_data_get(output_event); + if (!data) + goto unlock; } + old_data = event->data; + rcu_assign_pointer(event->data, data); ret = 0; +unlock: + mutex_unlock(&event->mmap_mutex); + + if (old_data) + perf_mmap_data_put(old_data); out: - fput_light(output_file, fput_needed); return ret; } @@ -4994,7 +5017,7 @@ SYSCALL_DEFINE5(perf_event_open, struct perf_event_attr __user *, attr_uptr, pid_t, pid, int, cpu, int, group_fd, unsigned long, flags) { - struct perf_event *event, *group_leader; + struct perf_event *event, *group_leader = NULL, *output_event = NULL; struct perf_event_attr attr; struct perf_event_context *ctx; struct file *event_file = NULL; @@ -5034,19 +5057,25 @@ SYSCALL_DEFINE5(perf_event_open, goto err_fd; } + if (group_fd != -1) { + group_leader = perf_fget_light(group_fd, &fput_needed); + if (IS_ERR(group_leader)) { + err = PTR_ERR(group_leader); + goto err_put_context; + } + group_file = group_leader->filp; + if (flags & PERF_FLAG_FD_OUTPUT) + output_event = group_leader; + if (flags & PERF_FLAG_FD_NO_GROUP) + group_leader = NULL; + } + /* * Look up the group leader (we will attach this event to it): */ - group_leader = NULL; - if (group_fd != -1 && !(flags & PERF_FLAG_FD_NO_GROUP)) { + if (group_leader) { err = -EINVAL; - group_file = fget_light(group_fd, &fput_needed); - if (!group_file) - goto err_put_context; - if (group_file->f_op != &perf_fops) - goto err_put_context; - group_leader = group_file->private_data; /* * Do not allow a recursive hierarchy (this new sibling * becoming part of another group-sibling): @@ -5068,9 +5097,16 @@ SYSCALL_DEFINE5(perf_event_open, event = perf_event_alloc(&attr, cpu, ctx, group_leader, NULL, NULL, GFP_KERNEL); - err = PTR_ERR(event); - if (IS_ERR(event)) + if (IS_ERR(event)) { + err = PTR_ERR(event); goto err_put_context; + } + + if (output_event) { + err = perf_event_set_output(event, output_event); + if (err) + goto err_free_put_context; + } event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR); if (IS_ERR(event_file)) { @@ -5078,12 +5114,6 @@ SYSCALL_DEFINE5(perf_event_open, goto err_free_put_context; } - if (flags & PERF_FLAG_FD_OUTPUT) { - err = perf_event_set_output(event, group_fd); - if (err) - goto err_fput_free_put_context; - } - event->filp = event_file; WARN_ON_ONCE(ctx->parent_ctx); mutex_lock(&ctx->mutex); @@ -5101,8 +5131,6 @@ SYSCALL_DEFINE5(perf_event_open, fd_install(event_fd, event_file); return event_fd; -err_fput_free_put_context: - fput(event_file); err_free_put_context: free_event(event); err_put_context: -- GitLab From 8a49542c0554af7d0073aac0ee73ee65b807ef34 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra <a.p.zijlstra@chello.nl> Date: Thu, 27 May 2010 15:47:49 +0200 Subject: [PATCH 300/842] perf_events: Fix races in group composition Group siblings don't pin each-other or the parent, so when we destroy events we must make sure to clean up all cross referencing pointers. In particular, for destruction of a group leader we must be able to find all its siblings and remove their reference to it. This means that detaching an event from its context must not detach it from the group, otherwise we can end up failing to clear all pointers. Solve this by clearly separating the attachment to a context and attachment to a group, and keep the group composed until we destroy the events. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- include/linux/perf_event.h | 4 ++ kernel/perf_event.c | 91 ++++++++++++++++++++++++++++---------- 2 files changed, 71 insertions(+), 24 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 490698590d6e..5d0266d94985 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -631,6 +631,9 @@ struct swevent_hlist { struct rcu_head rcu_head; }; +#define PERF_ATTACH_CONTEXT 0x01 +#define PERF_ATTACH_GROUP 0x02 + /** * struct perf_event - performance event kernel representation: */ @@ -646,6 +649,7 @@ struct perf_event { const struct pmu *pmu; enum perf_event_active_state state; + unsigned int attach_state; atomic64_t count; /* diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 848d49a043e9..10a1aee2309e 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -283,14 +283,15 @@ ctx_group_list(struct perf_event *event, struct perf_event_context *ctx) static void list_add_event(struct perf_event *event, struct perf_event_context *ctx) { - struct perf_event *group_leader = event->group_leader; + WARN_ON_ONCE(event->attach_state & PERF_ATTACH_CONTEXT); + event->attach_state |= PERF_ATTACH_CONTEXT; /* - * Depending on whether it is a standalone or sibling event, - * add it straight to the context's event list, or to the group - * leader's sibling list: + * If we're a stand alone event or group leader, we go to the context + * list, group events are kept attached to the group so that + * perf_group_detach can, at all times, locate all siblings. */ - if (group_leader == event) { + if (event->group_leader == event) { struct list_head *list; if (is_software_event(event)) @@ -298,13 +299,6 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx) list = ctx_group_list(event, ctx); list_add_tail(&event->group_entry, list); - } else { - if (group_leader->group_flags & PERF_GROUP_SOFTWARE && - !is_software_event(event)) - group_leader->group_flags &= ~PERF_GROUP_SOFTWARE; - - list_add_tail(&event->group_entry, &group_leader->sibling_list); - group_leader->nr_siblings++; } list_add_rcu(&event->event_entry, &ctx->event_list); @@ -313,6 +307,24 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx) ctx->nr_stat++; } +static void perf_group_attach(struct perf_event *event) +{ + struct perf_event *group_leader = event->group_leader; + + WARN_ON_ONCE(event->attach_state & PERF_ATTACH_GROUP); + event->attach_state |= PERF_ATTACH_GROUP; + + if (group_leader == event) + return; + + if (group_leader->group_flags & PERF_GROUP_SOFTWARE && + !is_software_event(event)) + group_leader->group_flags &= ~PERF_GROUP_SOFTWARE; + + list_add_tail(&event->group_entry, &group_leader->sibling_list); + group_leader->nr_siblings++; +} + /* * Remove a event from the lists for its context. * Must be called with ctx->mutex and ctx->lock held. @@ -320,17 +332,22 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx) static void list_del_event(struct perf_event *event, struct perf_event_context *ctx) { - if (list_empty(&event->group_entry)) + /* + * We can have double detach due to exit/hot-unplug + close. + */ + if (!(event->attach_state & PERF_ATTACH_CONTEXT)) return; + + event->attach_state &= ~PERF_ATTACH_CONTEXT; + ctx->nr_events--; if (event->attr.inherit_stat) ctx->nr_stat--; - list_del_init(&event->group_entry); list_del_rcu(&event->event_entry); - if (event->group_leader != event) - event->group_leader->nr_siblings--; + if (event->group_leader == event) + list_del_init(&event->group_entry); update_group_times(event); @@ -345,21 +362,39 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) event->state = PERF_EVENT_STATE_OFF; } -static void -perf_destroy_group(struct perf_event *event, struct perf_event_context *ctx) +static void perf_group_detach(struct perf_event *event) { struct perf_event *sibling, *tmp; + struct list_head *list = NULL; + + /* + * We can have double detach due to exit/hot-unplug + close. + */ + if (!(event->attach_state & PERF_ATTACH_GROUP)) + return; + + event->attach_state &= ~PERF_ATTACH_GROUP; + + /* + * If this is a sibling, remove it from its group. + */ + if (event->group_leader != event) { + list_del_init(&event->group_entry); + event->group_leader->nr_siblings--; + return; + } + + if (!list_empty(&event->group_entry)) + list = &event->group_entry; /* * If this was a group event with sibling events then * upgrade the siblings to singleton events by adding them - * to the context list directly: + * to whatever list we are on. */ list_for_each_entry_safe(sibling, tmp, &event->sibling_list, group_entry) { - struct list_head *list; - - list = ctx_group_list(event, ctx); - list_move_tail(&sibling->group_entry, list); + if (list) + list_move_tail(&sibling->group_entry, list); sibling->group_leader = sibling; /* Inherit group flags from the previous leader */ @@ -727,6 +762,7 @@ static void add_event_to_ctx(struct perf_event *event, struct perf_event_context *ctx) { list_add_event(event, ctx); + perf_group_attach(event); event->tstamp_enabled = ctx->time; event->tstamp_running = ctx->time; event->tstamp_stopped = ctx->time; @@ -1894,8 +1930,8 @@ int perf_event_release_kernel(struct perf_event *event) */ mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING); raw_spin_lock_irq(&ctx->lock); + perf_group_detach(event); list_del_event(event, ctx); - perf_destroy_group(event, ctx); raw_spin_unlock_irq(&ctx->lock); mutex_unlock(&ctx->mutex); @@ -5127,6 +5163,12 @@ SYSCALL_DEFINE5(perf_event_open, list_add_tail(&event->owner_entry, ¤t->perf_event_list); mutex_unlock(¤t->perf_event_mutex); + /* + * Drop the reference on the group_event after placing the + * new event on the sibling_list. This ensures destruction + * of the group leader will find the pointer to itself in + * perf_group_detach(). + */ fput_light(group_file, fput_needed); fd_install(event_fd, event_file); return event_fd; @@ -5448,6 +5490,7 @@ static void perf_free_event(struct perf_event *event, fput(parent->filp); + perf_group_detach(event); list_del_event(event, ctx); free_event(event); } -- GitLab From 3771f0771154675d4a0ca780be2411f3cc357208 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra <a.p.zijlstra@chello.nl> Date: Fri, 21 May 2010 12:31:09 +0200 Subject: [PATCH 301/842] perf_events, trace: Fix probe unregister race tracepoint_probe_unregister() does not synchronize against the probe callbacks, so do that explicitly. This properly serializes the callbacks and the free of the data used therein. Also, use this_cpu_ptr() where possible. Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1274438476.1674.1702.camel@laptop> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- include/trace/ftrace.h | 2 +- kernel/trace/trace_event_perf.c | 10 ++++++++-- kernel/trace/trace_kprobe.c | 4 ++-- kernel/trace/trace_syscalls.c | 4 ++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 3d685d1f2a03..5a64905d7278 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -725,7 +725,7 @@ perf_trace_##call(void *__data, proto) \ \ { assign; } \ \ - head = per_cpu_ptr(event_call->perf_events, smp_processor_id());\ + head = this_cpu_ptr(event_call->perf_events); \ perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \ __count, &__regs, head); \ } diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index cb6f365016e4..49c7abf2ba5c 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -116,7 +116,7 @@ int perf_trace_enable(struct perf_event *p_event) if (WARN_ON_ONCE(!list)) return -EINVAL; - list = per_cpu_ptr(list, smp_processor_id()); + list = this_cpu_ptr(list); hlist_add_head_rcu(&p_event->hlist_entry, list); return 0; @@ -142,6 +142,12 @@ void perf_trace_destroy(struct perf_event *p_event) tp_event->class->perf_probe, tp_event); + /* + * Ensure our callback won't be called anymore. See + * tracepoint_probe_unregister() and __DO_TRACE(). + */ + synchronize_sched(); + free_percpu(tp_event->perf_events); tp_event->perf_events = NULL; @@ -169,7 +175,7 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type, if (*rctxp < 0) return NULL; - raw_data = per_cpu_ptr(perf_trace_buf[*rctxp], smp_processor_id()); + raw_data = this_cpu_ptr(perf_trace_buf[*rctxp]); /* zero the dead bytes from align to not leak stack to user */ memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64)); diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index faf7cefd15da..f52b5f50299d 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -1359,7 +1359,7 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp, for (i = 0; i < tp->nr_args; i++) call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); - head = per_cpu_ptr(call->perf_events, smp_processor_id()); + head = this_cpu_ptr(call->perf_events); perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head); } @@ -1392,7 +1392,7 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri, for (i = 0; i < tp->nr_args; i++) call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); - head = per_cpu_ptr(call->perf_events, smp_processor_id()); + head = this_cpu_ptr(call->perf_events); perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, regs, head); } diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index d2c859cec9ea..34e35804304b 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -519,7 +519,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) syscall_get_arguments(current, regs, 0, sys_data->nb_args, (unsigned long *)&rec->args); - head = per_cpu_ptr(sys_data->enter_event->perf_events, smp_processor_id()); + head = this_cpu_ptr(sys_data->enter_event->perf_events); perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head); } @@ -595,7 +595,7 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) rec->nr = syscall_nr; rec->ret = syscall_get_return_value(current, regs); - head = per_cpu_ptr(sys_data->exit_event->perf_events, smp_processor_id()); + head = this_cpu_ptr(sys_data->exit_event->perf_events); perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head); } -- GitLab From 2e97942fe57864588774f173cf4cd7bb68968b76 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra <a.p.zijlstra@chello.nl> Date: Fri, 21 May 2010 16:22:33 +0200 Subject: [PATCH 302/842] perf_events, trace: Fix perf_trace_destroy(), mutex went missing Steve spotted I forgot to do the destroy under event_mutex. Reported-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1274451913.1674.1707.camel@laptop> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- kernel/trace/trace_event_perf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 49c7abf2ba5c..e6f65887842c 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -132,8 +132,9 @@ void perf_trace_destroy(struct perf_event *p_event) struct ftrace_event_call *tp_event = p_event->tp_event; int i; + mutex_lock(&event_mutex); if (--tp_event->perf_refcount > 0) - return; + goto out; if (tp_event->class->reg) tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER); @@ -157,6 +158,8 @@ void perf_trace_destroy(struct perf_event *p_event) perf_trace_buf[i] = NULL; } } +out: + mutex_unlock(&event_mutex); } __kprobes void *perf_trace_buf_prepare(int size, unsigned short type, -- GitLab From 90151c35b19633e0cab5a6c80f1ba4a51e7c913b Mon Sep 17 00:00:00 2001 From: Stephane Eranian <eranian@google.com> Date: Tue, 25 May 2010 16:23:10 +0200 Subject: [PATCH 303/842] perf_events: Fix event scheduling issues introduced by transactional API The transactional API patch between the generic and model-specific code introduced several important bugs with event scheduling, at least on X86. If you had pinned events, e.g., watchdog, and were over-committing the PMU, you would get bogus counts. The bug was showing up on Intel CPU because events would move around more often that on AMD. But the problem also existed on AMD, though harder to expose. The issues were: - group_sched_in() was missing a cancel_txn() in the error path - cpuc->n_added was not properly maintained, leading to missing actions in hw_perf_enable(), i.e., n_running being 0. You cannot update n_added until you know the transaction has succeeded. In case of failed transaction n_added was not adjusted back. - in case of failed transactions, event_sched_out() was called and eventually invoked x86_disable_event() to touch the HW reg. But with transactions, on X86, event_sched_in() does not touch HW registers, it simply collects events into a list. Thus, you could end up calling x86_disable_event() on a counter which did not correspond to the current event when idx != -1. The patch modifies the generic and X86 code to avoid all those problems. First, we keep track of the number of events added last. In case the transaction fails, we substract them from n_added. This approach is necessary (as opposed to delaying updates to n_added) because not all event updates use the transaction API, e.g., single events. Second, we encapsulate the event_sched_in() and event_sched_out() in group_sched_in() inside the transaction. That makes the operations symmetrical and you can also detect that you are inside a transaction and skip the HW reg access by checking cpuc->group_flag. With this patch, you can now overcommit the PMU even with pinned system-wide events present and still get valid counts. Signed-off-by: Stephane Eranian <eranian@google.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1274796225.5882.1389.camel@twins> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- arch/x86/kernel/cpu/perf_event.c | 22 ++++++++++++++++++++++ kernel/perf_event.c | 11 +++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index c77586061bcb..5db5b7d65a18 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -106,6 +106,7 @@ struct cpu_hw_events { int n_events; int n_added; + int n_txn; int assign[X86_PMC_IDX_MAX]; /* event to counter assignment */ u64 tags[X86_PMC_IDX_MAX]; struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */ @@ -983,6 +984,7 @@ static int x86_pmu_enable(struct perf_event *event) out: cpuc->n_events = n; cpuc->n_added += n - n0; + cpuc->n_txn += n - n0; return 0; } @@ -1089,6 +1091,14 @@ static void x86_pmu_disable(struct perf_event *event) struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); int i; + /* + * If we're called during a txn, we don't need to do anything. + * The events never got scheduled and ->cancel_txn will truncate + * the event_list. + */ + if (cpuc->group_flag & PERF_EVENT_TXN_STARTED) + return; + x86_pmu_stop(event); for (i = 0; i < cpuc->n_events; i++) { @@ -1379,6 +1389,7 @@ static void x86_pmu_start_txn(const struct pmu *pmu) struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); cpuc->group_flag |= PERF_EVENT_TXN_STARTED; + cpuc->n_txn = 0; } /* @@ -1391,6 +1402,11 @@ static void x86_pmu_cancel_txn(const struct pmu *pmu) struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); cpuc->group_flag &= ~PERF_EVENT_TXN_STARTED; + /* + * Truncate the collected events. + */ + cpuc->n_added -= cpuc->n_txn; + cpuc->n_events -= cpuc->n_txn; } /* @@ -1419,6 +1435,12 @@ static int x86_pmu_commit_txn(const struct pmu *pmu) */ memcpy(cpuc->assign, assign, n*sizeof(int)); + /* + * Clear out the txn count so that ->cancel_txn() which gets + * run after ->commit_txn() doesn't undo things. + */ + cpuc->n_txn = 0; + return 0; } diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 10a1aee2309e..42a0e9191af5 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -687,8 +687,11 @@ group_sched_in(struct perf_event *group_event, if (txn) pmu->start_txn(pmu); - if (event_sched_in(group_event, cpuctx, ctx)) + if (event_sched_in(group_event, cpuctx, ctx)) { + if (txn) + pmu->cancel_txn(pmu); return -EAGAIN; + } /* * Schedule in siblings as one group (if any): @@ -710,9 +713,6 @@ group_sched_in(struct perf_event *group_event, } group_error: - if (txn) - pmu->cancel_txn(pmu); - /* * Groups can be scheduled in as one unit only, so undo any * partial group before returning: @@ -724,6 +724,9 @@ group_error: } event_sched_out(group_event, cpuctx, ctx); + if (txn) + pmu->cancel_txn(pmu); + return -EAGAIN; } -- GitLab From 74048f895fa8cbf8119b4999f1f44881a825f954 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker <fweisbec@gmail.com> Date: Thu, 27 May 2010 21:34:58 +0200 Subject: [PATCH 304/842] perf_events: Fix unincremented buffer base on partial copy If a sample size crosses to the next page boundary, the copy will be made in more than one step. However we forget to advance the source offset for the next copy, leading to unexpected double copies that completely mess up the traces. This fixes various kinds of bad traces that have irrelevant data inside, as an example: geany-4979 [001] 5758.077775: sched_switch: prev_comm=! prev_pid=121 prev_prio=0 prev_state=S|D|Z|X|x ==> next_comm= next_pid=7497072 next_prio=0 Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1274988898-5639-1-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- kernel/perf_event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 42a0e9191af5..858f56fa2432 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -3064,6 +3064,7 @@ __always_inline void perf_output_copy(struct perf_output_handle *handle, len -= size; handle->addr += size; + buf += size; handle->size -= size; if (!handle->size) { struct perf_mmap_data *data = handle->data; -- GitLab From dd37f8e8659bc617c3f2a84e007a4824ccdac458 Mon Sep 17 00:00:00 2001 From: Daniel T Chen <crimsun@ubuntu.com> Date: Sun, 30 May 2010 01:17:03 -0400 Subject: [PATCH 305/842] ALSA: hda: Use LPIB for an ASUS device BugLink: https://launchpad.net/bugs/465942 Symptom: On the reporter's ASUS device, using PulseAudio in Ubuntu 10.04 LTS results in the PA daemon crashing shortly after attempting to select capture or to configure the audio hardware profile. Test case: Using Ubuntu 10.04 LTS (Linux 2.6.32.12), Linux 2.6.33, or Linux 2.6.34, adjust the HDA device's capture volume with PulseAudio. Resolution: add SSID for this machine to the position_fix quirk table, explicitly specifying the LPIB method. Reported-and-Tested-By: Irihapeti Cc: <stable@kernel.org> Signed-off-by: Daniel T Chen <crimsun@ubuntu.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/hda_intel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index dc79564fea30..7c54a404fe6e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2288,6 +2288,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), -- GitLab From 26fd74fc01991a18f0e3bd54f8b1b75945ee3dbb Mon Sep 17 00:00:00 2001 From: Daniel T Chen <crimsun@ubuntu.com> Date: Sun, 30 May 2010 09:55:23 -0400 Subject: [PATCH 306/842] ALSA: hda: Use mb31 quirk for an iMac model BugLink: https://launchpad.net/bugs/542550 Symptom: On the reporter's iMac, in Ubuntu 10.04 LTS neither playback nor capture appear audible out-of-the-box. Test case: Boot from an Ubuntu 10.04 LTS live cd or from an installed configuration and attempt to play or capture audio. Resolution: Specify the mb31 quirk for this machine in the codec SSID table. Reported-and-Tested-By: f3a97 Cc: <stable@kernel.org> Signed-off-by: Daniel T Chen <crimsun@ubuntu.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 17d4548cc353..d792cddbf4c2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9476,6 +9476,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), -- GitLab From b90c076424da8166797bdc34187660fd0124f530 Mon Sep 17 00:00:00 2001 From: Daniel T Chen <crimsun@ubuntu.com> Date: Sun, 30 May 2010 19:31:41 -0400 Subject: [PATCH 307/842] ALSA: hda: Use LPIB for another mainboard BugLink: https://launchpad.net/bugs/580749 Symptom: on the original reporter's VIA VT1708-based board, the PulseAudio daemon dies shortly after the user attempts to play an audio file. Test case: boot from Ubuntu 10.04 LTS live cd; attempt to play an audio file. Resolution: add SSID for the original reporter's hardware to the position_fix quirk table, explicitly specifying the LPIB method. Reported-and-Tested-By: Harald Cc: <stable@kernel.org> Signed-off-by: Daniel T Chen <crimsun@ubuntu.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/hda_intel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7c54a404fe6e..1640005e0cd9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2297,6 +2297,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB), SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), {} -- GitLab From 546cf44a1b507c1cbb5cf42bbe6169780567f36f Mon Sep 17 00:00:00 2001 From: Randy Dunlap <randy.dunlap@oracle.com> Date: Sat, 29 May 2010 11:45:07 -0700 Subject: [PATCH 308/842] blktrace: Fix new kernel-doc warnings Fix blktrace.c kernel-doc warnings: Warning(kernel/trace/blktrace.c:858): No description found for parameter 'ignore' Warning(kernel/trace/blktrace.c:890): No description found for parameter 'ignore' Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Cc: Jens Axboe <jens.axboe@oracle.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <20100529114507.c466fc1e.randy.dunlap@oracle.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- kernel/trace/blktrace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 36ea2b65dcdc..638711c17504 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -842,6 +842,7 @@ static void blk_add_trace_split(void *ignore, /** * blk_add_trace_remap - Add a trace for a remap operation + * @ignore: trace callback data parameter (not used) * @q: queue the io is for * @bio: the source bio * @dev: target device @@ -873,6 +874,7 @@ static void blk_add_trace_remap(void *ignore, /** * blk_add_trace_rq_remap - Add a trace for a request-remap operation + * @ignore: trace callback data parameter (not used) * @q: queue the io is for * @rq: the source request * @dev: target device -- GitLab From e565813ab95875af0d51a6bcd537068380bb06ea Mon Sep 17 00:00:00 2001 From: Akinobu Mita <akinobu.mita@gmail.com> Date: Mon, 24 May 2010 22:04:51 +0900 Subject: [PATCH 309/842] x86/mm: Remove unused DBG() macro DBG() macro for CONFIG_DEBUG_PER_CPU_MAPS is unused. Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> LKML-Reference: <1274706291-13554-1-git-send-email-akinobu.mita@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- arch/x86/kernel/setup_percpu.c | 6 ------ arch/x86/mm/numa.c | 6 ------ 2 files changed, 12 deletions(-) diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index a867940a6dfc..401ff1085a4d 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c @@ -21,12 +21,6 @@ #include <asm/cpu.h> #include <asm/stackprotector.h> -#ifdef CONFIG_DEBUG_PER_CPU_MAPS -# define DBG(fmt, ...) pr_dbg(fmt, ##__VA_ARGS__) -#else -# define DBG(fmt, ...) do { if (0) pr_dbg(fmt, ##__VA_ARGS__); } while (0) -#endif - DEFINE_PER_CPU(int, cpu_number); EXPORT_PER_CPU_SYMBOL(cpu_number); diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 550df481accd..787c52ca49c3 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -3,12 +3,6 @@ #include <linux/module.h> #include <linux/bootmem.h> -#ifdef CONFIG_DEBUG_PER_CPU_MAPS -# define DBG(x...) printk(KERN_DEBUG x) -#else -# define DBG(x...) -#endif - /* * Which logical CPUs are on which nodes */ -- GitLab From 84cb0999851e25bc4bd4aaa717cc8f8acbf42b2a Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Date: Sat, 22 May 2010 12:49:32 +0900 Subject: [PATCH 310/842] nilfs2: fix style issue in nilfs_destroy_cachep This gets rid of unwanted space chars in front of conditional sentences of nilfs_destroy_cachep(). Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> --- fs/nilfs2/super.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 03b34b738993..414ef68931cf 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -1130,13 +1130,13 @@ static void nilfs_segbuf_init_once(void *obj) static void nilfs_destroy_cachep(void) { - if (nilfs_inode_cachep) + if (nilfs_inode_cachep) kmem_cache_destroy(nilfs_inode_cachep); - if (nilfs_transaction_cachep) + if (nilfs_transaction_cachep) kmem_cache_destroy(nilfs_transaction_cachep); - if (nilfs_segbuf_cachep) + if (nilfs_segbuf_cachep) kmem_cache_destroy(nilfs_segbuf_cachep); - if (nilfs_btree_path_cache) + if (nilfs_btree_path_cache) kmem_cache_destroy(nilfs_btree_path_cache); } -- GitLab From c29684d6834af7b3792f2feb6bdcf8c906ad8db6 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Date: Sun, 23 May 2010 20:40:32 +0900 Subject: [PATCH 311/842] nilfs2: remove obsolete declarations of cache constructor and destructor The commit 41c88bd7 ("nilfs2: cleanup multi kmem_cache_{create,destroy} code") consolidated slab constructors and destructors used in nilfs, but it left some declarations in header files. This gets rid of the obsolete declarations. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> --- fs/nilfs2/btree.h | 2 -- fs/nilfs2/segbuf.h | 2 -- fs/nilfs2/segment.h | 2 -- 3 files changed, 6 deletions(-) diff --git a/fs/nilfs2/btree.h b/fs/nilfs2/btree.h index af638d59e3bf..43c8c5b541fd 100644 --- a/fs/nilfs2/btree.h +++ b/fs/nilfs2/btree.h @@ -75,8 +75,6 @@ struct nilfs_btree_path { extern struct kmem_cache *nilfs_btree_path_cache; -int nilfs_btree_path_cache_init(void); -void nilfs_btree_path_cache_destroy(void); int nilfs_btree_init(struct nilfs_bmap *); int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64, const __u64 *, const __u64 *, int); diff --git a/fs/nilfs2/segbuf.h b/fs/nilfs2/segbuf.h index fdf1c3b6d673..85fbb66455e2 100644 --- a/fs/nilfs2/segbuf.h +++ b/fs/nilfs2/segbuf.h @@ -127,8 +127,6 @@ struct nilfs_segment_buffer { extern struct kmem_cache *nilfs_segbuf_cachep; -int __init nilfs_init_segbuf_cache(void); -void nilfs_destroy_segbuf_cache(void); struct nilfs_segment_buffer *nilfs_segbuf_new(struct super_block *); void nilfs_segbuf_free(struct nilfs_segment_buffer *); void nilfs_segbuf_map(struct nilfs_segment_buffer *, __u64, unsigned long, diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h index dca142361ccf..01e20dbb217d 100644 --- a/fs/nilfs2/segment.h +++ b/fs/nilfs2/segment.h @@ -221,8 +221,6 @@ enum { extern struct kmem_cache *nilfs_transaction_cachep; /* segment.c */ -extern int nilfs_init_transaction_cache(void); -extern void nilfs_destroy_transaction_cache(void); extern void nilfs_relax_pressure_in_lock(struct super_block *); extern int nilfs_construct_segment(struct super_block *); -- GitLab From bc284f94f84c3d76e49c6f3df9028c503f9589d9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" <davem@davemloft.net> Date: Mon, 31 May 2010 05:47:32 -0700 Subject: [PATCH 312/842] greth: Fix build after OF device conversions. Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/greth.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/greth.c b/drivers/net/greth.c index f37a4c143ddd..3a029d02c2b4 100644 --- a/drivers/net/greth.c +++ b/drivers/net/greth.c @@ -1607,14 +1607,13 @@ static struct of_device_id greth_of_match[] = { MODULE_DEVICE_TABLE(of, greth_of_match); static struct of_platform_driver greth_of_driver = { - .name = "grlib-greth", - .match_table = greth_of_match, + .driver = { + .name = "grlib-greth", + .owner = THIS_MODULE, + .of_match_table = greth_of_match, + }, .probe = greth_of_probe, .remove = __devexit_p(greth_of_remove), - .driver = { - .owner = THIS_MODULE, - .name = "grlib-greth", - }, }; static int __init greth_init(void) -- GitLab From c936e8bd1de2fa50c49e3df6fa5036bf07870b67 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng <dfeng@redhat.com> Date: Mon, 31 May 2010 16:41:09 +0200 Subject: [PATCH 313/842] netfilter: don't xt_jumpstack_alloc twice in xt_register_table In xt_register_table, xt_jumpstack_alloc is called first, later xt_replace_table is used. But in xt_replace_table, xt_jumpstack_alloc will be used again. Then the memory allocated by previous xt_jumpstack_alloc will be leaked. We can simply remove the previous xt_jumpstack_alloc because there aren't any users of newinfo between xt_jumpstack_alloc and xt_replace_table. Signed-off-by: Xiaotian Feng <dfeng@redhat.com> Cc: Patrick McHardy <kaber@trash.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Jan Engelhardt <jengelh@medozas.de> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Alexey Dobriyan <adobriyan@gmail.com> Acked-By: Jan Engelhardt <jengelh@medozas.de> Signed-off-by: Patrick McHardy <kaber@trash.net> --- net/netfilter/x_tables.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 445de702b8b7..47b1e7917a9c 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -844,10 +844,6 @@ struct xt_table *xt_register_table(struct net *net, struct xt_table_info *private; struct xt_table *t, *table; - ret = xt_jumpstack_alloc(newinfo); - if (ret < 0) - return ERR_PTR(ret); - /* Don't add one object to multiple lists. */ table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL); if (!table) { -- GitLab From 7489aec8eed4f2f1eb3b4d35763bd3ea30b32ef5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Mon, 31 May 2010 16:41:35 +0200 Subject: [PATCH 314/842] netfilter: xtables: stackptr should be percpu commit f3c5c1bfd4 (netfilter: xtables: make ip_tables reentrant) introduced a performance regression, because stackptr array is shared by all cpus, adding cache line ping pongs. (16 cpus share a 64 bytes cache line) Fix this using alloc_percpu() Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Acked-By: Jan Engelhardt <jengelh@medozas.de> Signed-off-by: Patrick McHardy <kaber@trash.net> --- include/linux/netfilter/x_tables.h | 2 +- net/ipv4/netfilter/ip_tables.c | 2 +- net/ipv6/netfilter/ip6_tables.c | 2 +- net/netfilter/x_tables.c | 13 +++---------- 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index c00cc0c4d0b7..24e5d01d27d0 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -397,7 +397,7 @@ struct xt_table_info { * @stacksize jumps (number of user chains) can possibly be made. */ unsigned int stacksize; - unsigned int *stackptr; + unsigned int __percpu *stackptr; void ***jumpstack; /* ipt_entry tables: one per CPU */ /* Note : this field MUST be the last one, see XT_TABLE_INFO_SZ */ diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 63958f3394a5..4b6c5ca610fc 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -336,7 +336,7 @@ ipt_do_table(struct sk_buff *skb, cpu = smp_processor_id(); table_base = private->entries[cpu]; jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; - stackptr = &private->stackptr[cpu]; + stackptr = per_cpu_ptr(private->stackptr, cpu); origptr = *stackptr; e = get_entry(table_base, private->hook_entry[hook]); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 6f517bd83692..9d2d68f0e605 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -363,7 +363,7 @@ ip6t_do_table(struct sk_buff *skb, cpu = smp_processor_id(); table_base = private->entries[cpu]; jumpstack = (struct ip6t_entry **)private->jumpstack[cpu]; - stackptr = &private->stackptr[cpu]; + stackptr = per_cpu_ptr(private->stackptr, cpu); origptr = *stackptr; e = get_entry(table_base, private->hook_entry[hook]); diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 47b1e7917a9c..e34622fa0003 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -699,10 +699,8 @@ void xt_free_table_info(struct xt_table_info *info) vfree(info->jumpstack); else kfree(info->jumpstack); - if (sizeof(unsigned int) * nr_cpu_ids > PAGE_SIZE) - vfree(info->stackptr); - else - kfree(info->stackptr); + + free_percpu(info->stackptr); kfree(info); } @@ -753,14 +751,9 @@ static int xt_jumpstack_alloc(struct xt_table_info *i) unsigned int size; int cpu; - size = sizeof(unsigned int) * nr_cpu_ids; - if (size > PAGE_SIZE) - i->stackptr = vmalloc(size); - else - i->stackptr = kmalloc(size, GFP_KERNEL); + i->stackptr = alloc_percpu(unsigned int); if (i->stackptr == NULL) return -ENOMEM; - memset(i->stackptr, 0, size); size = sizeof(void **) * nr_cpu_ids; if (size > PAGE_SIZE) -- GitLab From dcbe7bcfa32c5bc4f9bb6c75d4d41bb4db8c36fc Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@caiaq.de> Date: Mon, 31 May 2010 13:35:36 +0200 Subject: [PATCH 315/842] ALSA: usb-audio: UAC2: clean up parsing of bmaControls Introduce two new static inline functions for a more readable parsing of UAC2 bmaControls. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- include/linux/usb/audio-v2.h | 10 ++++++++++ sound/usb/mixer.c | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index 92f1d99f0f17..8f91be3599c6 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h @@ -18,6 +18,16 @@ /* v1.0 and v2.0 of this standard have many things in common. For the rest * of the definitions, please refer to audio.h */ +static inline bool uac2_control_is_readable(u32 bmControls, u8 control) +{ + return (bmControls >> (control * 2)) & 0x1; +} + +static inline bool uac2_control_is_writeable(u32 bmControls, u8 control) +{ + return (bmControls >> (control * 2)) & 0x2; +} + /* 4.7.2.1 Clock Source Descriptor */ struct uac_clock_source_descriptor { diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 03ce971e0027..43d6417b811e 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1188,9 +1188,9 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void for (j = 0; j < channels; j++) { unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); - if (mask & (1 << (i * 2))) { + if (uac2_control_is_readable(mask, i)) { ch_bits |= (1 << j); - if (~mask & (1 << ((i * 2) + 1))) + if (!uac2_control_is_writeable(mask, i)) ch_read_only |= (1 << j); } } @@ -1198,9 +1198,9 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void /* FIXME: the whole unit is read-only if any of the channels is marked read-only */ if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, !!ch_read_only); - if (master_bits & (1 << i * 2)) + if (uac2_control_is_readable(master_bits, i)) build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, - ~master_bits & (1 << ((i * 2) + 1))); + !uac2_control_is_writeable(master_bits, i)); } } -- GitLab From a6a3325913efbe35a10e87fd3e9c3ce621fd32c7 Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@caiaq.de> Date: Mon, 31 May 2010 13:35:37 +0200 Subject: [PATCH 316/842] ALSA: usb-audio: support partially write-protected UAC2 controls So far, UAC2 controls are marked read-only if any of the channels are marked read-only in the descriptors. Change this behaviour and - mark them writeable unless all channels are read-only - store the read-only mask in usb_mixer_elem_info and - check the mask again in set_cur_mix_value(), and bail out for write-protected channels. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/usb/mixer.c | 30 ++++++++++++++++++++++++------ sound/usb/mixer.h | 2 ++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 43d6417b811e..9149a84c716f 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -462,6 +462,16 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int index, int value) { int err; + unsigned int read_only = (channel == 0) ? + cval->master_readonly : + cval->ch_readonly & (1 << (channel - 1)); + + if (read_only) { + snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n", + __func__, channel, cval->control); + return 0; + } + err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, value); if (err < 0) @@ -958,7 +968,7 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str) static void build_feature_ctl(struct mixer_build *state, void *raw_desc, unsigned int ctl_mask, int control, struct usb_audio_term *iterm, int unitid, - int read_only) + int readonly_mask) { struct uac_feature_unit_descriptor *desc = raw_desc; unsigned int len = 0; @@ -989,20 +999,25 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, cval->control = control; cval->cmask = ctl_mask; cval->val_type = audio_feature_info[control-1].type; - if (ctl_mask == 0) + if (ctl_mask == 0) { cval->channels = 1; /* master channel */ - else { + cval->master_readonly = readonly_mask; + } else { int i, c = 0; for (i = 0; i < 16; i++) if (ctl_mask & (1 << i)) c++; cval->channels = c; + cval->ch_readonly = readonly_mask; } /* get min/max values */ get_min_max(cval, 0); - if (read_only) + /* if all channels in the mask are marked read-only, make the control + * read-only. set_cur_mix_value() will check the mask again and won't + * issue write commands to read-only channels. */ + if (cval->channels == readonly_mask) kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); else kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); @@ -1195,9 +1210,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void } } - /* FIXME: the whole unit is read-only if any of the channels is marked read-only */ + /* NOTE: build_feature_ctl() will mark the control read-only if all channels + * are marked read-only in the descriptors. Otherwise, the control will be + * reported as writeable, but the driver will not actually issue a write + * command for read-only channels */ if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ - build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, !!ch_read_only); + build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, ch_read_only); if (uac2_control_is_readable(master_bits, i)) build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, !uac2_control_is_writeable(master_bits, i)); diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 130123854a6c..a7cf1007fbb0 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -34,6 +34,8 @@ struct usb_mixer_elem_info { unsigned int id; unsigned int control; /* CS or ICN (high byte) */ unsigned int cmask; /* channel mask bitmap: 0 = master */ + unsigned int ch_readonly; + unsigned int master_readonly; int channels; int val_type; int min, max, res; -- GitLab From 5dd360ebd8328affb22225141cece3a29403b965 Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@caiaq.de> Date: Mon, 31 May 2010 13:35:38 +0200 Subject: [PATCH 317/842] include/linux/usb/audio-v2.h: add more UAC2 details Also, remove the 'bmControl' field from uac_clock_selector_descriptor, which was at the wrong offset. This struct is currently unused. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- include/linux/usb/audio-v2.h | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index 8f91be3599c6..383b94ba8c20 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h @@ -41,6 +41,13 @@ struct uac_clock_source_descriptor { __u8 iClockSource; } __attribute__((packed)); +/* bmAttribute fields */ +#define UAC_CLOCK_SOURCE_TYPE_EXT 0x0 +#define UAC_CLOCK_SOURCE_TYPE_INT_FIXED 0x1 +#define UAC_CLOCK_SOURCE_TYPE_INT_VAR 0x2 +#define UAC_CLOCK_SOURCE_TYPE_INT_PROG 0x3 +#define UAC_CLOCK_SOURCE_SYNCED_TO_SOF (1 << 2) + /* 4.7.2.2 Clock Source Descriptor */ struct uac_clock_selector_descriptor { @@ -49,8 +56,20 @@ struct uac_clock_selector_descriptor { __u8 bDescriptorSubtype; __u8 bClockID; __u8 bNrInPins; - __u8 bmControls; __u8 baCSourceID[]; + /* bmControls, bAssocTerminal and iClockSource omitted */ +} __attribute__((packed)); + +/* 4.7.2.3 Clock Multiplier Descriptor */ + +struct uac_clock_multiplier_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubtype; + __u8 bClockID; + __u8 bCSourceID; + __u8 bmControls; + __u8 iClockMultiplier; } __attribute__((packed)); /* 4.7.2.4 Input terminal descriptor */ -- GitLab From 7176d37a28fa4ea7e32815007673f578cdcebf51 Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@caiaq.de> Date: Mon, 31 May 2010 13:35:39 +0200 Subject: [PATCH 318/842] ALSA: usb-audio: fix selector unit string index accessor This is another regression from the UAC2 code refactoring. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- include/linux/usb/audio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index 5d646c388752..ed5cf92a3c0f 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h @@ -244,7 +244,7 @@ struct uac_selector_unit_descriptor { static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc) { __u8 *raw = (__u8 *) desc; - return raw[9 + desc->bLength - 1]; + return raw[desc->bLength - 1]; } /* 4.3.2.5 Feature Unit Descriptor */ -- GitLab From 79f920fbff566ffc9de44111eb1456a3cef310f0 Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@caiaq.de> Date: Mon, 31 May 2010 14:51:31 +0200 Subject: [PATCH 319/842] ALSA: usb-audio: parse clock topology of UAC2 devices Audio devices which comply to the UAC2 standard can export complex clock topologies in its descriptors and set up links between them. The entities that are defined are - clock sources, which define the end-leafs. - clock selectors, which act as switch to select one out of many possible clocks sources. - clock multipliers, which have an input clock source, and act as clock source again. They can be used to derive one clock from another. All sample rate changes, clock validity queries and the like must go to clock source elements, while clock selectors and multipliers can be used as terminal clock source. The following patch adds a parser for these elements and functions to iterate over the tree and find the leaf nodes (clock sources). The samplerate set functions were moved to the new clock.c file. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/usb/Makefile | 3 +- sound/usb/card.c | 18 +-- sound/usb/card.h | 1 + sound/usb/clock.c | 311 +++++++++++++++++++++++++++++++++++++++++++ sound/usb/clock.h | 12 ++ sound/usb/endpoint.c | 57 +++++++- sound/usb/format.c | 16 ++- sound/usb/pcm.c | 98 +------------- sound/usb/usbaudio.h | 5 +- 9 files changed, 396 insertions(+), 125 deletions(-) create mode 100644 sound/usb/clock.c create mode 100644 sound/usb/clock.h diff --git a/sound/usb/Makefile b/sound/usb/Makefile index e7ac7f493a8f..1e362bf8834f 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -11,7 +11,8 @@ snd-usb-audio-objs := card.o \ endpoint.o \ urb.o \ pcm.o \ - helper.o + helper.o \ + clock.o snd-usbmidi-lib-objs := midi.o diff --git a/sound/usb/card.c b/sound/usb/card.c index da1346bd4856..7a8ac1d81be7 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -236,7 +236,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) } case UAC_VERSION_2: { - struct uac_clock_source_descriptor *cs; struct usb_interface_assoc_descriptor *assoc = usb_ifnum_to_if(dev, ctrlif)->intf_assoc; @@ -245,21 +244,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) return -EINVAL; } - /* FIXME: for now, we expect there is at least one clock source - * descriptor and we always take the first one. - * We should properly support devices with multiple clock sources, - * clock selectors and sample rate conversion units. */ - - cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, - NULL, UAC2_CLOCK_SOURCE); - - if (!cs) { - snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n"); - return -EINVAL; - } - - chip->clock_id = cs->bClockID; - for (i = 0; i < assoc->bInterfaceCount; i++) { int intf = assoc->bFirstInterface + i; @@ -481,6 +465,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __error; } + chip->ctrl_intf = alts; + if (err > 0) { /* create normal USB audio interfaces */ if (snd_usb_create_streams(chip, ifnum) < 0 || diff --git a/sound/usb/card.h b/sound/usb/card.h index ed92420c1095..1febf2f23754 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -25,6 +25,7 @@ struct audioformat { unsigned int rate_min, rate_max; /* min/max rates */ unsigned int nr_rates; /* number of rate table entries */ unsigned int *rate_table; /* rate table */ + unsigned char clock; /* associated clock */ }; struct snd_usb_substream; diff --git a/sound/usb/clock.c b/sound/usb/clock.c new file mode 100644 index 000000000000..b7aadd614c70 --- /dev/null +++ b/sound/usb/clock.c @@ -0,0 +1,311 @@ +/* + * Clock domain and sample rate management functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/bitops.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/usb.h> +#include <linux/moduleparam.h> +#include <linux/mutex.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h> + +#include <sound/core.h> +#include <sound/info.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> + +#include "usbaudio.h" +#include "card.h" +#include "midi.h" +#include "mixer.h" +#include "proc.h" +#include "quirks.h" +#include "endpoint.h" +#include "helper.h" +#include "debug.h" +#include "pcm.h" +#include "urb.h" +#include "format.h" + +static struct uac_clock_source_descriptor * + snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface, + int clock_id) +{ + struct uac_clock_source_descriptor *cs = NULL; + + while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + cs, UAC2_CLOCK_SOURCE))) { + if (cs->bClockID == clock_id) + return cs; + } + + return NULL; +} + +static struct uac_clock_selector_descriptor * + snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface, + int clock_id) +{ + struct uac_clock_selector_descriptor *cs = NULL; + + while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + cs, UAC2_CLOCK_SELECTOR))) { + if (cs->bClockID == clock_id) + return cs; + } + + return NULL; +} + +static struct uac_clock_multiplier_descriptor * + snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface, + int clock_id) +{ + struct uac_clock_multiplier_descriptor *cs = NULL; + + while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + cs, UAC2_CLOCK_MULTIPLIER))) { + if (cs->bClockID == clock_id) + return cs; + } + + return NULL; +} + +static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) +{ + unsigned char buf; + int ret; + + ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), + UAC2_CS_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + UAC2_CX_CLOCK_SELECTOR << 8, selector_id << 8, + &buf, sizeof(buf), 1000); + + if (ret < 0) + return ret; + + return buf; +} + +static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) +{ + int err; + unsigned char data; + struct usb_device *dev = chip->dev; + + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_CLOCK_VALID << 8, source_id << 8, + &data, sizeof(data), 1000); + + if (err < 0) { + snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", + __func__, source_id); + return err; + } + + return !!data; +} + +/* Try to find the clock source ID of a given clock entity */ + +static int __uac_clock_find_source(struct snd_usb_audio *chip, + struct usb_host_interface *host_iface, + int entity_id, unsigned long *visited) +{ + struct uac_clock_source_descriptor *source; + struct uac_clock_selector_descriptor *selector; + struct uac_clock_multiplier_descriptor *multiplier; + + entity_id &= 0xff; + + if (test_and_set_bit(entity_id, visited)) { + snd_printk(KERN_WARNING + "%s(): recursive clock topology detected, id %d.\n", + __func__, entity_id); + return -EINVAL; + } + + /* first, see if the ID we're looking for is a clock source already */ + source = snd_usb_find_clock_source(host_iface, entity_id); + if (source) + return source->bClockID; + + selector = snd_usb_find_clock_selector(host_iface, entity_id); + if (selector) { + int ret; + + /* the entity ID we are looking for is a selector. + * find out what it currently selects */ + ret = uac_clock_selector_get_val(chip, selector->bClockID); + if (ret < 0) + return ret; + + if (ret > selector->bNrInPins || ret < 1) { + printk(KERN_ERR + "%s(): selector reported illegal value, id %d, ret %d\n", + __func__, selector->bClockID, ret); + + return -EINVAL; + } + + return __uac_clock_find_source(chip, host_iface, + selector->baCSourceID[ret-1], + visited); + } + + /* FIXME: multipliers only act as pass-thru element for now */ + multiplier = snd_usb_find_clock_multiplier(host_iface, entity_id); + if (multiplier) + return __uac_clock_find_source(chip, host_iface, + multiplier->bCSourceID, visited); + + return -EINVAL; +} + +int snd_usb_clock_find_source(struct snd_usb_audio *chip, + struct usb_host_interface *host_iface, + int entity_id) +{ + DECLARE_BITMAP(visited, 256); + memset(visited, 0, sizeof(visited)); + return __uac_clock_find_source(chip, host_iface, entity_id, visited); +} + +static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, + struct usb_host_interface *alts, + struct audioformat *fmt, int rate) +{ + struct usb_device *dev = chip->dev; + unsigned int ep; + unsigned char data[3]; + int err, crate; + + ep = get_endpoint(alts, 0)->bEndpointAddress; + + /* if endpoint doesn't have sampling rate control, bail out */ + if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { + snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", + dev->devnum, iface, fmt->altsetting); + return 0; + } + + data[0] = rate; + data[1] = rate >> 8; + data[2] = rate >> 16; + if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, + USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, + UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, + data, sizeof(data), 1000)) < 0) { + snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", + dev->devnum, iface, fmt->altsetting, rate, ep); + return err; + } + + if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, + USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, + UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, + data, sizeof(data), 1000)) < 0) { + snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", + dev->devnum, iface, fmt->altsetting, ep); + return 0; /* some devices don't support reading */ + } + + crate = data[0] | (data[1] << 8) | (data[2] << 16); + if (crate != rate) { + snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); + // runtime->rate = crate; + } + + return 0; +} + +static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, + struct usb_host_interface *alts, + struct audioformat *fmt, int rate) +{ + struct usb_device *dev = chip->dev; + unsigned char data[4]; + int err, crate; + int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fmt->clock); + + if (clock < 0) + return clock; + + if (!uac_clock_source_is_valid(chip, clock)) { + snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n", + dev->devnum, iface, fmt->altsetting, clock); + return -ENXIO; + } + + data[0] = rate; + data[1] = rate >> 8; + data[2] = rate >> 16; + data[3] = rate >> 24; + if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, + data, sizeof(data), 1000)) < 0) { + snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", + dev->devnum, iface, fmt->altsetting, rate); + return err; + } + + if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, + data, sizeof(data), 1000)) < 0) { + snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", + dev->devnum, iface, fmt->altsetting); + return err; + } + + crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + if (crate != rate) + snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); + + return 0; +} + +int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, + struct usb_host_interface *alts, + struct audioformat *fmt, int rate) +{ + struct usb_interface_descriptor *altsd = get_iface_desc(alts); + + switch (altsd->bInterfaceProtocol) { + case UAC_VERSION_1: + return set_sample_rate_v1(chip, iface, alts, fmt, rate); + + case UAC_VERSION_2: + return set_sample_rate_v2(chip, iface, alts, fmt, rate); + } + + return -EINVAL; +} + diff --git a/sound/usb/clock.h b/sound/usb/clock.h new file mode 100644 index 000000000000..beb253684e2d --- /dev/null +++ b/sound/usb/clock.h @@ -0,0 +1,12 @@ +#ifndef __USBAUDIO_CLOCK_H +#define __USBAUDIO_CLOCK_H + +int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, + struct usb_host_interface *alts, + struct audioformat *fmt, int rate); + +int snd_usb_clock_find_source(struct snd_usb_audio *chip, + struct usb_host_interface *host_iface, + int entity_id); + +#endif /* __USBAUDIO_CLOCK_H */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 28ee1ce3971a..9593b91452b9 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -190,6 +190,38 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, return attributes; } +static struct uac2_input_terminal_descriptor * + snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, + int terminal_id) +{ + struct uac2_input_terminal_descriptor *term = NULL; + + while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + term, UAC_INPUT_TERMINAL))) { + if (term->bTerminalID == terminal_id) + return term; + } + + return NULL; +} + +static struct uac2_output_terminal_descriptor * + snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, + int terminal_id) +{ + struct uac2_output_terminal_descriptor *term = NULL; + + while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + term, UAC_OUTPUT_TERMINAL))) { + if (term->bTerminalID == terminal_id) + return term; + } + + return NULL; +} + int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) { struct usb_device *dev; @@ -199,7 +231,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) int i, altno, err, stream; int format = 0, num_channels = 0; struct audioformat *fp = NULL; - int num, protocol; + int num, protocol, clock = 0; struct uac_format_type_i_continuous_descriptor *fmt; dev = chip->dev; @@ -263,6 +295,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) } case UAC_VERSION_2: { + struct uac2_input_terminal_descriptor *input_term; + struct uac2_output_terminal_descriptor *output_term; struct uac_as_header_descriptor_v2 *as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); @@ -281,7 +315,25 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) num_channels = as->bNrChannels; format = le32_to_cpu(as->bmFormats); - break; + /* lookup the terminal associated to this interface + * to extract the clock */ + input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (input_term) { + clock = input_term->bCSourceID; + break; + } + + output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (output_term) { + clock = output_term->bCSourceID; + break; + } + + snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n", + dev->devnum, iface_no, altno, as->bTerminalLink); + continue; } default: @@ -338,6 +390,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) * (fp->maxpacksize & 0x7ff); fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); + fp->clock = clock; /* some quirks for attributes here */ diff --git a/sound/usb/format.c b/sound/usb/format.c index fe29d61de19b..5367cd1e52d9 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -29,6 +29,7 @@ #include "quirks.h" #include "helper.h" #include "debug.h" +#include "clock.h" /* * parse the audio format type I descriptor @@ -215,15 +216,17 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, struct usb_device *dev = chip->dev; unsigned char tmp[2], *data; int i, nr_rates, data_size, ret = 0; + int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fp->clock); /* get the number of sample rates first by only fetching 2 bytes */ ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, + UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, tmp, sizeof(tmp), 1000); if (ret < 0) { - snd_printk(KERN_ERR "unable to retrieve number of sample rates\n"); + snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n", + __func__, clock); goto err; } @@ -237,12 +240,13 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, /* now get the full information */ ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, - data, data_size, 1000); + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, + data, data_size, 1000); if (ret < 0) { - snd_printk(KERN_ERR "unable to retrieve sample rate range\n"); + snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n", + __func__, clock); ret = -EINVAL; goto err_free; } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 056587de7be4..456829882f40 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -31,6 +31,7 @@ #include "urb.h" #include "helper.h" #include "pcm.h" +#include "clock.h" /* * return the current pcm pointer. just based on the hwptr_done value. @@ -181,103 +182,6 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, return -EINVAL; } -static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, - struct audioformat *fmt, int rate) -{ - struct usb_device *dev = chip->dev; - unsigned int ep; - unsigned char data[3]; - int err, crate; - - ep = get_endpoint(alts, 0)->bEndpointAddress; - /* if endpoint doesn't have sampling rate control, bail out */ - if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { - snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", - dev->devnum, iface, fmt->altsetting); - return 0; - } - - data[0] = rate; - data[1] = rate >> 8; - data[2] = rate >> 16; - if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, - USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, - UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, - data, sizeof(data), 1000)) < 0) { - snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", - dev->devnum, iface, fmt->altsetting, rate, ep); - return err; - } - if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, - USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, - UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, - data, sizeof(data), 1000)) < 0) { - snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", - dev->devnum, iface, fmt->altsetting, ep); - return 0; /* some devices don't support reading */ - } - crate = data[0] | (data[1] << 8) | (data[2] << 16); - if (crate != rate) { - snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); - // runtime->rate = crate; - } - - return 0; -} - -static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, - struct audioformat *fmt, int rate) -{ - struct usb_device *dev = chip->dev; - unsigned char data[4]; - int err, crate; - - data[0] = rate; - data[1] = rate >> 8; - data[2] = rate >> 16; - data[3] = rate >> 24; - if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, - data, sizeof(data), 1000)) < 0) { - snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", - dev->devnum, iface, fmt->altsetting, rate); - return err; - } - if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, - data, sizeof(data), 1000)) < 0) { - snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", - dev->devnum, iface, fmt->altsetting); - return err; - } - crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); - if (crate != rate) - snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); - - return 0; -} - -int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, - struct usb_host_interface *alts, - struct audioformat *fmt, int rate) -{ - struct usb_interface_descriptor *altsd = get_iface_desc(alts); - - switch (altsd->bInterfaceProtocol) { - case UAC_VERSION_1: - return set_sample_rate_v1(chip, iface, alts, fmt, rate); - - case UAC_VERSION_2: - return set_sample_rate_v2(chip, iface, alts, fmt, rate); - } - - return -EINVAL; -} - /* * find a matching format and set up the interface */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 06ebf24d3a4d..24d3319cc34d 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -40,9 +40,6 @@ struct snd_usb_audio { int num_interfaces; int num_suspended_intf; - /* for audio class v2 */ - int clock_id; - struct list_head pcm_list; /* list of pcm streams */ int pcm_devs; @@ -53,6 +50,8 @@ struct snd_usb_audio { int setup; /* from the 'device_setup' module param */ int nrpacks; /* from the 'nrpacks' module param */ int async_unlink; /* from the 'async_unlink' module param */ + + struct usb_host_interface *ctrl_intf; /* the audio control interface */ }; /* -- GitLab From 65f25da44b51f55e3a74301c25f29263be2bf1ba Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@caiaq.de> Date: Mon, 31 May 2010 13:35:41 +0200 Subject: [PATCH 320/842] ALSA: usb-audio: unify constants from specification Move more definitions from private enums to appropriate header files. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- include/linux/usb/audio.h | 88 ++++++++++++++++++++++++---------- sound/usb/mixer.c | 99 +++++++++++++-------------------------- sound/usb/mixer_maps.c | 4 +- 3 files changed, 98 insertions(+), 93 deletions(-) diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index ed5cf92a3c0f..c51200c715e5 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h @@ -47,6 +47,15 @@ #define UAC_FORMAT_TYPE 0x02 #define UAC_FORMAT_SPECIFIC 0x03 +/* A.7 Processing Unit Process Types */ +#define UAC_PROCESS_UNDEFINED 0x00 +#define UAC_PROCESS_UP_DOWNMIX 0x01 +#define UAC_PROCESS_DOLBY_PROLOGIC 0x02 +#define UAC_PROCESS_STEREO_EXTENDER 0x03 +#define UAC_PROCESS_REVERB 0x04 +#define UAC_PROCESS_CHORUS 0x05 +#define UAC_PROCESS_DYN_RANGE_COMP 0x06 + /* A.8 Audio Class-Specific Endpoint Descriptor Subtypes */ #define UAC_EP_GENERAL 0x01 @@ -73,6 +82,60 @@ #define UAC_GET_STAT 0xff +/* A.10 Control Selector Codes */ + +/* A.10.1 Terminal Control Selectors */ +#define UAC_TERM_COPY_PROTECT 0x01 + +/* A.10.2 Feature Unit Control Selectors */ +#define UAC_FU_MUTE 0x01 +#define UAC_FU_VOLUME 0x02 +#define UAC_FU_BASS 0x03 +#define UAC_FU_MID 0x04 +#define UAC_FU_TREBLE 0x05 +#define UAC_FU_GRAPHIC_EQUALIZER 0x06 +#define UAC_FU_AUTOMATIC_GAIN 0x07 +#define UAC_FU_DELAY 0x08 +#define UAC_FU_BASS_BOOST 0x09 +#define UAC_FU_LOUDNESS 0x0a + +#define UAC_CONTROL_BIT(CS) (1 << ((CS) - 1)) + +/* A.10.3.1 Up/Down-mix Processing Unit Controls Selectors */ +#define UAC_UD_ENABLE 0x01 +#define UAC_UD_MODE_SELECT 0x02 + +/* A.10.3.2 Dolby Prologic (tm) Processing Unit Controls Selectors */ +#define UAC_DP_ENABLE 0x01 +#define UAC_DP_MODE_SELECT 0x02 + +/* A.10.3.3 3D Stereo Extender Processing Unit Control Selectors */ +#define UAC_3D_ENABLE 0x01 +#define UAC_3D_SPACE 0x02 + +/* A.10.3.4 Reverberation Processing Unit Control Selectors */ +#define UAC_REVERB_ENABLE 0x01 +#define UAC_REVERB_LEVEL 0x02 +#define UAC_REVERB_TIME 0x03 +#define UAC_REVERB_FEEDBACK 0x04 + +/* A.10.3.5 Chorus Processing Unit Control Selectors */ +#define UAC_CHORUS_ENABLE 0x01 +#define UAC_CHORUS_LEVEL 0x02 +#define UAC_CHORUS_RATE 0x03 +#define UAC_CHORUS_DEPTH 0x04 + +/* A.10.3.6 Dynamic Range Compressor Unit Control Selectors */ +#define UAC_DCR_ENABLE 0x01 +#define UAC_DCR_RATE 0x02 +#define UAC_DCR_MAXAMPL 0x03 +#define UAC_DCR_THRESHOLD 0x04 +#define UAC_DCR_ATTACK_TIME 0x05 +#define UAC_DCR_RELEASE_TIME 0x06 + +/* A.10.4 Extension Unit Control Selectors */ +#define UAC_XU_ENABLE 0x01 + /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */ #define UAC_MS_HEADER 0x01 #define UAC_MIDI_IN_JACK 0x02 @@ -463,31 +526,6 @@ struct uac_iso_endpoint_descriptor { #define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02 #define UAC_EP_CS_ATTR_FILL_MAX 0x80 -/* A.10.2 Feature Unit Control Selectors */ - -#define UAC_FU_CONTROL_UNDEFINED 0x00 -#define UAC_MUTE_CONTROL 0x01 -#define UAC_VOLUME_CONTROL 0x02 -#define UAC_BASS_CONTROL 0x03 -#define UAC_MID_CONTROL 0x04 -#define UAC_TREBLE_CONTROL 0x05 -#define UAC_GRAPHIC_EQUALIZER_CONTROL 0x06 -#define UAC_AUTOMATIC_GAIN_CONTROL 0x07 -#define UAC_DELAY_CONTROL 0x08 -#define UAC_BASS_BOOST_CONTROL 0x09 -#define UAC_LOUDNESS_CONTROL 0x0a - -#define UAC_FU_MUTE (1 << (UAC_MUTE_CONTROL - 1)) -#define UAC_FU_VOLUME (1 << (UAC_VOLUME_CONTROL - 1)) -#define UAC_FU_BASS (1 << (UAC_BASS_CONTROL - 1)) -#define UAC_FU_MID (1 << (UAC_MID_CONTROL - 1)) -#define UAC_FU_TREBLE (1 << (UAC_TREBLE_CONTROL - 1)) -#define UAC_FU_GRAPHIC_EQ (1 << (UAC_GRAPHIC_EQUALIZER_CONTROL - 1)) -#define UAC_FU_AUTO_GAIN (1 << (UAC_AUTOMATIC_GAIN_CONTROL - 1)) -#define UAC_FU_DELAY (1 << (UAC_DELAY_CONTROL - 1)) -#define UAC_FU_BASS_BOOST (1 << (UAC_BASS_BOOST_CONTROL - 1)) -#define UAC_FU_LOUDNESS (1 << (UAC_LOUDNESS_CONTROL - 1)) - /* status word format (3.7.1.1) */ #define UAC1_STATUS_TYPE_ORIG_MASK 0x0f diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 9149a84c716f..24428198ae1b 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -78,39 +78,6 @@ enum { USB_MIXER_U16, }; -enum { - USB_PROC_UPDOWN = 1, - USB_PROC_UPDOWN_SWITCH = 1, - USB_PROC_UPDOWN_MODE_SEL = 2, - - USB_PROC_PROLOGIC = 2, - USB_PROC_PROLOGIC_SWITCH = 1, - USB_PROC_PROLOGIC_MODE_SEL = 2, - - USB_PROC_3DENH = 3, - USB_PROC_3DENH_SWITCH = 1, - USB_PROC_3DENH_SPACE = 2, - - USB_PROC_REVERB = 4, - USB_PROC_REVERB_SWITCH = 1, - USB_PROC_REVERB_LEVEL = 2, - USB_PROC_REVERB_TIME = 3, - USB_PROC_REVERB_DELAY = 4, - - USB_PROC_CHORUS = 5, - USB_PROC_CHORUS_SWITCH = 1, - USB_PROC_CHORUS_LEVEL = 2, - USB_PROC_CHORUS_RATE = 3, - USB_PROC_CHORUS_DEPTH = 4, - - USB_PROC_DCR = 6, - USB_PROC_DCR_SWITCH = 1, - USB_PROC_DCR_RATIO = 2, - USB_PROC_DCR_MAX_AMP = 3, - USB_PROC_DCR_THRESHOLD = 4, - USB_PROC_DCR_ATTACK = 5, - USB_PROC_DCR_RELEASE = 6, -}; /*E-mu 0202(0404) eXtension Unit(XU) control*/ enum { @@ -980,7 +947,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, control++; /* change from zero-based to 1-based value */ - if (control == UAC_GRAPHIC_EQUALIZER_CONTROL) { + if (control == UAC_FU_GRAPHIC_EQUALIZER) { /* FIXME: not supported yet */ return; } @@ -1036,8 +1003,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, kctl->id.name, sizeof(kctl->id.name)); switch (control) { - case UAC_MUTE_CONTROL: - case UAC_VOLUME_CONTROL: + case UAC_FU_MUTE: + case UAC_FU_VOLUME: /* determine the control name. the rule is: * - if a name id is given in descriptor, use it. * - if the connected input can be determined, then use the name @@ -1064,9 +1031,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, len = append_ctl_name(kctl, " Playback"); } } - append_ctl_name(kctl, control == UAC_MUTE_CONTROL ? + append_ctl_name(kctl, control == UAC_FU_MUTE ? " Switch" : " Volume"); - if (control == UAC_VOLUME_CONTROL) { + if (control == UAC_FU_VOLUME) { kctl->tlv.c = mixer_vol_tlv; kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ | @@ -1165,7 +1132,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void snd_printk(KERN_INFO "usbmixer: master volume quirk for PCM2702 chip\n"); /* disable non-functional volume control */ - master_bits &= ~UAC_FU_VOLUME; + master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME); break; } if (channels > 0) @@ -1410,51 +1377,51 @@ struct procunit_info { }; static struct procunit_value_info updown_proc_info[] = { - { USB_PROC_UPDOWN_SWITCH, "Switch", USB_MIXER_BOOLEAN }, - { USB_PROC_UPDOWN_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 }, + { UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN }, + { UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, { 0 } }; static struct procunit_value_info prologic_proc_info[] = { - { USB_PROC_PROLOGIC_SWITCH, "Switch", USB_MIXER_BOOLEAN }, - { USB_PROC_PROLOGIC_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 }, + { UAC_DP_ENABLE, "Switch", USB_MIXER_BOOLEAN }, + { UAC_DP_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, { 0 } }; static struct procunit_value_info threed_enh_proc_info[] = { - { USB_PROC_3DENH_SWITCH, "Switch", USB_MIXER_BOOLEAN }, - { USB_PROC_3DENH_SPACE, "Spaciousness", USB_MIXER_U8 }, + { UAC_3D_ENABLE, "Switch", USB_MIXER_BOOLEAN }, + { UAC_3D_SPACE, "Spaciousness", USB_MIXER_U8 }, { 0 } }; static struct procunit_value_info reverb_proc_info[] = { - { USB_PROC_REVERB_SWITCH, "Switch", USB_MIXER_BOOLEAN }, - { USB_PROC_REVERB_LEVEL, "Level", USB_MIXER_U8 }, - { USB_PROC_REVERB_TIME, "Time", USB_MIXER_U16 }, - { USB_PROC_REVERB_DELAY, "Delay", USB_MIXER_U8 }, + { UAC_REVERB_ENABLE, "Switch", USB_MIXER_BOOLEAN }, + { UAC_REVERB_LEVEL, "Level", USB_MIXER_U8 }, + { UAC_REVERB_TIME, "Time", USB_MIXER_U16 }, + { UAC_REVERB_FEEDBACK, "Feedback", USB_MIXER_U8 }, { 0 } }; static struct procunit_value_info chorus_proc_info[] = { - { USB_PROC_CHORUS_SWITCH, "Switch", USB_MIXER_BOOLEAN }, - { USB_PROC_CHORUS_LEVEL, "Level", USB_MIXER_U8 }, - { USB_PROC_CHORUS_RATE, "Rate", USB_MIXER_U16 }, - { USB_PROC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 }, + { UAC_CHORUS_ENABLE, "Switch", USB_MIXER_BOOLEAN }, + { UAC_CHORUS_LEVEL, "Level", USB_MIXER_U8 }, + { UAC_CHORUS_RATE, "Rate", USB_MIXER_U16 }, + { UAC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 }, { 0 } }; static struct procunit_value_info dcr_proc_info[] = { - { USB_PROC_DCR_SWITCH, "Switch", USB_MIXER_BOOLEAN }, - { USB_PROC_DCR_RATIO, "Ratio", USB_MIXER_U16 }, - { USB_PROC_DCR_MAX_AMP, "Max Amp", USB_MIXER_S16 }, - { USB_PROC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 }, - { USB_PROC_DCR_ATTACK, "Attack Time", USB_MIXER_U16 }, - { USB_PROC_DCR_RELEASE, "Release Time", USB_MIXER_U16 }, + { UAC_DCR_ENABLE, "Switch", USB_MIXER_BOOLEAN }, + { UAC_DCR_RATE, "Ratio", USB_MIXER_U16 }, + { UAC_DCR_MAXAMPL, "Max Amp", USB_MIXER_S16 }, + { UAC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 }, + { UAC_DCR_ATTACK_TIME, "Attack Time", USB_MIXER_U16 }, + { UAC_DCR_RELEASE_TIME, "Release Time", USB_MIXER_U16 }, { 0 } }; static struct procunit_info procunits[] = { - { USB_PROC_UPDOWN, "Up Down", updown_proc_info }, - { USB_PROC_PROLOGIC, "Dolby Prologic", prologic_proc_info }, - { USB_PROC_3DENH, "3D Stereo Extender", threed_enh_proc_info }, - { USB_PROC_REVERB, "Reverb", reverb_proc_info }, - { USB_PROC_CHORUS, "Chorus", chorus_proc_info }, - { USB_PROC_DCR, "DCR", dcr_proc_info }, + { UAC_PROCESS_UP_DOWNMIX, "Up Down", updown_proc_info }, + { UAC_PROCESS_DOLBY_PROLOGIC, "Dolby Prologic", prologic_proc_info }, + { UAC_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", threed_enh_proc_info }, + { UAC_PROCESS_REVERB, "Reverb", reverb_proc_info }, + { UAC_PROCESS_CHORUS, "Chorus", chorus_proc_info }, + { UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info }, { 0 }, }; /* @@ -1542,7 +1509,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw cval->channels = 1; /* get min/max values */ - if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) { + if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) { __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol); /* FIXME: hard-coded */ cval->min = 1; diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index d93fc89beba8..f1324c423835 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -85,8 +85,8 @@ static struct usbmix_name_map extigy_map[] = { /* 16: MU (w/o controls) */ { 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */ { 17, "Channel Routing", 2 }, /* PU: mode select */ - { 18, "Tone Control - Bass", UAC_BASS_CONTROL }, /* FU */ - { 18, "Tone Control - Treble", UAC_TREBLE_CONTROL }, /* FU */ + { 18, "Tone Control - Bass", UAC_FU_BASS }, /* FU */ + { 18, "Tone Control - Treble", UAC_FU_TREBLE }, /* FU */ { 18, "Master Playback" }, /* FU; others */ /* 19: OT speaker */ /* 20: OT headphone */ -- GitLab From 2e0281d15c220d0a81c45c73872aa08d2f3ae3ef Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@caiaq.de> Date: Mon, 31 May 2010 13:35:42 +0200 Subject: [PATCH 321/842] ALSA: usb-audio: add UAC2 sepecific Feature Unit controls The bits to enable them are always 0 for UAC1 devices, so no additional checks are required. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/usb/mixer.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 24428198ae1b..8be6bf2552b0 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -686,16 +686,20 @@ struct usb_feature_control_info { }; static struct usb_feature_control_info audio_feature_info[] = { - { "Mute", USB_MIXER_INV_BOOLEAN }, - { "Volume", USB_MIXER_S16 }, + { "Mute", USB_MIXER_INV_BOOLEAN }, + { "Volume", USB_MIXER_S16 }, { "Tone Control - Bass", USB_MIXER_S8 }, { "Tone Control - Mid", USB_MIXER_S8 }, { "Tone Control - Treble", USB_MIXER_S8 }, { "Graphic Equalizer", USB_MIXER_S8 }, /* FIXME: not implemeted yet */ - { "Auto Gain Control", USB_MIXER_BOOLEAN }, - { "Delay Control", USB_MIXER_U16 }, - { "Bass Boost", USB_MIXER_BOOLEAN }, - { "Loudness", USB_MIXER_BOOLEAN }, + { "Auto Gain Control", USB_MIXER_BOOLEAN }, + { "Delay Control", USB_MIXER_U16 }, + { "Bass Boost", USB_MIXER_BOOLEAN }, + { "Loudness", USB_MIXER_BOOLEAN }, + /* UAC2 specific */ + { "Input Gain Control", USB_MIXER_U16 }, + { "Input Gain Pad Control", USB_MIXER_BOOLEAN }, + { "Phase Inverter Control", USB_MIXER_BOOLEAN }, }; -- GitLab From 67e1daa0bb30eda6ec5add27c3abf4536030f5a6 Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@caiaq.de> Date: Mon, 31 May 2010 13:35:43 +0200 Subject: [PATCH 322/842] ALSA: usb-audio: clean up find_audio_control_unit() Use a struct to parse the audio units, and return usable descriptors for all types. There's no need to limit the result set, except for some kind of sanity check. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/usb/mixer.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 8be6bf2552b0..cb345360f811 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -165,22 +165,24 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid, /* * find an audio control unit with the given unit id - * this doesn't return any clock related units, so they need to be handled elsewhere */ static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit) { - unsigned char *p; + /* we just parse the header */ + struct uac_feature_unit_descriptor *hdr = NULL; - p = NULL; - while ((p = snd_usb_find_desc(state->buffer, state->buflen, p, - USB_DT_CS_INTERFACE)) != NULL) { - if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC2_EXTENSION_UNIT_V2 && p[3] == unit) - return p; + while ((hdr = snd_usb_find_desc(state->buffer, state->buflen, hdr, + USB_DT_CS_INTERFACE)) != NULL) { + if (hdr->bLength >= 4 && + hdr->bDescriptorSubtype >= UAC_INPUT_TERMINAL && + hdr->bDescriptorSubtype <= UAC2_SAMPLE_RATE_CONVERTER && + hdr->bUnitID == unit) + return hdr; } + return NULL; } - /* * copy a string with the given id */ -- GitLab From 09414207d4daab8c4990bface3a79fdba3474bec Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@caiaq.de> Date: Mon, 31 May 2010 13:35:44 +0200 Subject: [PATCH 323/842] ALSA: usb-audio: export UAC2 clock selectors as mixer controls The UAC2 clock selectors are fortunately compatible with UAC1 audio selector units, so we can simply reuse the same approach to get all the linked units. Requests to this control need a different CS value though. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/usb/mixer.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index cb345360f811..a060d005e209 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -313,8 +313,8 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v buf, sizeof(buf), 1000); if (ret < 0) { - snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", - request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); + snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", + request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); return ret; } @@ -610,6 +610,7 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm */ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) { + int err; void *p1; memset(term, 0, sizeof(*term)); @@ -630,6 +631,11 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ term->channels = d->bNrChannels; term->chconfig = le32_to_cpu(d->bmChannelConfig); term->name = d->iTerminal; + + /* call recursively to get the clock selectors */ + err = check_input_term(state, d->bCSourceID, term); + if (err < 0) + return err; } return 0; case UAC_FEATURE_UNIT: { @@ -646,7 +652,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ term->name = uac_mixer_unit_iMixer(d); return 0; } - case UAC_SELECTOR_UNIT: { + case UAC_SELECTOR_UNIT: + case UAC2_CLOCK_SELECTOR: { struct uac_selector_unit_descriptor *d = p1; /* call recursively to retrieve the channel info */ if (check_input_term(state, d->baSourceID[0], term) < 0) @@ -669,6 +676,13 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); return 0; } + case UAC2_CLOCK_SOURCE: { + struct uac_clock_source_descriptor *d = p1; + term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->id = id; + term->name = d->iClockSource; + return 0; + } default: return -ENODEV; } @@ -1610,7 +1624,7 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ struct usb_mixer_elem_info *cval = kcontrol->private_data; int val, err; - err = get_cur_ctl_value(cval, 0, &val); + err = get_cur_ctl_value(cval, cval->control << 8, &val); if (err < 0) { if (cval->mixer->ignore_ctl_error) { ucontrol->value.enumerated.item[0] = 0; @@ -1629,7 +1643,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ struct usb_mixer_elem_info *cval = kcontrol->private_data; int val, oval, err; - err = get_cur_ctl_value(cval, 0, &oval); + err = get_cur_ctl_value(cval, cval->control << 8, &oval); if (err < 0) { if (cval->mixer->ignore_ctl_error) return 0; @@ -1638,7 +1652,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ val = ucontrol->value.enumerated.item[0]; val = get_abs_value(cval, val); if (val != oval) { - set_cur_ctl_value(cval, 0, val); + set_cur_ctl_value(cval, cval->control << 8, val); return 1; } return 0; @@ -1720,6 +1734,11 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void cval->res = 1; cval->initialized = 1; + if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) + cval->control = UAC2_CX_CLOCK_SELECTOR; + else + cval->control = 0; + namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); if (! namelist) { snd_printk(KERN_ERR "cannot malloc\n"); @@ -1769,7 +1788,9 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void if (! len) strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); - if ((state->oterm.type & 0xff00) == 0x0100) + if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) + append_ctl_name(kctl, " Clock Source"); + else if ((state->oterm.type & 0xff00) == 0x0100) append_ctl_name(kctl, " Capture Source"); else append_ctl_name(kctl, " Playback Source"); @@ -1803,10 +1824,12 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) switch (p1[2]) { case UAC_INPUT_TERMINAL: + case UAC2_CLOCK_SOURCE: return 0; /* NOP */ case UAC_MIXER_UNIT: return parse_audio_mixer_unit(state, unitid, p1); case UAC_SELECTOR_UNIT: + case UAC2_CLOCK_SELECTOR: return parse_audio_selector_unit(state, unitid, p1); case UAC_FEATURE_UNIT: return parse_audio_feature_unit(state, unitid, p1); @@ -1903,6 +1926,11 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) err = parse_audio_unit(&state, desc->bSourceID); if (err < 0) return err; + + /* for UAC2, use the same approach to also add the clock selectors */ + err = parse_audio_unit(&state, desc->bCSourceID); + if (err < 0) + return err; } } -- GitLab From fc9cbe3998ea23a0658c97159c35765c98eafa37 Mon Sep 17 00:00:00 2001 From: Sascha Hauer <s.hauer@pengutronix.de> Date: Mon, 31 May 2010 10:49:54 +0200 Subject: [PATCH 324/842] ASoC: Add missing Kconfig entry for Phytec boards Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> --- sound/soc/imx/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index eba9b9d257a1..de508a553058 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -19,3 +19,12 @@ config SND_MXC_SOC_WM1133_EV1 help Enable support for audio on the i.MX31ADS with the WM1133-EV1 PMIC board with WM8835x fitted. + +config SND_SOC_PHYCORE_AC97 + tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" + depends on MACH_PCM043 || MACH_PCA100 + select SND_MXC_SOC_SSI + select SND_SOC_WM9712 + help + Say Y if you want to add support for SoC audio on Phytec phyCORE + and phyCARD boards in AC97 mode -- GitLab From 29512c95b5e2f0f245bfa4975ccae6c3449d4dd2 Mon Sep 17 00:00:00 2001 From: Sascha Hauer <s.hauer@pengutronix.de> Date: Mon, 31 May 2010 14:19:50 +0200 Subject: [PATCH 325/842] ASoC: MX31ads sound support should depend on MACH_MX31ADS_WM1133_EV1 Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> --- sound/soc/imx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index de508a553058..252defea93b5 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -13,7 +13,7 @@ config SND_MXC_SOC_SSI config SND_MXC_SOC_WM1133_EV1 tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted" - depends on SND_IMX_SOC && EXPERIMENTAL + depends on SND_IMX_SOC && MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL select SND_SOC_WM8350 select SND_MXC_SOC_SSI help -- GitLab From 293a7cfeedc2b2380a7c7274902323c3cf5f7575 Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Mon, 31 May 2010 19:53:50 +0930 Subject: [PATCH 326/842] module: fix reference to mod->percpu after freeing module. Rafael sees a sometimes crash at precpu_modfree from kernel/module.c; it only occurred with another (since-reverted) patch, but that patch simply changed timing to uncover this bug, it was otherwise unrelated. The comment about the mod being freed is self-explanatory, but neither Tejun nor I read it. This bug was introduced in 259354deaa, after it had previously been fixed in 6e2b75740b. How embarrassing. Reported-by: "Rafael J. Wysocki" <rjw@sisk.pl> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Embarrassingly-Acked-by: Tejun Heo <tj@kernel.org> Cc: Masami Hiramatsu <mhiramat@redhat.com> Tested-by: "Rafael J. Wysocki" <rjw@sisk.pl> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- kernel/module.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/module.c b/kernel/module.c index 333fbcc96978..d806e00e4450 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2014,6 +2014,7 @@ static noinline struct module *load_module(void __user *umod, long err = 0; void *ptr = NULL; /* Stops spurious gcc warning */ unsigned long symoffs, stroffs, *strmap; + void __percpu *percpu; mm_segment_t old_fs; @@ -2158,6 +2159,8 @@ static noinline struct module *load_module(void __user *umod, goto free_mod; sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC; } + /* Keep this around for failure path. */ + percpu = mod_percpu(mod); /* Determine total sizes, and put offsets in sh_entsize. For now this is done generically; there doesn't appear to be any @@ -2463,7 +2466,7 @@ static noinline struct module *load_module(void __user *umod, module_free(mod, mod->module_core); /* mod will be freed with core. Don't access it beyond this line! */ free_percpu: - percpu_modfree(mod); + free_percpu(percpu); free_mod: kfree(args); kfree(strmap); -- GitLab From 13eb04fdbeb9d21dfe4696630daefe18ef6a1a84 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker <fweisbec@gmail.com> Date: Mon, 31 May 2010 23:38:44 +0200 Subject: [PATCH 327/842] perf: Process comm events by tid When we synthetize the existing running tasks though procfs, we walk through every threads of a process, queuing one comm events per tid. But then on report time, event__process_comm() only creates and sets the comm on a per process granularity. This is the right thing for comm events that came from the kernel, as they are only created on exec. Sub-threads then inherit their comm from fork events. But that doesn't work with our synthetized comm events taken from procfs informations as the per thread granularity is done on comm events directly there. Hence we need event__process_comm() to work with the tid rather than the pid. It won't change anything for comm events coming from the kernel but this will fix the synthetized ones. Before: $ ./perf report -D | grep COMM | grep firefox 0x2c7b8 [0x18]: PERF_RECORD_COMM: firefox:5297 0x2c7d0 [0x18]: PERF_RECORD_COMM: firefox:5297 0x2c7e8 [0x18]: PERF_RECORD_COMM: firefox:5297 0x2c800 [0x18]: PERF_RECORD_COMM: firefox:5297 0x2c818 [0x18]: PERF_RECORD_COMM: firefox:5297 0x2c830 [0x18]: PERF_RECORD_COMM: firefox:5297 After: $ ./perf report -D | grep COMM | grep firefox 0x2c7b8 [0x18]: PERF_RECORD_COMM: firefox:5297 0x2c7d0 [0x18]: PERF_RECORD_COMM: firefox:5299 0x2c7e8 [0x18]: PERF_RECORD_COMM: firefox:5300 0x2c800 [0x18]: PERF_RECORD_COMM: firefox:5308 0x2c818 [0x18]: PERF_RECORD_COMM: firefox:5309 0x2c830 [0x18]: PERF_RECORD_COMM: firefox:5312 This fixes various unresolved pid on perf sched. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Stephane Eranian <eranian@google.com> --- tools/perf/util/event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 50771b5813ee..d28d80968f36 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -370,9 +370,9 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm) int event__process_comm(event_t *self, struct perf_session *session) { - struct thread *thread = perf_session__findnew(session, self->comm.pid); + struct thread *thread = perf_session__findnew(session, self->comm.tid); - dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); + dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid); if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) { dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); -- GitLab From af64865ba6825e10fe62a3105fea5cadffeb52c6 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker <fweisbec@gmail.com> Date: Tue, 1 Jun 2010 00:03:40 +0200 Subject: [PATCH 328/842] perf: Use event__process_task from perf sched perf sched uses event__process_comm(), which means it can resolve comms from: - tasks that have exec'ed (kernel comm events) - tasks that were running when perf record started the actual recording (synthetized comm events) But perf sched can't resolve the pids of tasks that were created after the recording started. To solve this, we need to inherit the comms on fork events using event__process_task(). This fixes various unresolved pids in perf sched, easily visible with: perf sched record perf bench sched messaging Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Stephane Eranian <eranian@google.com> --- tools/perf/builtin-sched.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index f67bce2a83b4..55f3b5dcc731 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1645,6 +1645,7 @@ static struct perf_event_ops event_ops = { .sample = process_sample_event, .comm = event__process_comm, .lost = event__process_lost, + .fork = event__process_task, .ordered_samples = true, }; -- GitLab From dd833d713ccc79e00176eb1b3a6c65638c44e27b Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker <fweisbec@gmail.com> Date: Tue, 1 Jun 2010 00:43:07 +0200 Subject: [PATCH 329/842] perf: Do the comm inheritance per thread in event__process_task event__process_task() doesn't propagate the comm copy on clone, but only on process fork. So we loose all the tid:comm resolution for tasks that aren't a main process thread. Progragate the per thread granularity to event__process_task for pid resolution. This fixes various unresolved pids in perf sched, especially when we trace multithread processes. The problem is quickly reproducible with the messaging benchmark using the multithread mode "-t" : perf sched record perf bench sched messaging -t Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Stephane Eranian <eranian@google.com> --- tools/perf/util/event.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index d28d80968f36..1f08f008d289 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -532,16 +532,11 @@ out_problem: int event__process_task(event_t *self, struct perf_session *session) { - struct thread *thread = perf_session__findnew(session, self->fork.pid); - struct thread *parent = perf_session__findnew(session, self->fork.ppid); + struct thread *thread = perf_session__findnew(session, self->fork.tid); + struct thread *parent = perf_session__findnew(session, self->fork.ptid); dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, self->fork.ppid, self->fork.ptid); - /* - * A thread clone will have the same PID for both parent and child. - */ - if (thread == parent) - return 0; if (self->header.type == PERF_RECORD_EXIT) return 0; -- GitLab From 2fb750e825b5347de0390315f4284f13709a9856 Mon Sep 17 00:00:00 2001 From: Borislav Petkov <bp@alien8.de> Date: Mon, 31 May 2010 23:18:18 +0200 Subject: [PATCH 330/842] perf-record: Check correct pid when forking When forking the child to be traced, we should check the correct return value from fork() and not a local variable which is otherwise unused. Signed-off-by: Borislav Petkov <bp@alien8.de> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Stephane Eranian <eranian@google.com> LKML-Reference: <20100531211818.GA30175@liondog.tnic> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> --- tools/perf/builtin-record.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 9bc89050e6f8..dc3435e18bde 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -503,7 +503,6 @@ static int __cmd_record(int argc, const char **argv) { int i, counter; struct stat st; - pid_t pid = 0; int flags; int err; unsigned long waking = 0; @@ -572,7 +571,7 @@ static int __cmd_record(int argc, const char **argv) if (forks) { child_pid = fork(); - if (pid < 0) { + if (child_pid < 0) { perror("failed to fork"); exit(-1); } -- GitLab From 7e71f8a59e1c9adbbc3b737b4b818c8aa4169d0e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Fri, 28 May 2010 11:21:54 +0200 Subject: [PATCH 331/842] drm/vmwgfx: Assume larger framebuffer max size. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index bbc7c4c30bc7..642bcd7a1500 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -765,8 +765,9 @@ int vmw_kms_init(struct vmw_private *dev_priv) dev->mode_config.funcs = &vmw_kms_funcs; dev->mode_config.min_width = 1; dev->mode_config.min_height = 1; - dev->mode_config.max_width = dev_priv->fb_max_width; - dev->mode_config.max_height = dev_priv->fb_max_height; + /* assumed largest fb size */ + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; ret = vmw_kms_init_legacy_display_system(dev_priv); -- GitLab From 6a591a96d7315fbe81acc33e20bab4956d1f02a3 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Fri, 28 May 2010 11:21:55 +0200 Subject: [PATCH 332/842] drm/vmwgfx: Fix single framebuffer detection. V2: Fix a typo. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 90891593bf6c..a348fec22137 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -130,6 +130,7 @@ static int vmw_ldu_del_active(struct vmw_private *vmw_priv, if (list_empty(&ldu->active)) return 0; + /* Must init otherwise list_empty(&ldu->active) will not work. */ list_del_init(&ldu->active); if (--(ld->num_active) == 0) { BUG_ON(!ld->fb); @@ -208,6 +209,8 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) /* ldu only supports one fb active at the time */ if (dev_priv->ldu_priv->fb && vfb && + !(dev_priv->ldu_priv->num_active == 1 && + !list_empty(&ldu->active)) && dev_priv->ldu_priv->fb != vfb) { DRM_ERROR("Multiple framebuffers not supported\n"); return -EINVAL; -- GitLab From 04e9e94dba3e564ce810cedab88e957dfd681b4a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Fri, 28 May 2010 11:21:56 +0200 Subject: [PATCH 333/842] drm/vmwgfx: Make sure to unpin old and pin new framebuffer. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index a348fec22137..e1b3cf539b4a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -150,6 +150,15 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, struct vmw_legacy_display_unit *entry; struct list_head *at; + BUG_ON(!ld->num_active && ld->fb); + if (vfb != ld->fb) { + if (ld->fb && ld->fb->unpin) + ld->fb->unpin(ld->fb); + if (vfb->pin) + vfb->pin(vfb); + ld->fb = vfb; + } + if (!list_empty(&ldu->active)) return 0; @@ -162,12 +171,8 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, } list_add(&ldu->active, at); - if (ld->num_active++ == 0) { - BUG_ON(ld->fb); - if (vfb->pin) - vfb->pin(vfb); - ld->fb = vfb; - } + + ld->num_active++; return 0; } -- GitLab From 1925d4565888eb313cc923372da6a08bbfb3a859 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Fri, 28 May 2010 11:21:57 +0200 Subject: [PATCH 334/842] drm/vmwgfx: Add kernel throttling support. Bump minor. The throttle_us member in the execbuf argument is now honored. If the member is 0, no waiting for lag will occur, which guarantees backwards compatibility with well-behaved clients. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/Makefile | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 27 +++- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 9 ++ drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 173 ++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 5 +- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 17 ++- 6 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_fence.c diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index 1a3cb6816d1c..4505e17df3f5 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -4,6 +4,6 @@ ccflags-y := -Iinclude/drm vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \ vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ - vmwgfx_overlay.o + vmwgfx_overlay.o vmwgfx_fence.o obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 356dc935ec13..9a0a82b41c3e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -41,7 +41,7 @@ #define VMWGFX_DRIVER_DATE "20100209" #define VMWGFX_DRIVER_MAJOR 1 -#define VMWGFX_DRIVER_MINOR 0 +#define VMWGFX_DRIVER_MINOR 1 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) @@ -102,6 +102,13 @@ struct vmw_surface { struct vmw_cursor_snooper snooper; }; +struct vmw_fence_queue { + struct list_head head; + struct timespec lag; + struct timespec lag_time; + spinlock_t lock; +}; + struct vmw_fifo_state { unsigned long reserved_size; __le32 *dynamic_buffer; @@ -115,6 +122,7 @@ struct vmw_fifo_state { uint32_t capabilities; struct mutex fifo_mutex; struct rw_semaphore rwsem; + struct vmw_fence_queue fence_queue; }; struct vmw_relocation { @@ -441,6 +449,23 @@ extern int vmw_fallback_wait(struct vmw_private *dev_priv, uint32_t sequence, bool interruptible, unsigned long timeout); +extern void vmw_update_sequence(struct vmw_private *dev_priv, + struct vmw_fifo_state *fifo_state); + + +/** + * Rudimentary fence objects currently used only for throttling - + * vmwgfx_fence.c + */ + +extern void vmw_fence_queue_init(struct vmw_fence_queue *queue); +extern void vmw_fence_queue_takedown(struct vmw_fence_queue *queue); +extern int vmw_fence_push(struct vmw_fence_queue *queue, + uint32_t sequence); +extern int vmw_fence_pull(struct vmw_fence_queue *queue, + uint32_t signaled_sequence); +extern int vmw_wait_lag(struct vmw_private *dev_priv, + struct vmw_fence_queue *queue, uint32_t us); /** * Kernel framebuffer - vmwgfx_fb.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index dbd36b8910cf..bdd67cf83315 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -669,6 +669,15 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, goto out_err; vmw_apply_relocations(sw_context); + + if (arg->throttle_us) { + ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.fence_queue, + arg->throttle_us); + + if (unlikely(ret != 0)) + goto out_err; + } + vmw_fifo_commit(dev_priv, arg->command_size); ret = vmw_fifo_send_fence(dev_priv, &sequence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c new file mode 100644 index 000000000000..61eacc1b5ca3 --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -0,0 +1,173 @@ +/************************************************************************** + * + * Copyright (C) 2010 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "vmwgfx_drv.h" + +struct vmw_fence { + struct list_head head; + uint32_t sequence; + struct timespec submitted; +}; + +void vmw_fence_queue_init(struct vmw_fence_queue *queue) +{ + INIT_LIST_HEAD(&queue->head); + queue->lag = ns_to_timespec(0); + getrawmonotonic(&queue->lag_time); + spin_lock_init(&queue->lock); +} + +void vmw_fence_queue_takedown(struct vmw_fence_queue *queue) +{ + struct vmw_fence *fence, *next; + + spin_lock(&queue->lock); + list_for_each_entry_safe(fence, next, &queue->head, head) { + kfree(fence); + } + spin_unlock(&queue->lock); +} + +int vmw_fence_push(struct vmw_fence_queue *queue, + uint32_t sequence) +{ + struct vmw_fence *fence = kmalloc(sizeof(*fence), GFP_KERNEL); + + if (unlikely(!fence)) + return -ENOMEM; + + fence->sequence = sequence; + getrawmonotonic(&fence->submitted); + spin_lock(&queue->lock); + list_add_tail(&fence->head, &queue->head); + spin_unlock(&queue->lock); + + return 0; +} + +int vmw_fence_pull(struct vmw_fence_queue *queue, + uint32_t signaled_sequence) +{ + struct vmw_fence *fence, *next; + struct timespec now; + bool updated = false; + + spin_lock(&queue->lock); + getrawmonotonic(&now); + + if (list_empty(&queue->head)) { + queue->lag = ns_to_timespec(0); + queue->lag_time = now; + updated = true; + goto out_unlock; + } + + list_for_each_entry_safe(fence, next, &queue->head, head) { + if (signaled_sequence - fence->sequence > (1 << 30)) + continue; + + queue->lag = timespec_sub(now, fence->submitted); + queue->lag_time = now; + updated = true; + list_del(&fence->head); + kfree(fence); + } + +out_unlock: + spin_unlock(&queue->lock); + + return (updated) ? 0 : -EBUSY; +} + +static struct timespec vmw_timespec_add(struct timespec t1, + struct timespec t2) +{ + t1.tv_sec += t2.tv_sec; + t1.tv_nsec += t2.tv_nsec; + if (t1.tv_nsec >= 1000000000L) { + t1.tv_sec += 1; + t1.tv_nsec -= 1000000000L; + } + + return t1; +} + +static struct timespec vmw_fifo_lag(struct vmw_fence_queue *queue) +{ + struct timespec now; + + spin_lock(&queue->lock); + getrawmonotonic(&now); + queue->lag = vmw_timespec_add(queue->lag, + timespec_sub(now, queue->lag_time)); + queue->lag_time = now; + spin_unlock(&queue->lock); + return queue->lag; +} + + +static bool vmw_lag_lt(struct vmw_fence_queue *queue, + uint32_t us) +{ + struct timespec lag, cond; + + cond = ns_to_timespec((s64) us * 1000); + lag = vmw_fifo_lag(queue); + return (timespec_compare(&lag, &cond) < 1); +} + +int vmw_wait_lag(struct vmw_private *dev_priv, + struct vmw_fence_queue *queue, uint32_t us) +{ + struct vmw_fence *fence; + uint32_t sequence; + int ret; + + while (!vmw_lag_lt(queue, us)) { + spin_lock(&queue->lock); + if (list_empty(&queue->head)) + sequence = atomic_read(&dev_priv->fence_seq); + else { + fence = list_first_entry(&queue->head, + struct vmw_fence, head); + sequence = fence->sequence; + } + spin_unlock(&queue->lock); + + ret = vmw_wait_fence(dev_priv, false, sequence, true, + 3*HZ); + + if (unlikely(ret != 0)) + return ret; + + (void) vmw_fence_pull(queue, sequence); + } + return 0; +} + + diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 39d43a01d846..a8e5445f94ec 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -120,7 +120,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) atomic_set(&dev_priv->fence_seq, dev_priv->last_read_sequence); iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE); - + vmw_fence_queue_init(&fifo->fence_queue); return vmw_fifo_send_fence(dev_priv, &dummy); out_err: vfree(fifo->static_buffer); @@ -159,6 +159,7 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) dev_priv->enable_state); mutex_unlock(&dev_priv->hw_mutex); + vmw_fence_queue_takedown(&fifo->fence_queue); if (likely(fifo->last_buffer != NULL)) { vfree(fifo->last_buffer); @@ -484,6 +485,8 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) fifo_state->last_buffer_add = true; vmw_fifo_commit(dev_priv, bytes); fifo_state->last_buffer_add = false; + (void) vmw_fence_push(&fifo_state->fence_queue, *sequence); + vmw_update_sequence(dev_priv, fifo_state); out_err: return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index 4d7cb5393860..e92298a6a383 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -64,22 +64,33 @@ static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t sequence) return (busy == 0); } +void vmw_update_sequence(struct vmw_private *dev_priv, + struct vmw_fifo_state *fifo_state) +{ + __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + + uint32_t sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE); + + if (dev_priv->last_read_sequence != sequence) { + dev_priv->last_read_sequence = sequence; + vmw_fence_pull(&fifo_state->fence_queue, sequence); + } +} bool vmw_fence_signaled(struct vmw_private *dev_priv, uint32_t sequence) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; struct vmw_fifo_state *fifo_state; bool ret; if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) return true; - dev_priv->last_read_sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE); + fifo_state = &dev_priv->fifo; + vmw_update_sequence(dev_priv, fifo_state); if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) return true; - fifo_state = &dev_priv->fifo; if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) && vmw_fifo_idle(dev_priv, sequence)) return true; -- GitLab From 1ae1ddd5e99bbc067414ff571ac18d4312b4c8cf Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Fri, 28 May 2010 11:21:58 +0200 Subject: [PATCH 335/842] drm/vmwgfx: Get connector status from detection function. Also make sure the ldu::active member is properly initialized. Part of fix by Michel Daenzer <daenzer@vmware.com>. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Michel Daenzer <daenzer@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index e1b3cf539b4a..fefef9012c4b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -456,13 +456,11 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) encoder = &ldu->base.encoder; connector = &ldu->base.connector; + INIT_LIST_HEAD(&ldu->active); + drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, DRM_MODE_CONNECTOR_LVDS); - /* Initial status */ - if (unit == 0) - connector->status = connector_status_connected; - else - connector->status = connector_status_disconnected; + connector->status = vmw_ldu_connector_detect(connector); drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, DRM_MODE_ENCODER_LVDS); @@ -470,8 +468,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; - INIT_LIST_HEAD(&ldu->active); - drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs); drm_connector_attach_property(connector, -- GitLab From d7e1958dbe4a7b81d4cab5fab545a068501b967e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Fri, 28 May 2010 11:21:59 +0200 Subject: [PATCH 336/842] drm/vmwgfx: Support older hardware. V2: Fix a couple of typos. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 9 ++++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 5 ++ drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 81 ++++++++++------------------ drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 18 +++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 72 +++++++++++-------------- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 70 +++++++++++++++++++----- 6 files changed, 148 insertions(+), 107 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 0c9c0811f42d..bdd87dc9e7b1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -318,6 +318,15 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) goto out_err3; } + /* Need mmio memory to check for fifo pitchlock cap. */ + if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) && + !(dev_priv->capabilities & SVGA_CAP_PITCHLOCK) && + !vmw_fifo_have_pitchlock(dev_priv)) { + ret = -ENOSYS; + DRM_ERROR("Hardware has no pitchlock\n"); + goto out_err4; + } + dev_priv->tdev = ttm_object_device_init (dev_priv->mem_global_ref.object, 12); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 9a0a82b41c3e..1341adef408d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -187,6 +187,7 @@ struct vmw_private { uint32_t vga_red_mask; uint32_t vga_blue_mask; uint32_t vga_green_mask; + uint32_t vga_pitchlock; /* * Framebuffer info. @@ -401,6 +402,7 @@ extern int vmw_fifo_send_fence(struct vmw_private *dev_priv, extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason); extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma); extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv); +extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv); /** * TTM glue - vmwgfx_ttm_glue.c @@ -491,6 +493,9 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, struct ttm_object_file *tfile, struct ttm_buffer_object *bo, SVGA3dCmdHeader *header); +void vmw_kms_write_svga(struct vmw_private *vmw_priv, + unsigned width, unsigned height, unsigned pitch, + unsigned bbp, unsigned depth); /** * Overlay control - vmwgfx_overlay.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 7421aaad8d09..fb66e62b8e2c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -132,16 +132,14 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var, return -EINVAL; } - /* without multimon its hard to resize */ - if (!(vmw_priv->capabilities & SVGA_CAP_MULTIMON) && - (var->xres != par->max_width || - var->yres != par->max_height)) { - DRM_ERROR("Tried to resize, but we don't have multimon\n"); + if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) && + (var->xoffset != 0 || var->yoffset != 0)) { + DRM_ERROR("Can not handle panning without display topology\n"); return -EINVAL; } - if (var->xres > par->max_width || - var->yres > par->max_height) { + if ((var->xoffset + var->xres) > par->max_width || + (var->yoffset + var->yres) > par->max_height) { DRM_ERROR("Requested geom can not fit in framebuffer\n"); return -EINVAL; } @@ -154,8 +152,8 @@ static int vmw_fb_set_par(struct fb_info *info) struct vmw_fb_par *par = info->par; struct vmw_private *vmw_priv = par->vmw_priv; - if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); + if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) { + vmw_write(vmw_priv, SVGA_REG_ENABLE, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); @@ -164,18 +162,11 @@ static int vmw_fb_set_par(struct fb_info *info) vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); - vmw_write(vmw_priv, SVGA_REG_WIDTH, par->max_width); - vmw_write(vmw_priv, SVGA_REG_HEIGHT, par->max_height); - vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, par->bpp); - vmw_write(vmw_priv, SVGA_REG_DEPTH, par->depth); - vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000); - vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); - vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff); + vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, + info->fix.line_length, + par->bpp, par->depth); /* TODO check if pitch and offset changes */ - - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, info->var.xoffset); @@ -183,13 +174,22 @@ static int vmw_fb_set_par(struct fb_info *info) vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); + vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); + vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); } else { - vmw_write(vmw_priv, SVGA_REG_WIDTH, info->var.xres); - vmw_write(vmw_priv, SVGA_REG_HEIGHT, info->var.yres); + vmw_write(vmw_priv, SVGA_REG_ENABLE, 0); + vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, + info->fix.line_length, + par->bpp, par->depth); + vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); - /* TODO check if pitch and offset changes */ } + /* This is really helpful since if this fails the user + * can probably not see anything on the screen. + */ + WARN_ON(vmw_read(vmw_priv, SVGA_REG_FB_OFFSET) != 0); + return 0; } @@ -416,48 +416,23 @@ int vmw_fb_init(struct vmw_private *vmw_priv) unsigned fb_bbp, fb_depth, fb_offset, fb_pitch, fb_size; int ret; + /* XXX These shouldn't be hardcoded. */ initial_width = 800; initial_height = 600; fb_bbp = 32; fb_depth = 24; - if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { - fb_width = min(vmw_priv->fb_max_width, (unsigned)2048); - fb_height = min(vmw_priv->fb_max_height, (unsigned)2048); - } else { - fb_width = min(vmw_priv->fb_max_width, initial_width); - fb_height = min(vmw_priv->fb_max_height, initial_height); - } + /* XXX As shouldn't these be as well. */ + fb_width = min(vmw_priv->fb_max_width, (unsigned)2048); + fb_height = min(vmw_priv->fb_max_height, (unsigned)2048); initial_width = min(fb_width, initial_width); initial_height = min(fb_height, initial_height); - vmw_write(vmw_priv, SVGA_REG_WIDTH, fb_width); - vmw_write(vmw_priv, SVGA_REG_HEIGHT, fb_height); - vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, fb_bbp); - vmw_write(vmw_priv, SVGA_REG_DEPTH, fb_depth); - vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000); - vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); - vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff); - - fb_size = vmw_read(vmw_priv, SVGA_REG_FB_SIZE); + fb_pitch = fb_width * fb_bbp / 8; + fb_size = fb_pitch * fb_height; fb_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET); - fb_pitch = vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE); - - DRM_DEBUG("width %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_WIDTH)); - DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_HEIGHT)); - DRM_DEBUG("width %u\n", vmw_read(vmw_priv, SVGA_REG_WIDTH)); - DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_HEIGHT)); - DRM_DEBUG("bpp %u\n", vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL)); - DRM_DEBUG("depth %u\n", vmw_read(vmw_priv, SVGA_REG_DEPTH)); - DRM_DEBUG("bpl %u\n", vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE)); - DRM_DEBUG("r mask %08x\n", vmw_read(vmw_priv, SVGA_REG_RED_MASK)); - DRM_DEBUG("g mask %08x\n", vmw_read(vmw_priv, SVGA_REG_GREEN_MASK)); - DRM_DEBUG("b mask %08x\n", vmw_read(vmw_priv, SVGA_REG_BLUE_MASK)); - DRM_DEBUG("fb_offset 0x%08x\n", fb_offset); - DRM_DEBUG("fb_pitch %u\n", fb_pitch); - DRM_DEBUG("fb_size %u kiB\n", fb_size / 1024); info = framebuffer_alloc(sizeof(*par), device); if (!info) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index a8e5445f94ec..e6a1eb7ea954 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -34,6 +34,9 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) __le32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t fifo_min, hwversion; + if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) + return false; + fifo_min = ioread32(fifo_mem + SVGA_FIFO_MIN); if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) return false; @@ -48,6 +51,21 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) return true; } +bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv) +{ + __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + uint32_t caps; + + if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) + return false; + + caps = ioread32(fifo_mem + SVGA_FIFO_CAPABILITIES); + if (caps & SVGA_FIFO_CAP_PITCHLOCK) + return true; + + return false; +} + int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 642bcd7a1500..c748207e9e1c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -596,31 +596,11 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) vmw_framebuffer_to_vfbd(&vfb->base); int ret; + vmw_overlay_pause_all(dev_priv); ret = vmw_dmabuf_to_start_of_vram(dev_priv, vfbd->buffer); - if (dev_priv->capabilities & SVGA_CAP_MULTIMON) { - vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); - vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); - vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - - vmw_write(dev_priv, SVGA_REG_ENABLE, 1); - vmw_write(dev_priv, SVGA_REG_WIDTH, vfb->base.width); - vmw_write(dev_priv, SVGA_REG_HEIGHT, vfb->base.height); - vmw_write(dev_priv, SVGA_REG_BITS_PER_PIXEL, vfb->base.bits_per_pixel); - vmw_write(dev_priv, SVGA_REG_DEPTH, vfb->base.depth); - vmw_write(dev_priv, SVGA_REG_RED_MASK, 0x00ff0000); - vmw_write(dev_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); - vmw_write(dev_priv, SVGA_REG_BLUE_MASK, 0x000000ff); - } else - WARN_ON(true); - vmw_overlay_resume_all(dev_priv); return 0; @@ -668,7 +648,7 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, /* XXX get the first 3 from the surface info */ vfbd->base.base.bits_per_pixel = 32; - vfbd->base.base.pitch = width * 32 / 4; + vfbd->base.base.pitch = width * vfbd->base.base.bits_per_pixel / 8; vfbd->base.base.depth = 24; vfbd->base.base.width = width; vfbd->base.base.height = height; @@ -827,24 +807,25 @@ out: return ret; } -int vmw_kms_save_vga(struct vmw_private *vmw_priv) +void vmw_kms_write_svga(struct vmw_private *vmw_priv, + unsigned width, unsigned height, unsigned pitch, + unsigned bbp, unsigned depth) { - /* - * setup a single multimon monitor with the size - * of 0x0, this stops the UI from resizing when we - * change the framebuffer size - */ - if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - } + if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) + vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch); + else if (vmw_fifo_have_pitchlock(vmw_priv)) + iowrite32(pitch, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); + vmw_write(vmw_priv, SVGA_REG_WIDTH, width); + vmw_write(vmw_priv, SVGA_REG_HEIGHT, height); + vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bbp); + vmw_write(vmw_priv, SVGA_REG_DEPTH, depth); + vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000); + vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00); + vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff); +} +int vmw_kms_save_vga(struct vmw_private *vmw_priv) +{ vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH); vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT); vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); @@ -853,6 +834,12 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv) vmw_priv->vga_red_mask = vmw_read(vmw_priv, SVGA_REG_RED_MASK); vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK); vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_MASK); + if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) + vmw_priv->vga_pitchlock = + vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); + else if (vmw_fifo_have_pitchlock(vmw_priv)) + vmw_priv->vga_pitchlock = + ioread32(vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); return 0; } @@ -867,9 +854,12 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv) vmw_write(vmw_priv, SVGA_REG_RED_MASK, vmw_priv->vga_red_mask); vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, vmw_priv->vga_green_mask); vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, vmw_priv->vga_blue_mask); - - /* TODO check for multimon */ - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0); + if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) + vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, + vmw_priv->vga_pitchlock); + else if (vmw_fifo_have_pitchlock(vmw_priv)) + iowrite32(vmw_priv->vga_pitchlock, + vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index fefef9012c4b..8fde9bf8be41 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -38,6 +38,7 @@ struct vmw_legacy_display { struct list_head active; unsigned num_active; + unsigned last_num_active; struct vmw_framebuffer *fb; }; @@ -88,12 +89,37 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) { struct vmw_legacy_display *lds = dev_priv->ldu_priv; struct vmw_legacy_display_unit *entry; - struct drm_crtc *crtc; + struct drm_framebuffer *fb = NULL; + struct drm_crtc *crtc = NULL; int i = 0; - /* to stop the screen from changing size on resize */ - vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0); - for (i = 0; i < lds->num_active; i++) { + /* If there is no display topology the host just assumes + * that the guest will set the same layout as the host. + */ + if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) { + int w = 0, h = 0; + list_for_each_entry(entry, &lds->active, active) { + crtc = &entry->base.crtc; + w = max(w, crtc->x + crtc->mode.hdisplay); + h = max(h, crtc->y + crtc->mode.vdisplay); + i++; + } + + if (crtc == NULL) + return 0; + fb = entry->base.crtc.fb; + + vmw_write(dev_priv, SVGA_REG_ENABLE, 0); + vmw_kms_write_svga(dev_priv, w, h, fb->pitch, + fb->bits_per_pixel, fb->depth); + vmw_write(dev_priv, SVGA_REG_ENABLE, 1); + + return 0; + } + + vmw_write(dev_priv, SVGA_REG_ENABLE, 0); + + for (i = 0; i < lds->last_num_active; i++) { vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0); @@ -103,8 +129,14 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); } - /* Now set the mode */ - vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, lds->num_active); + if (!list_empty(&lds->active)) { + entry = list_entry(lds->active.next, typeof(*entry), active); + fb = entry->base.crtc.fb; + + vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitch, + fb->bits_per_pixel, fb->depth); + } + i = 0; list_for_each_entry(entry, &lds->active, active) { crtc = &entry->base.crtc; @@ -120,6 +152,14 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) i++; } + /* Make sure we always show something. */ + vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, i ? i : 1); + vmw_write(dev_priv, SVGA_REG_ENABLE, 1); + + BUG_ON(i != lds->num_active); + + lds->last_num_active = lds->num_active; + return 0; } @@ -491,18 +531,22 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) INIT_LIST_HEAD(&dev_priv->ldu_priv->active); dev_priv->ldu_priv->num_active = 0; + dev_priv->ldu_priv->last_num_active = 0; dev_priv->ldu_priv->fb = NULL; drm_mode_create_dirty_info_property(dev_priv->dev); vmw_ldu_init(dev_priv, 0); - vmw_ldu_init(dev_priv, 1); - vmw_ldu_init(dev_priv, 2); - vmw_ldu_init(dev_priv, 3); - vmw_ldu_init(dev_priv, 4); - vmw_ldu_init(dev_priv, 5); - vmw_ldu_init(dev_priv, 6); - vmw_ldu_init(dev_priv, 7); + /* for old hardware without multimon only enable one display */ + if (dev_priv->capabilities & SVGA_CAP_MULTIMON) { + vmw_ldu_init(dev_priv, 1); + vmw_ldu_init(dev_priv, 2); + vmw_ldu_init(dev_priv, 3); + vmw_ldu_init(dev_priv, 4); + vmw_ldu_init(dev_priv, 5); + vmw_ldu_init(dev_priv, 6); + vmw_ldu_init(dev_priv, 7); + } return 0; } -- GitLab From 22ee861c816689b2566290356d54e4a01c9b2e74 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Fri, 28 May 2010 11:22:00 +0200 Subject: [PATCH 337/842] drm/vmwgfx: Reserve first part of VRAM for framebuffer. The host may be touching this part of VRAM at modesetting, even if we never use it ourselves, since we blit screen updates from 3D surfaces. Make sure no DMA buffers are placed in this part of VRAM. V2: Fix an error check in vmw_surface_dmabuf_pin(). Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 41 +++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index c748207e9e1c..250282fee9c8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -30,6 +30,8 @@ /* Might need a hrtimer here? */ #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) +static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb); +static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb); void vmw_display_unit_cleanup(struct vmw_display_unit *du) { @@ -326,6 +328,7 @@ int vmw_framebuffer_create_handle(struct drm_framebuffer *fb, struct vmw_framebuffer_surface { struct vmw_framebuffer base; struct vmw_surface *surface; + struct vmw_dma_buffer *buffer; struct delayed_work d_work; struct mutex work_lock; bool present_fs; @@ -500,8 +503,8 @@ int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, vfbs->base.base.depth = 24; vfbs->base.base.width = width; vfbs->base.base.height = height; - vfbs->base.pin = NULL; - vfbs->base.unpin = NULL; + vfbs->base.pin = &vmw_surface_dmabuf_pin; + vfbs->base.unpin = &vmw_surface_dmabuf_unpin; vfbs->surface = surface; mutex_init(&vfbs->work_lock); INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback); @@ -589,6 +592,40 @@ static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { .create_handle = vmw_framebuffer_create_handle, }; +static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb) +{ + struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); + struct vmw_framebuffer_surface *vfbs = + vmw_framebuffer_to_vfbs(&vfb->base); + unsigned long size = vfbs->base.base.pitch * vfbs->base.base.height; + int ret; + + vfbs->buffer = kzalloc(sizeof(*vfbs->buffer), GFP_KERNEL); + if (unlikely(vfbs->buffer == NULL)) + return -ENOMEM; + + vmw_overlay_pause_all(dev_priv); + ret = vmw_dmabuf_init(dev_priv, vfbs->buffer, size, + &vmw_vram_ne_placement, + false, &vmw_dmabuf_bo_free); + vmw_overlay_resume_all(dev_priv); + + return ret; +} + +static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb) +{ + struct ttm_buffer_object *bo; + struct vmw_framebuffer_surface *vfbs = + vmw_framebuffer_to_vfbs(&vfb->base); + + bo = &vfbs->buffer->base; + ttm_bo_unref(&bo); + vfbs->buffer = NULL; + + return 0; +} + static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) { struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); -- GitLab From bbfad33663fe8de1cce84ac776664292c46fe7ae Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Fri, 28 May 2010 11:22:01 +0200 Subject: [PATCH 338/842] drm/vmwgfx: Remove duplicate member from struct vmw_legacy_display_unit. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 8fde9bf8be41..b35d7b0fd48d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -50,8 +50,6 @@ struct vmw_legacy_display_unit { struct vmw_display_unit base; struct list_head active; - - unsigned unit; }; static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu) @@ -204,7 +202,7 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, at = &ld->active; list_for_each_entry(entry, &ld->active, active) { - if (entry->unit > ldu->unit) + if (entry->base.unit > ldu->base.unit) break; at = &entry->active; @@ -491,7 +489,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) if (!ldu) return -ENOMEM; - ldu->unit = unit; + ldu->base.unit = unit; crtc = &ldu->base.crtc; encoder = &ldu->base.encoder; connector = &ldu->base.connector; -- GitLab From d451f62a7c567654f74018be9ab8da8089660d3b Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Fri, 28 May 2010 11:22:02 +0200 Subject: [PATCH 339/842] drm/vmwgfx: Don't use SVGA_REG_ENABLE in modesetting code. We should not use SVGA_REG_ENABLE anywhere but in the fifo setup code, since it controls whether the device is active. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 ---- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 5 ----- 2 files changed, 9 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index fb66e62b8e2c..06f431442e92 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -153,7 +153,6 @@ static int vmw_fb_set_par(struct fb_info *info) struct vmw_private *vmw_priv = par->vmw_priv; if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) { - vmw_write(vmw_priv, SVGA_REG_ENABLE, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); @@ -175,13 +174,10 @@ static int vmw_fb_set_par(struct fb_info *info) vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); - vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); } else { - vmw_write(vmw_priv, SVGA_REG_ENABLE, 0); vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, info->fix.line_length, par->bpp, par->depth); - vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index b35d7b0fd48d..d98b1b1a8705 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -107,16 +107,12 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) return 0; fb = entry->base.crtc.fb; - vmw_write(dev_priv, SVGA_REG_ENABLE, 0); vmw_kms_write_svga(dev_priv, w, h, fb->pitch, fb->bits_per_pixel, fb->depth); - vmw_write(dev_priv, SVGA_REG_ENABLE, 1); return 0; } - vmw_write(dev_priv, SVGA_REG_ENABLE, 0); - for (i = 0; i < lds->last_num_active; i++) { vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); @@ -152,7 +148,6 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) /* Make sure we always show something. */ vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, i ? i : 1); - vmw_write(dev_priv, SVGA_REG_ENABLE, 1); BUG_ON(i != lds->num_active); -- GitLab From 259600d593181b8a3b1d7fe99d93233b1b113fd0 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Fri, 28 May 2010 11:22:03 +0200 Subject: [PATCH 340/842] drm/vmwgfx: Some modesetting cleanups and fixes. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index d98b1b1a8705..f7094dde18f9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -113,16 +113,6 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) return 0; } - for (i = 0; i < lds->last_num_active; i++) { - vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); - vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); - vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0); - vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - } - if (!list_empty(&lds->active)) { entry = list_entry(lds->active.next, typeof(*entry), active); fb = entry->base.crtc.fb; @@ -131,6 +121,10 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) fb->bits_per_pixel, fb->depth); } + /* Make sure we always show something. */ + vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, + lds->num_active ? lds->num_active : 1); + i = 0; list_for_each_entry(entry, &lds->active, active) { crtc = &entry->base.crtc; @@ -146,9 +140,6 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) i++; } - /* Make sure we always show something. */ - vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, i ? i : 1); - BUG_ON(i != lds->num_active); lds->last_num_active = lds->num_active; -- GitLab From 792778e8e058471e1909b78d7c5e6ab94962ff8e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Fri, 28 May 2010 11:22:04 +0200 Subject: [PATCH 341/842] drm/vmwgfx: Unpause overlay on update. The unpause codepath uses vmw_overlay_update() so we must unset the paused status. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index ad566c85b075..df2036ed18d5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -358,6 +358,8 @@ static int vmw_overlay_update_stream(struct vmw_private *dev_priv, if (stream->buf != buf) stream->buf = vmw_dmabuf_reference(buf); stream->saved = *arg; + /* stream is no longer stopped/paused */ + stream->paused = false; return 0; } -- GitLab From 316ab13ae2ad603fd5e3a909524e68d98db1b1b6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Fri, 28 May 2010 11:22:05 +0200 Subject: [PATCH 342/842] drm/vmwgfx: Print warnings in kernel log about bo pinning that fails. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 ++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 06f431442e92..181f47222580 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -630,6 +630,10 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv, goto err_unlock; ret = ttm_bo_validate(bo, &ne_placement, false, false, false); + + /* Could probably bug on */ + WARN_ON(bo->offset != 0); + ttm_bo_unreserve(bo); err_unlock: ttm_write_unlock(&vmw_priv->active_master->lock); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 250282fee9c8..b78dcf001858 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -640,6 +640,8 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) vmw_overlay_resume_all(dev_priv); + WARN_ON(ret != 0); + return 0; } -- GitLab From 1ca14e75caae504fdf957cf0c1c4f3aafc886a60 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Fri, 28 May 2010 11:22:06 +0200 Subject: [PATCH 343/842] drm/vmwgfx: Remove some leftover debug messages. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index bdd87dc9e7b1..7597323d5a5a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -408,8 +408,6 @@ static int vmw_driver_unload(struct drm_device *dev) { struct vmw_private *dev_priv = vmw_priv(dev); - DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n"); - unregister_pm_notifier(&dev_priv->pm_nb); vmw_fb_close(dev_priv); @@ -555,7 +553,6 @@ static int vmw_master_create(struct drm_device *dev, { struct vmw_master *vmaster; - DRM_INFO("Master create.\n"); vmaster = kzalloc(sizeof(*vmaster), GFP_KERNEL); if (unlikely(vmaster == NULL)) return -ENOMEM; @@ -572,7 +569,6 @@ static void vmw_master_destroy(struct drm_device *dev, { struct vmw_master *vmaster = vmw_master(master); - DRM_INFO("Master destroy.\n"); master->driver_priv = NULL; kfree(vmaster); } @@ -588,8 +584,6 @@ static int vmw_master_set(struct drm_device *dev, struct vmw_master *vmaster = vmw_master(file_priv->master); int ret = 0; - DRM_INFO("Master set.\n"); - if (active) { BUG_ON(active != &dev_priv->fbdev_master); ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile); @@ -631,8 +625,6 @@ static void vmw_master_drop(struct drm_device *dev, struct vmw_master *vmaster = vmw_master(file_priv->master); int ret; - DRM_INFO("Master drop.\n"); - /** * Make sure the master doesn't disappear while we have * it locked. -- GitLab From e8613c0e29d0018a80652e6ae58660c8a75ac74b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Wed, 26 May 2010 16:21:03 +0200 Subject: [PATCH 344/842] drm/ttm: Fix cached TTM page allocation. This patch fixes a regression introduced with the pool page allocator in the event that there are no highmem pages (for example x86_64), in which case cached page allocation would fail. Tested with the vmwgfx driver on a 64-bit vm. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/ttm/ttm_page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 0d9a42c2394f..b6d152360675 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -671,7 +671,7 @@ int ttm_get_pages(struct list_head *pages, int flags, if (flags & TTM_PAGE_FLAG_DMA32) gfp_flags |= GFP_DMA32; else - gfp_flags |= __GFP_HIGHMEM; + gfp_flags |= GFP_HIGHUSER; for (r = 0; r < count; ++r) { p = alloc_page(gfp_flags); -- GitLab From 4abe4389790d5f02569fbacdf035536ba84c7d44 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Wed, 26 May 2010 16:21:04 +0200 Subject: [PATCH 345/842] drm/ttm: Fix ttm_page_alloc.c Fix a number of typos misspellings and checkpatch.pl warnings. Replace "[ttm] " with TTM_PFX Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/ttm/ttm_page_alloc.c | 62 ++++++++++++++++------------ 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index b6d152360675..ef910694bd63 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -77,7 +77,7 @@ struct ttm_page_pool { /** * Limits for the pool. They are handled without locks because only place where * they may change is in sysfs store. They won't have immediate effect anyway - * so forcing serialiazation to access them is pointless. + * so forcing serialization to access them is pointless. */ struct ttm_pool_opts { @@ -165,16 +165,18 @@ static ssize_t ttm_pool_store(struct kobject *kobj, m->options.small = val; else if (attr == &ttm_page_pool_alloc_size) { if (val > NUM_PAGES_TO_ALLOC*8) { - printk(KERN_ERR "[ttm] Setting allocation size to %lu " - "is not allowed. Recomended size is " - "%lu\n", - NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 7), - NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); + printk(KERN_ERR TTM_PFX + "Setting allocation size to %lu " + "is not allowed. Recommended size is " + "%lu\n", + NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 7), + NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); return size; } else if (val > NUM_PAGES_TO_ALLOC) { - printk(KERN_WARNING "[ttm] Setting allocation size to " - "larger than %lu is not recomended.\n", - NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); + printk(KERN_WARNING TTM_PFX + "Setting allocation size to " + "larger than %lu is not recommended.\n", + NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10)); } m->options.alloc_size = val; } @@ -277,7 +279,7 @@ static void ttm_pages_put(struct page *pages[], unsigned npages) { unsigned i; if (set_pages_array_wb(pages, npages)) - printk(KERN_ERR "[ttm] Failed to set %d pages to wb!\n", + printk(KERN_ERR TTM_PFX "Failed to set %d pages to wb!\n", npages); for (i = 0; i < npages; ++i) __free_page(pages[i]); @@ -313,7 +315,8 @@ static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free) pages_to_free = kmalloc(npages_to_free * sizeof(struct page *), GFP_KERNEL); if (!pages_to_free) { - printk(KERN_ERR "Failed to allocate memory for pool free operation.\n"); + printk(KERN_ERR TTM_PFX + "Failed to allocate memory for pool free operation.\n"); return 0; } @@ -390,7 +393,7 @@ static int ttm_pool_get_num_unused_pages(void) } /** - * Calback for mm to request pool to reduce number of page held. + * Callback for mm to request pool to reduce number of page held. */ static int ttm_pool_mm_shrink(int shrink_pages, gfp_t gfp_mask) { @@ -433,14 +436,16 @@ static int ttm_set_pages_caching(struct page **pages, case tt_uncached: r = set_pages_array_uc(pages, cpages); if (r) - printk(KERN_ERR "[ttm] Failed to set %d pages to uc!\n", - cpages); + printk(KERN_ERR TTM_PFX + "Failed to set %d pages to uc!\n", + cpages); break; case tt_wc: r = set_pages_array_wc(pages, cpages); if (r) - printk(KERN_ERR "[ttm] Failed to set %d pages to wc!\n", - cpages); + printk(KERN_ERR TTM_PFX + "Failed to set %d pages to wc!\n", + cpages); break; default: break; @@ -458,7 +463,7 @@ static void ttm_handle_caching_state_failure(struct list_head *pages, struct page **failed_pages, unsigned cpages) { unsigned i; - /* Failed pages has to be reed */ + /* Failed pages have to be freed */ for (i = 0; i < cpages; ++i) { list_del(&failed_pages[i]->lru); __free_page(failed_pages[i]); @@ -485,7 +490,8 @@ static int ttm_alloc_new_pages(struct list_head *pages, int gfp_flags, caching_array = kmalloc(max_cpages*sizeof(struct page *), GFP_KERNEL); if (!caching_array) { - printk(KERN_ERR "[ttm] unable to allocate table for new pages."); + printk(KERN_ERR TTM_PFX + "Unable to allocate table for new pages."); return -ENOMEM; } @@ -493,12 +499,13 @@ static int ttm_alloc_new_pages(struct list_head *pages, int gfp_flags, p = alloc_page(gfp_flags); if (!p) { - printk(KERN_ERR "[ttm] unable to get page %u\n", i); + printk(KERN_ERR TTM_PFX "Unable to get page %u.\n", i); /* store already allocated pages in the pool after * setting the caching state */ if (cpages) { - r = ttm_set_pages_caching(caching_array, cstate, cpages); + r = ttm_set_pages_caching(caching_array, + cstate, cpages); if (r) ttm_handle_caching_state_failure(pages, ttm_flags, cstate, @@ -590,7 +597,8 @@ static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool, ++pool->nrefills; pool->npages += alloc_size; } else { - printk(KERN_ERR "[ttm] Failed to fill pool (%p).", pool); + printk(KERN_ERR TTM_PFX + "Failed to fill pool (%p).", pool); /* If we have any pages left put them to the pool. */ list_for_each_entry(p, &pool->list, lru) { ++cpages; @@ -677,7 +685,8 @@ int ttm_get_pages(struct list_head *pages, int flags, p = alloc_page(gfp_flags); if (!p) { - printk(KERN_ERR "[ttm] unable to allocate page."); + printk(KERN_ERR TTM_PFX + "Unable to allocate page."); return -ENOMEM; } @@ -709,8 +718,9 @@ int ttm_get_pages(struct list_head *pages, int flags, if (r) { /* If there is any pages in the list put them back to * the pool. */ - printk(KERN_ERR "[ttm] Failed to allocate extra pages " - "for large request."); + printk(KERN_ERR TTM_PFX + "Failed to allocate extra pages " + "for large request."); ttm_put_pages(pages, 0, flags, cstate); return r; } @@ -778,7 +788,7 @@ int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages) if (atomic_add_return(1, &_manager.page_alloc_inited) > 1) return 0; - printk(KERN_INFO "[ttm] Initializing pool allocator.\n"); + printk(KERN_INFO TTM_PFX "Initializing pool allocator.\n"); ttm_page_pool_init_locked(&_manager.wc_pool, GFP_HIGHUSER, "wc"); @@ -813,7 +823,7 @@ void ttm_page_alloc_fini() if (atomic_sub_return(1, &_manager.page_alloc_inited) > 0) return; - printk(KERN_INFO "[ttm] Finilizing pool allocator.\n"); + printk(KERN_INFO TTM_PFX "Finalizing pool allocator.\n"); ttm_pool_mm_shrink_fini(&_manager); for (i = 0; i < NUM_POOLS; ++i) -- GitLab From 8b281db596744a15b2abbfdbf655796c64e172ca Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Mon, 31 May 2010 09:04:03 +1000 Subject: [PATCH 346/842] drm/nv50: cast IGP memory location to u64 before shifting Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_mem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 775a7017af64..c1fd42b0dad1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -540,7 +540,8 @@ nouveau_mem_detect(struct drm_device *dev) dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA); dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK; if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) - dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12; + dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10); + dev_priv->vram_sys_base <<= 12; } NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); -- GitLab From afeb3e11147adb357603b071d6d7d1f30ea7f19d Mon Sep 17 00:00:00 2001 From: Dave Airlie <airlied@redhat.com> Date: Wed, 7 Apr 2010 13:55:09 +1000 Subject: [PATCH 347/842] drm/nouveau: attempt to get bios from ACPI v3 Some of the laptops with the switchable graphics, seem to not post the secondary GPU at all, and we can't find a copy of the BIOS anywhere except in the ACPI rom retrieval. This adds support for ACPI ROM retrieval to nouveau. Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 59 +++++++++++++++++++++++++- drivers/gpu/drm/nouveau/nouveau_bios.c | 20 +++++++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 5 +++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index e13f6af0037a..b3f146a811ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -35,6 +35,7 @@ static struct nouveau_dsm_priv { bool dsm_detected; acpi_handle dhandle; acpi_handle dsm_handle; + acpi_handle rom_handle; } nouveau_dsm_priv; static const char nouveau_dsm_muid[] = { @@ -151,12 +152,13 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); if (!dhandle) return false; + status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle); if (ACPI_FAILURE(status)) { return false; } - ret= nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED, + ret = nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED, NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); if (ret < 0) return false; @@ -173,6 +175,7 @@ static bool nouveau_dsm_detect(void) struct pci_dev *pdev = NULL; int has_dsm = 0; int vga_count = 0; + while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { vga_count++; @@ -204,3 +207,57 @@ void nouveau_unregister_dsm_handler(void) { vga_switcheroo_unregister_handler(); } + +/* retrieve the ROM in 4k blocks */ +static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios, + int offset, int len) +{ + acpi_status status; + union acpi_object rom_arg_elements[2], *obj; + struct acpi_object_list rom_arg; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; + + rom_arg.count = 2; + rom_arg.pointer = &rom_arg_elements[0]; + + rom_arg_elements[0].type = ACPI_TYPE_INTEGER; + rom_arg_elements[0].integer.value = offset; + + rom_arg_elements[1].type = ACPI_TYPE_INTEGER; + rom_arg_elements[1].integer.value = len; + + status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_INFO "failed to evaluate ROM got %s\n", acpi_format_exception(status)); + return -ENODEV; + } + obj = (union acpi_object *)buffer.pointer; + memcpy(bios+offset, obj->buffer.pointer, len); + kfree(buffer.pointer); + return len; +} + +bool nouveau_acpi_rom_supported(struct pci_dev *pdev) +{ + acpi_status status; + acpi_handle dhandle, rom_handle; + + if (!nouveau_dsm_priv.dsm_detected) + return false; + + dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); + if (!dhandle) + return false; + + status = acpi_get_handle(dhandle, "_ROM", &rom_handle); + if (ACPI_FAILURE(status)) + return false; + + nouveau_dsm_priv.rom_handle = rom_handle; + return true; +} + +int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) +{ + return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e7e69ccce5c9..745ff3788e9d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -178,6 +178,25 @@ out: pci_disable_rom(dev->pdev); } +static void load_vbios_acpi(struct drm_device *dev, uint8_t *data) +{ + int i; + int ret; + int size = 64 * 1024; + + if (!nouveau_acpi_rom_supported(dev->pdev)) + return; + + for (i = 0; i < (size / ROM_BIOS_PAGE); i++) { + ret = nouveau_acpi_get_bios_chunk(data, + (i * ROM_BIOS_PAGE), + ROM_BIOS_PAGE); + if (ret <= 0) + break; + } + return; +} + struct methods { const char desc[8]; void (*loadbios)(struct drm_device *, uint8_t *); @@ -191,6 +210,7 @@ static struct methods nv04_methods[] = { }; static struct methods nv50_methods[] = { + { "ACPI", load_vbios_acpi, true }, { "PRAMIN", load_vbios_pramin, true }, { "PROM", load_vbios_prom, false }, { "PCIROM", load_vbios_pci, true }, diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 5b134438effe..c69719106489 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -851,12 +851,17 @@ extern int nouveau_dma_init(struct nouveau_channel *); extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size); /* nouveau_acpi.c */ +#define ROM_BIOS_PAGE 4096 #if defined(CONFIG_ACPI) void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); +int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); +bool nouveau_acpi_rom_supported(struct pci_dev *pdev); #else static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} +static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } +static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } #endif /* nouveau_backlight.c */ -- GitLab From fc5ea29d72bde1bec230538becf396caad8621b8 Mon Sep 17 00:00:00 2001 From: Dave Airlie <airlied@redhat.com> Date: Mon, 31 May 2010 17:10:52 +1000 Subject: [PATCH 348/842] drm/nouveau: fixup confusion over which handle the DSM is hanging off. This fixes the DSM setup correctly since vga switcheroo. Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index b3f146a811ca..d4bcca8a5133 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -34,7 +34,6 @@ static struct nouveau_dsm_priv { bool dsm_detected; acpi_handle dhandle; - acpi_handle dsm_handle; acpi_handle rom_handle; } nouveau_dsm_priv; @@ -108,9 +107,9 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id) { if (id == VGA_SWITCHEROO_IGD) - return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_STAMINA); + return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA); else - return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_SPEED); + return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_SPEED); } static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id, @@ -119,7 +118,7 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id, if (id == VGA_SWITCHEROO_IGD) return 0; - return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dsm_handle, state); + return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state); } static int nouveau_dsm_init(void) @@ -158,13 +157,12 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) return false; } - ret = nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED, - NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); + ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED, + NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); if (ret < 0) return false; nouveau_dsm_priv.dhandle = dhandle; - nouveau_dsm_priv.dsm_handle = nvidia_handle; return true; } @@ -183,7 +181,7 @@ static bool nouveau_dsm_detect(void) } if (vga_count == 2 && has_dsm) { - acpi_get_name(nouveau_dsm_priv.dsm_handle, ACPI_FULL_PATHNAME, &buffer); + acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", acpi_method_name); nouveau_dsm_priv.dsm_detected = true; -- GitLab From fbf81762e385d3d45acad057b654d56972acf58c Mon Sep 17 00:00:00 2001 From: Dave Airlie <airlied@redhat.com> Date: Tue, 1 Jun 2010 09:09:06 +1000 Subject: [PATCH 349/842] drm/kms: disable/enable poll around switcheroo on/off Because we aren't in a suspend state the poll will still run when we have switcherooed a card off. Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/drm_crtc_helper.c | 28 +++++++++++++++++++------ drivers/gpu/drm/i915/i915_dma.c | 4 +++- drivers/gpu/drm/nouveau/nouveau_state.c | 3 +++ drivers/gpu/drm/radeon/radeon_device.c | 2 ++ include/drm/drm_crtc_helper.h | 3 +++ 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 764401951041..9b2a54117c91 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -860,19 +860,24 @@ static void output_poll_execute(struct slow_work *work) } } -void drm_kms_helper_poll_init(struct drm_device *dev) +void drm_kms_helper_poll_disable(struct drm_device *dev) +{ + if (!dev->mode_config.poll_enabled) + return; + delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); +} +EXPORT_SYMBOL(drm_kms_helper_poll_disable); + +void drm_kms_helper_poll_enable(struct drm_device *dev) { - struct drm_connector *connector; bool poll = false; + struct drm_connector *connector; int ret; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->polled) poll = true; } - slow_work_register_user(THIS_MODULE); - delayed_slow_work_init(&dev->mode_config.output_poll_slow_work, - &output_poll_ops); if (poll) { ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD); @@ -880,11 +885,22 @@ void drm_kms_helper_poll_init(struct drm_device *dev) DRM_ERROR("delayed enqueue failed %d\n", ret); } } +EXPORT_SYMBOL(drm_kms_helper_poll_enable); + +void drm_kms_helper_poll_init(struct drm_device *dev) +{ + slow_work_register_user(THIS_MODULE); + delayed_slow_work_init(&dev->mode_config.output_poll_slow_work, + &output_poll_ops); + dev->mode_config.poll_enabled = true; + + drm_kms_helper_poll_enable(dev); +} EXPORT_SYMBOL(drm_kms_helper_poll_init); void drm_kms_helper_poll_fini(struct drm_device *dev) { - delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); + drm_kms_helper_poll_disable(dev); slow_work_unregister_user(THIS_MODULE); } EXPORT_SYMBOL(drm_kms_helper_poll_fini); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2a6b5de5ae5d..cc6e56a18edd 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1399,12 +1399,14 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_ struct drm_device *dev = pci_get_drvdata(pdev); pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; if (state == VGA_SWITCHEROO_ON) { - printk(KERN_INFO "i915: switched off\n"); + printk(KERN_INFO "i915: switched on\n"); /* i915 resume handler doesn't set to D0 */ pci_set_power_state(dev->pdev, PCI_D0); i915_resume(dev); + drm_kms_helper_poll_enable(dev); } else { printk(KERN_ERR "i915: switched off\n"); + drm_kms_helper_poll_disable(dev); i915_suspend(dev, pmm); } } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index e632339c323e..5c468a4fef9a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -376,12 +376,15 @@ out_err: static void nouveau_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) { + struct drm_device *dev = pci_get_drvdata(pdev); pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; if (state == VGA_SWITCHEROO_ON) { printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); nouveau_pci_resume(pdev); + drm_kms_helper_poll_enable(dev); } else { printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); + drm_kms_helper_poll_disable(dev); nouveau_pci_suspend(pdev, pmm); } } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index fdc3fdf78acb..db338522191f 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -546,8 +546,10 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero /* don't suspend or resume card normally */ rdev->powered_down = false; radeon_resume_kms(dev); + drm_kms_helper_poll_enable(dev); } else { printk(KERN_INFO "radeon: switched off\n"); + drm_kms_helper_poll_disable(dev); radeon_suspend_kms(dev, pmm); /* don't suspend or resume card normally */ rdev->powered_down = true; diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index dc5873c21e45..1121f7799c6f 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -130,4 +130,7 @@ extern int drm_helper_resume_force_mode(struct drm_device *dev); extern void drm_kms_helper_poll_init(struct drm_device *dev); extern void drm_kms_helper_poll_fini(struct drm_device *dev); extern void drm_helper_hpd_irq_event(struct drm_device *dev); + +extern void drm_kms_helper_poll_disable(struct drm_device *dev); +extern void drm_kms_helper_poll_enable(struct drm_device *dev); #endif -- GitLab From cb5fcbd540b438a5d311bd15dc910841d01ed140 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Fri, 28 May 2010 19:01:35 -0400 Subject: [PATCH 350/842] drm/radeon/kms/evergreen: add initial CS parser Advanced validation is not implemented yet. The mesa code that uses this will be released soon. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/Makefile | 7 +- drivers/gpu/drm/radeon/evergreen_cs.c | 1356 +++++++++++++++++++++ drivers/gpu/drm/radeon/evergreen_reg.h | 3 + drivers/gpu/drm/radeon/evergreend.h | 464 +++++++ drivers/gpu/drm/radeon/radeon_asic.c | 4 +- drivers/gpu/drm/radeon/radeon_asic.h | 1 + drivers/gpu/drm/radeon/reg_srcs/evergreen | 611 ++++++++++ 7 files changed, 2443 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/radeon/evergreen_cs.c create mode 100644 drivers/gpu/drm/radeon/reg_srcs/evergreen diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 3c91312dea9a..84b1f2729d43 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -33,6 +33,9 @@ $(obj)/rs600_reg_safe.h: $(src)/reg_srcs/rs600 $(obj)/mkregtable $(obj)/r600_reg_safe.h: $(src)/reg_srcs/r600 $(obj)/mkregtable $(call if_changed,mkregtable) +$(obj)/evergreen_reg_safe.h: $(src)/reg_srcs/evergreen $(obj)/mkregtable + $(call if_changed,mkregtable) + $(obj)/r100.o: $(obj)/r100_reg_safe.h $(obj)/rn50_reg_safe.h $(obj)/r200.o: $(obj)/r200_reg_safe.h @@ -47,6 +50,8 @@ $(obj)/rs600.o: $(obj)/rs600_reg_safe.h $(obj)/r600_cs.o: $(obj)/r600_reg_safe.h +$(obj)/evergreen_cs.o: $(obj)/evergreen_reg_safe.h + radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o \ radeon_irq.o r300_cmdbuf.o r600_cp.o # add KMS driver @@ -60,7 +65,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \ - evergreen.o + evergreen.o evergreen_cs.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c new file mode 100644 index 000000000000..64516b950891 --- /dev/null +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -0,0 +1,1356 @@ +/* + * Copyright 2010 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon.h" +#include "evergreend.h" +#include "evergreen_reg_safe.h" + +static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc); + +struct evergreen_cs_track { + u32 group_size; + u32 nbanks; + u32 npipes; + /* value we track */ + u32 nsamples; + u32 cb_color_base_last[12]; + struct radeon_bo *cb_color_bo[12]; + u32 cb_color_bo_offset[12]; + struct radeon_bo *cb_color_fmask_bo[8]; + struct radeon_bo *cb_color_cmask_bo[8]; + u32 cb_color_info[12]; + u32 cb_color_view[12]; + u32 cb_color_pitch_idx[12]; + u32 cb_color_slice_idx[12]; + u32 cb_color_dim_idx[12]; + u32 cb_color_dim[12]; + u32 cb_color_pitch[12]; + u32 cb_color_slice[12]; + u32 cb_color_cmask_slice[8]; + u32 cb_color_fmask_slice[8]; + u32 cb_target_mask; + u32 cb_shader_mask; + u32 vgt_strmout_config; + u32 vgt_strmout_buffer_config; + u32 db_depth_control; + u32 db_depth_view; + u32 db_depth_size; + u32 db_depth_size_idx; + u32 db_z_info; + u32 db_z_idx; + u32 db_z_read_offset; + u32 db_z_write_offset; + struct radeon_bo *db_z_read_bo; + struct radeon_bo *db_z_write_bo; + u32 db_s_info; + u32 db_s_idx; + u32 db_s_read_offset; + u32 db_s_write_offset; + struct radeon_bo *db_s_read_bo; + struct radeon_bo *db_s_write_bo; +}; + +static void evergreen_cs_track_init(struct evergreen_cs_track *track) +{ + int i; + + for (i = 0; i < 8; i++) { + track->cb_color_fmask_bo[i] = NULL; + track->cb_color_cmask_bo[i] = NULL; + track->cb_color_cmask_slice[i] = 0; + track->cb_color_fmask_slice[i] = 0; + } + + for (i = 0; i < 12; i++) { + track->cb_color_base_last[i] = 0; + track->cb_color_bo[i] = NULL; + track->cb_color_bo_offset[i] = 0xFFFFFFFF; + track->cb_color_info[i] = 0; + track->cb_color_view[i] = 0; + track->cb_color_pitch_idx[i] = 0; + track->cb_color_slice_idx[i] = 0; + track->cb_color_dim[i] = 0; + track->cb_color_pitch[i] = 0; + track->cb_color_slice[i] = 0; + track->cb_color_dim[i] = 0; + } + track->cb_target_mask = 0xFFFFFFFF; + track->cb_shader_mask = 0xFFFFFFFF; + + track->db_depth_view = 0xFFFFC000; + track->db_depth_size = 0xFFFFFFFF; + track->db_depth_size_idx = 0; + track->db_depth_control = 0xFFFFFFFF; + track->db_z_info = 0xFFFFFFFF; + track->db_z_idx = 0xFFFFFFFF; + track->db_z_read_offset = 0xFFFFFFFF; + track->db_z_write_offset = 0xFFFFFFFF; + track->db_z_read_bo = NULL; + track->db_z_write_bo = NULL; + track->db_s_info = 0xFFFFFFFF; + track->db_s_idx = 0xFFFFFFFF; + track->db_s_read_offset = 0xFFFFFFFF; + track->db_s_write_offset = 0xFFFFFFFF; + track->db_s_read_bo = NULL; + track->db_s_write_bo = NULL; +} + +static inline int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, int i) +{ + /* XXX fill in */ + return 0; +} + +static int evergreen_cs_track_check(struct radeon_cs_parser *p) +{ + struct evergreen_cs_track *track = p->track; + + /* we don't support stream out buffer yet */ + if (track->vgt_strmout_config || track->vgt_strmout_buffer_config) { + dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n"); + return -EINVAL; + } + + /* XXX fill in */ + return 0; +} + +/** + * evergreen_cs_packet_parse() - parse cp packet and point ib index to next packet + * @parser: parser structure holding parsing context. + * @pkt: where to store packet informations + * + * Assume that chunk_ib_index is properly set. Will return -EINVAL + * if packet is bigger than remaining ib size. or if packets is unknown. + **/ +int evergreen_cs_packet_parse(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx) +{ + struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; + uint32_t header; + + if (idx >= ib_chunk->length_dw) { + DRM_ERROR("Can not parse packet at %d after CS end %d !\n", + idx, ib_chunk->length_dw); + return -EINVAL; + } + header = radeon_get_ib_value(p, idx); + pkt->idx = idx; + pkt->type = CP_PACKET_GET_TYPE(header); + pkt->count = CP_PACKET_GET_COUNT(header); + pkt->one_reg_wr = 0; + switch (pkt->type) { + case PACKET_TYPE0: + pkt->reg = CP_PACKET0_GET_REG(header); + break; + case PACKET_TYPE3: + pkt->opcode = CP_PACKET3_GET_OPCODE(header); + break; + case PACKET_TYPE2: + pkt->count = -1; + break; + default: + DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx); + return -EINVAL; + } + if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) { + DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n", + pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); + return -EINVAL; + } + return 0; +} + +/** + * evergreen_cs_packet_next_reloc() - parse next packet which should be reloc packet3 + * @parser: parser structure holding parsing context. + * @data: pointer to relocation data + * @offset_start: starting offset + * @offset_mask: offset mask (to align start offset on) + * @reloc: reloc informations + * + * Check next packet is relocation packet3, do bo validation and compute + * GPU offset using the provided start. + **/ +static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc) +{ + struct radeon_cs_chunk *relocs_chunk; + struct radeon_cs_packet p3reloc; + unsigned idx; + int r; + + if (p->chunk_relocs_idx == -1) { + DRM_ERROR("No relocation chunk !\n"); + return -EINVAL; + } + *cs_reloc = NULL; + relocs_chunk = &p->chunks[p->chunk_relocs_idx]; + r = evergreen_cs_packet_parse(p, &p3reloc, p->idx); + if (r) { + return r; + } + p->idx += p3reloc.count + 2; + if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { + DRM_ERROR("No packet3 for relocation for packet at %d.\n", + p3reloc.idx); + return -EINVAL; + } + idx = radeon_get_ib_value(p, p3reloc.idx + 1); + if (idx >= relocs_chunk->length_dw) { + DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", + idx, relocs_chunk->length_dw); + return -EINVAL; + } + /* FIXME: we assume reloc size is 4 dwords */ + *cs_reloc = p->relocs_ptr[(idx / 4)]; + return 0; +} + +/** + * evergreen_cs_packet_next_is_pkt3_nop() - test if next packet is packet3 nop for reloc + * @parser: parser structure holding parsing context. + * + * Check next packet is relocation packet3, do bo validation and compute + * GPU offset using the provided start. + **/ +static inline int evergreen_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p) +{ + struct radeon_cs_packet p3reloc; + int r; + + r = evergreen_cs_packet_parse(p, &p3reloc, p->idx); + if (r) { + return 0; + } + if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { + return 0; + } + return 1; +} + +/** + * evergreen_cs_packet_next_vline() - parse userspace VLINE packet + * @parser: parser structure holding parsing context. + * + * Userspace sends a special sequence for VLINE waits. + * PACKET0 - VLINE_START_END + value + * PACKET3 - WAIT_REG_MEM poll vline status reg + * RELOC (P3) - crtc_id in reloc. + * + * This function parses this and relocates the VLINE START END + * and WAIT_REG_MEM packets to the correct crtc. + * It also detects a switched off crtc and nulls out the + * wait in that case. + */ +static int evergreen_cs_packet_parse_vline(struct radeon_cs_parser *p) +{ + struct drm_mode_object *obj; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + struct radeon_cs_packet p3reloc, wait_reg_mem; + int crtc_id; + int r; + uint32_t header, h_idx, reg, wait_reg_mem_info; + volatile uint32_t *ib; + + ib = p->ib->ptr; + + /* parse the WAIT_REG_MEM */ + r = evergreen_cs_packet_parse(p, &wait_reg_mem, p->idx); + if (r) + return r; + + /* check its a WAIT_REG_MEM */ + if (wait_reg_mem.type != PACKET_TYPE3 || + wait_reg_mem.opcode != PACKET3_WAIT_REG_MEM) { + DRM_ERROR("vline wait missing WAIT_REG_MEM segment\n"); + r = -EINVAL; + return r; + } + + wait_reg_mem_info = radeon_get_ib_value(p, wait_reg_mem.idx + 1); + /* bit 4 is reg (0) or mem (1) */ + if (wait_reg_mem_info & 0x10) { + DRM_ERROR("vline WAIT_REG_MEM waiting on MEM rather than REG\n"); + r = -EINVAL; + return r; + } + /* waiting for value to be equal */ + if ((wait_reg_mem_info & 0x7) != 0x3) { + DRM_ERROR("vline WAIT_REG_MEM function not equal\n"); + r = -EINVAL; + return r; + } + if ((radeon_get_ib_value(p, wait_reg_mem.idx + 2) << 2) != EVERGREEN_VLINE_STATUS) { + DRM_ERROR("vline WAIT_REG_MEM bad reg\n"); + r = -EINVAL; + return r; + } + + if (radeon_get_ib_value(p, wait_reg_mem.idx + 5) != EVERGREEN_VLINE_STAT) { + DRM_ERROR("vline WAIT_REG_MEM bad bit mask\n"); + r = -EINVAL; + return r; + } + + /* jump over the NOP */ + r = evergreen_cs_packet_parse(p, &p3reloc, p->idx + wait_reg_mem.count + 2); + if (r) + return r; + + h_idx = p->idx - 2; + p->idx += wait_reg_mem.count + 2; + p->idx += p3reloc.count + 2; + + header = radeon_get_ib_value(p, h_idx); + crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1); + reg = CP_PACKET0_GET_REG(header); + mutex_lock(&p->rdev->ddev->mode_config.mutex); + obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC); + if (!obj) { + DRM_ERROR("cannot find crtc %d\n", crtc_id); + r = -EINVAL; + goto out; + } + crtc = obj_to_crtc(obj); + radeon_crtc = to_radeon_crtc(crtc); + crtc_id = radeon_crtc->crtc_id; + + if (!crtc->enabled) { + /* if the CRTC isn't enabled - we need to nop out the WAIT_REG_MEM */ + ib[h_idx + 2] = PACKET2(0); + ib[h_idx + 3] = PACKET2(0); + ib[h_idx + 4] = PACKET2(0); + ib[h_idx + 5] = PACKET2(0); + ib[h_idx + 6] = PACKET2(0); + ib[h_idx + 7] = PACKET2(0); + ib[h_idx + 8] = PACKET2(0); + } else { + switch (reg) { + case EVERGREEN_VLINE_START_END: + header &= ~R600_CP_PACKET0_REG_MASK; + header |= (EVERGREEN_VLINE_START_END + radeon_crtc->crtc_offset) >> 2; + ib[h_idx] = header; + ib[h_idx + 4] = (EVERGREEN_VLINE_STATUS + radeon_crtc->crtc_offset) >> 2; + break; + default: + DRM_ERROR("unknown crtc reloc\n"); + r = -EINVAL; + goto out; + } + } +out: + mutex_unlock(&p->rdev->ddev->mode_config.mutex); + return r; +} + +static int evergreen_packet0_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + unsigned idx, unsigned reg) +{ + int r; + + switch (reg) { + case EVERGREEN_VLINE_START_END: + r = evergreen_cs_packet_parse_vline(p); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + return r; + } + break; + default: + printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", + reg, idx); + return -EINVAL; + } + return 0; +} + +static int evergreen_cs_parse_packet0(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt) +{ + unsigned reg, i; + unsigned idx; + int r; + + idx = pkt->idx + 1; + reg = pkt->reg; + for (i = 0; i <= pkt->count; i++, idx++, reg += 4) { + r = evergreen_packet0_check(p, pkt, idx, reg); + if (r) { + return r; + } + } + return 0; +} + +/** + * evergreen_cs_check_reg() - check if register is authorized or not + * @parser: parser structure holding parsing context + * @reg: register we are testing + * @idx: index into the cs buffer + * + * This function will test against evergreen_reg_safe_bm and return 0 + * if register is safe. If register is not flag as safe this function + * will test it against a list of register needind special handling. + */ +static inline int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) +{ + struct evergreen_cs_track *track = (struct evergreen_cs_track *)p->track; + struct radeon_cs_reloc *reloc; + u32 last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); + u32 m, i, tmp, *ib; + int r; + + i = (reg >> 7); + if (i > last_reg) { + dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); + return -EINVAL; + } + m = 1 << ((reg >> 2) & 31); + if (!(evergreen_reg_safe_bm[i] & m)) + return 0; + ib = p->ib->ptr; + switch (reg) { + /* force following reg to 0 in an attemp to disable out buffer + * which will need us to better understand how it works to perform + * security check on it (Jerome) + */ + case SQ_ESGS_RING_SIZE: + case SQ_GSVS_RING_SIZE: + case SQ_ESTMP_RING_SIZE: + case SQ_GSTMP_RING_SIZE: + case SQ_HSTMP_RING_SIZE: + case SQ_LSTMP_RING_SIZE: + case SQ_PSTMP_RING_SIZE: + case SQ_VSTMP_RING_SIZE: + case SQ_ESGS_RING_ITEMSIZE: + case SQ_ESTMP_RING_ITEMSIZE: + case SQ_GSTMP_RING_ITEMSIZE: + case SQ_GSVS_RING_ITEMSIZE: + case SQ_GS_VERT_ITEMSIZE: + case SQ_GS_VERT_ITEMSIZE_1: + case SQ_GS_VERT_ITEMSIZE_2: + case SQ_GS_VERT_ITEMSIZE_3: + case SQ_GSVS_RING_OFFSET_1: + case SQ_GSVS_RING_OFFSET_2: + case SQ_GSVS_RING_OFFSET_3: + case SQ_HSTMP_RING_ITEMSIZE: + case SQ_LSTMP_RING_ITEMSIZE: + case SQ_PSTMP_RING_ITEMSIZE: + case SQ_VSTMP_RING_ITEMSIZE: + case VGT_TF_RING_SIZE: + /* get value to populate the IB don't remove */ + tmp =radeon_get_ib_value(p, idx); + ib[idx] = 0; + break; + case DB_DEPTH_CONTROL: + track->db_depth_control = radeon_get_ib_value(p, idx); + break; + case DB_Z_INFO: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_z_info = radeon_get_ib_value(p, idx); + ib[idx] &= ~Z_ARRAY_MODE(0xf); + track->db_z_info &= ~Z_ARRAY_MODE(0xf); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx] |= Z_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + track->db_z_info |= Z_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + } else { + ib[idx] |= Z_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + track->db_z_info |= Z_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + } + break; + case DB_STENCIL_INFO: + track->db_s_info = radeon_get_ib_value(p, idx); + break; + case DB_DEPTH_VIEW: + track->db_depth_view = radeon_get_ib_value(p, idx); + break; + case DB_DEPTH_SIZE: + track->db_depth_size = radeon_get_ib_value(p, idx); + track->db_depth_size_idx = idx; + break; + case DB_Z_READ_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_z_read_offset = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->db_z_read_bo = reloc->robj; + break; + case DB_Z_WRITE_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_z_write_offset = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->db_z_write_bo = reloc->robj; + break; + case DB_STENCIL_READ_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_s_read_offset = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->db_s_read_bo = reloc->robj; + break; + case DB_STENCIL_WRITE_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_s_write_offset = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->db_s_write_bo = reloc->robj; + break; + case VGT_STRMOUT_CONFIG: + track->vgt_strmout_config = radeon_get_ib_value(p, idx); + break; + case VGT_STRMOUT_BUFFER_CONFIG: + track->vgt_strmout_buffer_config = radeon_get_ib_value(p, idx); + break; + case CB_TARGET_MASK: + track->cb_target_mask = radeon_get_ib_value(p, idx); + break; + case CB_SHADER_MASK: + track->cb_shader_mask = radeon_get_ib_value(p, idx); + break; + case PA_SC_AA_CONFIG: + tmp = radeon_get_ib_value(p, idx) & MSAA_NUM_SAMPLES_MASK; + track->nsamples = 1 << tmp; + break; + case CB_COLOR0_VIEW: + case CB_COLOR1_VIEW: + case CB_COLOR2_VIEW: + case CB_COLOR3_VIEW: + case CB_COLOR4_VIEW: + case CB_COLOR5_VIEW: + case CB_COLOR6_VIEW: + case CB_COLOR7_VIEW: + tmp = (reg - CB_COLOR0_VIEW) / 0x3c; + track->cb_color_view[tmp] = radeon_get_ib_value(p, idx); + break; + case CB_COLOR8_VIEW: + case CB_COLOR9_VIEW: + case CB_COLOR10_VIEW: + case CB_COLOR11_VIEW: + tmp = ((reg - CB_COLOR8_VIEW) / 0x1c) + 8; + track->cb_color_view[tmp] = radeon_get_ib_value(p, idx); + break; + case CB_COLOR0_INFO: + case CB_COLOR1_INFO: + case CB_COLOR2_INFO: + case CB_COLOR3_INFO: + case CB_COLOR4_INFO: + case CB_COLOR5_INFO: + case CB_COLOR6_INFO: + case CB_COLOR7_INFO: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + tmp = (reg - CB_COLOR0_INFO) / 0x3c; + track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { + ib[idx] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + } + break; + case CB_COLOR8_INFO: + case CB_COLOR9_INFO: + case CB_COLOR10_INFO: + case CB_COLOR11_INFO: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + tmp = ((reg - CB_COLOR8_INFO) / 0x1c) + 8; + track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { + ib[idx] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + } + break; + case CB_COLOR0_PITCH: + case CB_COLOR1_PITCH: + case CB_COLOR2_PITCH: + case CB_COLOR3_PITCH: + case CB_COLOR4_PITCH: + case CB_COLOR5_PITCH: + case CB_COLOR6_PITCH: + case CB_COLOR7_PITCH: + tmp = (reg - CB_COLOR0_PITCH) / 0x3c; + track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_pitch_idx[tmp] = idx; + break; + case CB_COLOR8_PITCH: + case CB_COLOR9_PITCH: + case CB_COLOR10_PITCH: + case CB_COLOR11_PITCH: + tmp = ((reg - CB_COLOR8_PITCH) / 0x1c) + 8; + track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_pitch_idx[tmp] = idx; + break; + case CB_COLOR0_SLICE: + case CB_COLOR1_SLICE: + case CB_COLOR2_SLICE: + case CB_COLOR3_SLICE: + case CB_COLOR4_SLICE: + case CB_COLOR5_SLICE: + case CB_COLOR6_SLICE: + case CB_COLOR7_SLICE: + tmp = (reg - CB_COLOR0_SLICE) / 0x3c; + track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_slice_idx[tmp] = idx; + break; + case CB_COLOR8_SLICE: + case CB_COLOR9_SLICE: + case CB_COLOR10_SLICE: + case CB_COLOR11_SLICE: + tmp = ((reg - CB_COLOR8_SLICE) / 0x1c) + 8; + track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_slice_idx[tmp] = idx; + break; + case CB_COLOR0_ATTRIB: + case CB_COLOR1_ATTRIB: + case CB_COLOR2_ATTRIB: + case CB_COLOR3_ATTRIB: + case CB_COLOR4_ATTRIB: + case CB_COLOR5_ATTRIB: + case CB_COLOR6_ATTRIB: + case CB_COLOR7_ATTRIB: + case CB_COLOR8_ATTRIB: + case CB_COLOR9_ATTRIB: + case CB_COLOR10_ATTRIB: + case CB_COLOR11_ATTRIB: + break; + case CB_COLOR0_DIM: + case CB_COLOR1_DIM: + case CB_COLOR2_DIM: + case CB_COLOR3_DIM: + case CB_COLOR4_DIM: + case CB_COLOR5_DIM: + case CB_COLOR6_DIM: + case CB_COLOR7_DIM: + tmp = (reg - CB_COLOR0_DIM) / 0x3c; + track->cb_color_dim[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_dim_idx[tmp] = idx; + break; + case CB_COLOR8_DIM: + case CB_COLOR9_DIM: + case CB_COLOR10_DIM: + case CB_COLOR11_DIM: + tmp = ((reg - CB_COLOR8_DIM) / 0x1c) + 8; + track->cb_color_dim[tmp] = radeon_get_ib_value(p, idx); + track->cb_color_dim_idx[tmp] = idx; + break; + case CB_COLOR0_FMASK: + case CB_COLOR1_FMASK: + case CB_COLOR2_FMASK: + case CB_COLOR3_FMASK: + case CB_COLOR4_FMASK: + case CB_COLOR5_FMASK: + case CB_COLOR6_FMASK: + case CB_COLOR7_FMASK: + tmp = (reg - CB_COLOR0_FMASK) / 0x3c; + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); + return -EINVAL; + } + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->cb_color_fmask_bo[tmp] = reloc->robj; + break; + case CB_COLOR0_CMASK: + case CB_COLOR1_CMASK: + case CB_COLOR2_CMASK: + case CB_COLOR3_CMASK: + case CB_COLOR4_CMASK: + case CB_COLOR5_CMASK: + case CB_COLOR6_CMASK: + case CB_COLOR7_CMASK: + tmp = (reg - CB_COLOR0_CMASK) / 0x3c; + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); + return -EINVAL; + } + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->cb_color_cmask_bo[tmp] = reloc->robj; + break; + case CB_COLOR0_FMASK_SLICE: + case CB_COLOR1_FMASK_SLICE: + case CB_COLOR2_FMASK_SLICE: + case CB_COLOR3_FMASK_SLICE: + case CB_COLOR4_FMASK_SLICE: + case CB_COLOR5_FMASK_SLICE: + case CB_COLOR6_FMASK_SLICE: + case CB_COLOR7_FMASK_SLICE: + tmp = (reg - CB_COLOR0_FMASK_SLICE) / 0x3c; + track->cb_color_fmask_slice[tmp] = radeon_get_ib_value(p, idx); + break; + case CB_COLOR0_CMASK_SLICE: + case CB_COLOR1_CMASK_SLICE: + case CB_COLOR2_CMASK_SLICE: + case CB_COLOR3_CMASK_SLICE: + case CB_COLOR4_CMASK_SLICE: + case CB_COLOR5_CMASK_SLICE: + case CB_COLOR6_CMASK_SLICE: + case CB_COLOR7_CMASK_SLICE: + tmp = (reg - CB_COLOR0_CMASK_SLICE) / 0x3c; + track->cb_color_cmask_slice[tmp] = radeon_get_ib_value(p, idx); + break; + case CB_COLOR0_BASE: + case CB_COLOR1_BASE: + case CB_COLOR2_BASE: + case CB_COLOR3_BASE: + case CB_COLOR4_BASE: + case CB_COLOR5_BASE: + case CB_COLOR6_BASE: + case CB_COLOR7_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + tmp = (reg - CB_COLOR0_BASE) / 0x3c; + track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->cb_color_base_last[tmp] = ib[idx]; + track->cb_color_bo[tmp] = reloc->robj; + break; + case CB_COLOR8_BASE: + case CB_COLOR9_BASE: + case CB_COLOR10_BASE: + case CB_COLOR11_BASE: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + tmp = ((reg - CB_COLOR8_BASE) / 0x1c) + 8; + track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx); + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + track->cb_color_base_last[tmp] = ib[idx]; + track->cb_color_bo[tmp] = reloc->robj; + break; + case CB_IMMED0_BASE: + case CB_IMMED1_BASE: + case CB_IMMED2_BASE: + case CB_IMMED3_BASE: + case CB_IMMED4_BASE: + case CB_IMMED5_BASE: + case CB_IMMED6_BASE: + case CB_IMMED7_BASE: + case CB_IMMED8_BASE: + case CB_IMMED9_BASE: + case CB_IMMED10_BASE: + case CB_IMMED11_BASE: + case DB_HTILE_DATA_BASE: + case SQ_PGM_START_FS: + case SQ_PGM_START_ES: + case SQ_PGM_START_VS: + case SQ_PGM_START_GS: + case SQ_PGM_START_PS: + case SQ_PGM_START_HS: + case SQ_PGM_START_LS: + case GDS_ADDR_BASE: + case SQ_CONST_MEM_BASE: + case SQ_ALU_CONST_CACHE_GS_0: + case SQ_ALU_CONST_CACHE_GS_1: + case SQ_ALU_CONST_CACHE_GS_2: + case SQ_ALU_CONST_CACHE_GS_3: + case SQ_ALU_CONST_CACHE_GS_4: + case SQ_ALU_CONST_CACHE_GS_5: + case SQ_ALU_CONST_CACHE_GS_6: + case SQ_ALU_CONST_CACHE_GS_7: + case SQ_ALU_CONST_CACHE_GS_8: + case SQ_ALU_CONST_CACHE_GS_9: + case SQ_ALU_CONST_CACHE_GS_10: + case SQ_ALU_CONST_CACHE_GS_11: + case SQ_ALU_CONST_CACHE_GS_12: + case SQ_ALU_CONST_CACHE_GS_13: + case SQ_ALU_CONST_CACHE_GS_14: + case SQ_ALU_CONST_CACHE_GS_15: + case SQ_ALU_CONST_CACHE_PS_0: + case SQ_ALU_CONST_CACHE_PS_1: + case SQ_ALU_CONST_CACHE_PS_2: + case SQ_ALU_CONST_CACHE_PS_3: + case SQ_ALU_CONST_CACHE_PS_4: + case SQ_ALU_CONST_CACHE_PS_5: + case SQ_ALU_CONST_CACHE_PS_6: + case SQ_ALU_CONST_CACHE_PS_7: + case SQ_ALU_CONST_CACHE_PS_8: + case SQ_ALU_CONST_CACHE_PS_9: + case SQ_ALU_CONST_CACHE_PS_10: + case SQ_ALU_CONST_CACHE_PS_11: + case SQ_ALU_CONST_CACHE_PS_12: + case SQ_ALU_CONST_CACHE_PS_13: + case SQ_ALU_CONST_CACHE_PS_14: + case SQ_ALU_CONST_CACHE_PS_15: + case SQ_ALU_CONST_CACHE_VS_0: + case SQ_ALU_CONST_CACHE_VS_1: + case SQ_ALU_CONST_CACHE_VS_2: + case SQ_ALU_CONST_CACHE_VS_3: + case SQ_ALU_CONST_CACHE_VS_4: + case SQ_ALU_CONST_CACHE_VS_5: + case SQ_ALU_CONST_CACHE_VS_6: + case SQ_ALU_CONST_CACHE_VS_7: + case SQ_ALU_CONST_CACHE_VS_8: + case SQ_ALU_CONST_CACHE_VS_9: + case SQ_ALU_CONST_CACHE_VS_10: + case SQ_ALU_CONST_CACHE_VS_11: + case SQ_ALU_CONST_CACHE_VS_12: + case SQ_ALU_CONST_CACHE_VS_13: + case SQ_ALU_CONST_CACHE_VS_14: + case SQ_ALU_CONST_CACHE_VS_15: + case SQ_ALU_CONST_CACHE_HS_0: + case SQ_ALU_CONST_CACHE_HS_1: + case SQ_ALU_CONST_CACHE_HS_2: + case SQ_ALU_CONST_CACHE_HS_3: + case SQ_ALU_CONST_CACHE_HS_4: + case SQ_ALU_CONST_CACHE_HS_5: + case SQ_ALU_CONST_CACHE_HS_6: + case SQ_ALU_CONST_CACHE_HS_7: + case SQ_ALU_CONST_CACHE_HS_8: + case SQ_ALU_CONST_CACHE_HS_9: + case SQ_ALU_CONST_CACHE_HS_10: + case SQ_ALU_CONST_CACHE_HS_11: + case SQ_ALU_CONST_CACHE_HS_12: + case SQ_ALU_CONST_CACHE_HS_13: + case SQ_ALU_CONST_CACHE_HS_14: + case SQ_ALU_CONST_CACHE_HS_15: + case SQ_ALU_CONST_CACHE_LS_0: + case SQ_ALU_CONST_CACHE_LS_1: + case SQ_ALU_CONST_CACHE_LS_2: + case SQ_ALU_CONST_CACHE_LS_3: + case SQ_ALU_CONST_CACHE_LS_4: + case SQ_ALU_CONST_CACHE_LS_5: + case SQ_ALU_CONST_CACHE_LS_6: + case SQ_ALU_CONST_CACHE_LS_7: + case SQ_ALU_CONST_CACHE_LS_8: + case SQ_ALU_CONST_CACHE_LS_9: + case SQ_ALU_CONST_CACHE_LS_10: + case SQ_ALU_CONST_CACHE_LS_11: + case SQ_ALU_CONST_CACHE_LS_12: + case SQ_ALU_CONST_CACHE_LS_13: + case SQ_ALU_CONST_CACHE_LS_14: + case SQ_ALU_CONST_CACHE_LS_15: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + break; + default: + dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); + return -EINVAL; + } + return 0; +} + +/** + * evergreen_check_texture_resource() - check if register is authorized or not + * @p: parser structure holding parsing context + * @idx: index into the cs buffer + * @texture: texture's bo structure + * @mipmap: mipmap's bo structure + * + * This function will check that the resource has valid field and that + * the texture and mipmap bo object are big enough to cover this resource. + */ +static inline int evergreen_check_texture_resource(struct radeon_cs_parser *p, u32 idx, + struct radeon_bo *texture, + struct radeon_bo *mipmap) +{ + /* XXX fill in */ + return 0; +} + +static int evergreen_packet3_check(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt) +{ + struct radeon_cs_reloc *reloc; + struct evergreen_cs_track *track; + volatile u32 *ib; + unsigned idx; + unsigned i; + unsigned start_reg, end_reg, reg; + int r; + u32 idx_value; + + track = (struct evergreen_cs_track *)p->track; + ib = p->ib->ptr; + idx = pkt->idx + 1; + idx_value = radeon_get_ib_value(p, idx); + + switch (pkt->opcode) { + case PACKET3_CONTEXT_CONTROL: + if (pkt->count != 1) { + DRM_ERROR("bad CONTEXT_CONTROL\n"); + return -EINVAL; + } + break; + case PACKET3_INDEX_TYPE: + case PACKET3_NUM_INSTANCES: + case PACKET3_CLEAR_STATE: + if (pkt->count) { + DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES/CLEAR_STATE\n"); + return -EINVAL; + } + break; + case PACKET3_INDEX_BASE: + if (pkt->count != 1) { + DRM_ERROR("bad INDEX_BASE\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad INDEX_BASE\n"); + return -EINVAL; + } + ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_DRAW_INDEX: + if (pkt->count != 3) { + DRM_ERROR("bad DRAW_INDEX\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad DRAW_INDEX\n"); + return -EINVAL; + } + ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_DRAW_INDEX_2: + if (pkt->count != 4) { + DRM_ERROR("bad DRAW_INDEX_2\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad DRAW_INDEX_2\n"); + return -EINVAL; + } + ib[idx+1] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_DRAW_INDEX_AUTO: + if (pkt->count != 1) { + DRM_ERROR("bad DRAW_INDEX_AUTO\n"); + return -EINVAL; + } + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx); + return r; + } + break; + case PACKET3_DRAW_INDEX_MULTI_AUTO: + if (pkt->count != 2) { + DRM_ERROR("bad DRAW_INDEX_MULTI_AUTO\n"); + return -EINVAL; + } + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx); + return r; + } + break; + case PACKET3_DRAW_INDEX_IMMD: + if (pkt->count < 2) { + DRM_ERROR("bad DRAW_INDEX_IMMD\n"); + return -EINVAL; + } + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_DRAW_INDEX_OFFSET: + if (pkt->count != 2) { + DRM_ERROR("bad DRAW_INDEX_OFFSET\n"); + return -EINVAL; + } + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_DRAW_INDEX_OFFSET_2: + if (pkt->count != 3) { + DRM_ERROR("bad DRAW_INDEX_OFFSET_2\n"); + return -EINVAL; + } + r = evergreen_cs_track_check(p); + if (r) { + dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__); + return r; + } + break; + case PACKET3_WAIT_REG_MEM: + if (pkt->count != 5) { + DRM_ERROR("bad WAIT_REG_MEM\n"); + return -EINVAL; + } + /* bit 4 is reg (0) or mem (1) */ + if (idx_value & 0x10) { + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad WAIT_REG_MEM\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + } + break; + case PACKET3_SURFACE_SYNC: + if (pkt->count != 3) { + DRM_ERROR("bad SURFACE_SYNC\n"); + return -EINVAL; + } + /* 0xffffffff/0x0 is flush all cache flag */ + if (radeon_get_ib_value(p, idx + 1) != 0xffffffff || + radeon_get_ib_value(p, idx + 2) != 0) { + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SURFACE_SYNC\n"); + return -EINVAL; + } + ib[idx+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + } + break; + case PACKET3_EVENT_WRITE: + if (pkt->count != 2 && pkt->count != 0) { + DRM_ERROR("bad EVENT_WRITE\n"); + return -EINVAL; + } + if (pkt->count) { + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad EVENT_WRITE\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + } + break; + case PACKET3_EVENT_WRITE_EOP: + if (pkt->count != 4) { + DRM_ERROR("bad EVENT_WRITE_EOP\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad EVENT_WRITE_EOP\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + break; + case PACKET3_EVENT_WRITE_EOS: + if (pkt->count != 3) { + DRM_ERROR("bad EVENT_WRITE_EOS\n"); + return -EINVAL; + } + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad EVENT_WRITE_EOS\n"); + return -EINVAL; + } + ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); + ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + break; + case PACKET3_SET_CONFIG_REG: + start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_CONFIG_REG_START) || + (start_reg >= PACKET3_SET_CONFIG_REG_END) || + (end_reg >= PACKET3_SET_CONFIG_REG_END)) { + DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n"); + return -EINVAL; + } + for (i = 0; i < pkt->count; i++) { + reg = start_reg + (4 * i); + r = evergreen_cs_check_reg(p, reg, idx+1+i); + if (r) + return r; + } + break; + case PACKET3_SET_CONTEXT_REG: + start_reg = (idx_value << 2) + PACKET3_SET_CONTEXT_REG_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_CONTEXT_REG_START) || + (start_reg >= PACKET3_SET_CONTEXT_REG_END) || + (end_reg >= PACKET3_SET_CONTEXT_REG_END)) { + DRM_ERROR("bad PACKET3_SET_CONTEXT_REG\n"); + return -EINVAL; + } + for (i = 0; i < pkt->count; i++) { + reg = start_reg + (4 * i); + r = evergreen_cs_check_reg(p, reg, idx+1+i); + if (r) + return r; + } + break; + case PACKET3_SET_RESOURCE: + if (pkt->count % 8) { + DRM_ERROR("bad SET_RESOURCE\n"); + return -EINVAL; + } + start_reg = (idx_value << 2) + PACKET3_SET_RESOURCE_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_RESOURCE_START) || + (start_reg >= PACKET3_SET_RESOURCE_END) || + (end_reg >= PACKET3_SET_RESOURCE_END)) { + DRM_ERROR("bad SET_RESOURCE\n"); + return -EINVAL; + } + for (i = 0; i < (pkt->count / 8); i++) { + struct radeon_bo *texture, *mipmap; + u32 size, offset; + + switch (G__SQ_CONSTANT_TYPE(radeon_get_ib_value(p, idx+1+(i*8)+7))) { + case SQ_TEX_VTX_VALID_TEXTURE: + /* tex base */ + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_RESOURCE (tex)\n"); + return -EINVAL; + } + ib[idx+1+(i*8)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) + ib[idx+1+(i*8)+1] |= TEX_ARRAY_MODE(ARRAY_2D_TILED_THIN1); + else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) + ib[idx+1+(i*8)+1] |= TEX_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + texture = reloc->robj; + /* tex mip base */ + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_RESOURCE (tex)\n"); + return -EINVAL; + } + ib[idx+1+(i*8)+4] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + mipmap = reloc->robj; + r = evergreen_check_texture_resource(p, idx+1+(i*8), + texture, mipmap); + if (r) + return r; + break; + case SQ_TEX_VTX_VALID_BUFFER: + /* vtx base */ + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("bad SET_RESOURCE (vtx)\n"); + return -EINVAL; + } + offset = radeon_get_ib_value(p, idx+1+(i*8)+0); + size = radeon_get_ib_value(p, idx+1+(i*8)+1); + if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) { + /* force size to size of the buffer */ + dev_warn(p->dev, "vbo resource seems too big for the bo\n"); + ib[idx+1+(i*8)+1] = radeon_bo_size(reloc->robj); + } + ib[idx+1+(i*8)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff); + ib[idx+1+(i*8)+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; + break; + case SQ_TEX_VTX_INVALID_TEXTURE: + case SQ_TEX_VTX_INVALID_BUFFER: + default: + DRM_ERROR("bad SET_RESOURCE\n"); + return -EINVAL; + } + } + break; + case PACKET3_SET_ALU_CONST: + /* XXX fix me ALU const buffers only */ + break; + case PACKET3_SET_BOOL_CONST: + start_reg = (idx_value << 2) + PACKET3_SET_BOOL_CONST_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_BOOL_CONST_START) || + (start_reg >= PACKET3_SET_BOOL_CONST_END) || + (end_reg >= PACKET3_SET_BOOL_CONST_END)) { + DRM_ERROR("bad SET_BOOL_CONST\n"); + return -EINVAL; + } + break; + case PACKET3_SET_LOOP_CONST: + start_reg = (idx_value << 2) + PACKET3_SET_LOOP_CONST_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_LOOP_CONST_START) || + (start_reg >= PACKET3_SET_LOOP_CONST_END) || + (end_reg >= PACKET3_SET_LOOP_CONST_END)) { + DRM_ERROR("bad SET_LOOP_CONST\n"); + return -EINVAL; + } + break; + case PACKET3_SET_CTL_CONST: + start_reg = (idx_value << 2) + PACKET3_SET_CTL_CONST_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_CTL_CONST_START) || + (start_reg >= PACKET3_SET_CTL_CONST_END) || + (end_reg >= PACKET3_SET_CTL_CONST_END)) { + DRM_ERROR("bad SET_CTL_CONST\n"); + return -EINVAL; + } + break; + case PACKET3_SET_SAMPLER: + if (pkt->count % 3) { + DRM_ERROR("bad SET_SAMPLER\n"); + return -EINVAL; + } + start_reg = (idx_value << 2) + PACKET3_SET_SAMPLER_START; + end_reg = 4 * pkt->count + start_reg - 4; + if ((start_reg < PACKET3_SET_SAMPLER_START) || + (start_reg >= PACKET3_SET_SAMPLER_END) || + (end_reg >= PACKET3_SET_SAMPLER_END)) { + DRM_ERROR("bad SET_SAMPLER\n"); + return -EINVAL; + } + break; + case PACKET3_NOP: + break; + default: + DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode); + return -EINVAL; + } + return 0; +} + +int evergreen_cs_parse(struct radeon_cs_parser *p) +{ + struct radeon_cs_packet pkt; + struct evergreen_cs_track *track; + int r; + + if (p->track == NULL) { + /* initialize tracker, we are in kms */ + track = kzalloc(sizeof(*track), GFP_KERNEL); + if (track == NULL) + return -ENOMEM; + evergreen_cs_track_init(track); + track->npipes = p->rdev->config.evergreen.tiling_npipes; + track->nbanks = p->rdev->config.evergreen.tiling_nbanks; + track->group_size = p->rdev->config.evergreen.tiling_group_size; + p->track = track; + } + do { + r = evergreen_cs_packet_parse(p, &pkt, p->idx); + if (r) { + kfree(p->track); + p->track = NULL; + return r; + } + p->idx += pkt.count + 2; + switch (pkt.type) { + case PACKET_TYPE0: + r = evergreen_cs_parse_packet0(p, &pkt); + break; + case PACKET_TYPE2: + break; + case PACKET_TYPE3: + r = evergreen_packet3_check(p, &pkt); + break; + default: + DRM_ERROR("Unknown packet type %d !\n", pkt.type); + kfree(p->track); + p->track = NULL; + return -EINVAL; + } + if (r) { + kfree(p->track); + p->track = NULL; + return r; + } + } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); +#if 0 + for (r = 0; r < p->ib->length_dw; r++) { + printk(KERN_INFO "%05d 0x%08X\n", r, p->ib->ptr[r]); + mdelay(1); + } +#endif + kfree(p->track); + p->track = NULL; + return 0; +} + diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index af86af836f13..e028c1cd9d9b 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -151,6 +151,9 @@ #define EVERGREEN_DATA_FORMAT 0x6b00 # define EVERGREEN_INTERLEAVE_EN (1 << 0) #define EVERGREEN_DESKTOP_HEIGHT 0x6b04 +#define EVERGREEN_VLINE_START_END 0x6b08 +#define EVERGREEN_VLINE_STATUS 0x6bb8 +# define EVERGREEN_VLINE_STAT (1 << 12) #define EVERGREEN_VIEWPORT_START 0x6d70 #define EVERGREEN_VIEWPORT_SIZE 0x6d74 diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 93e9e17ad54a..79683f6b4452 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -218,6 +218,8 @@ #define CLIP_VTX_REORDER_ENA (1 << 0) #define NUM_CLIP_SEQ(x) ((x) << 1) #define PA_SC_AA_CONFIG 0x28C04 +#define MSAA_NUM_SAMPLES_SHIFT 0 +#define MSAA_NUM_SAMPLES_MASK 0x3 #define PA_SC_CLIPRECT_RULE 0x2820C #define PA_SC_EDGERULE 0x28230 #define PA_SC_FIFO_SIZE 0x8BCC @@ -553,4 +555,466 @@ # define DC_HPDx_RX_INT_TIMER(x) ((x) << 16) # define DC_HPDx_EN (1 << 28) +/* + * PM4 + */ +#define PACKET_TYPE0 0 +#define PACKET_TYPE1 1 +#define PACKET_TYPE2 2 +#define PACKET_TYPE3 3 + +#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3) +#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF) +#define CP_PACKET0_GET_REG(h) (((h) & 0xFFFF) << 2) +#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) +#define PACKET0(reg, n) ((PACKET_TYPE0 << 30) | \ + (((reg) >> 2) & 0xFFFF) | \ + ((n) & 0x3FFF) << 16) +#define CP_PACKET2 0x80000000 +#define PACKET2_PAD_SHIFT 0 +#define PACKET2_PAD_MASK (0x3fffffff << 0) + +#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v))) + +#define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \ + (((op) & 0xFF) << 8) | \ + ((n) & 0x3FFF) << 16) + +/* Packet 3 types */ +#define PACKET3_NOP 0x10 +#define PACKET3_SET_BASE 0x11 +#define PACKET3_CLEAR_STATE 0x12 +#define PACKET3_INDIRECT_BUFFER_SIZE 0x13 +#define PACKET3_DISPATCH_DIRECT 0x15 +#define PACKET3_DISPATCH_INDIRECT 0x16 +#define PACKET3_INDIRECT_BUFFER_END 0x17 +#define PACKET3_SET_PREDICATION 0x20 +#define PACKET3_REG_RMW 0x21 +#define PACKET3_COND_EXEC 0x22 +#define PACKET3_PRED_EXEC 0x23 +#define PACKET3_DRAW_INDIRECT 0x24 +#define PACKET3_DRAW_INDEX_INDIRECT 0x25 +#define PACKET3_INDEX_BASE 0x26 +#define PACKET3_DRAW_INDEX_2 0x27 +#define PACKET3_CONTEXT_CONTROL 0x28 +#define PACKET3_DRAW_INDEX_OFFSET 0x29 +#define PACKET3_INDEX_TYPE 0x2A +#define PACKET3_DRAW_INDEX 0x2B +#define PACKET3_DRAW_INDEX_AUTO 0x2D +#define PACKET3_DRAW_INDEX_IMMD 0x2E +#define PACKET3_NUM_INSTANCES 0x2F +#define PACKET3_DRAW_INDEX_MULTI_AUTO 0x30 +#define PACKET3_STRMOUT_BUFFER_UPDATE 0x34 +#define PACKET3_DRAW_INDEX_OFFSET_2 0x35 +#define PACKET3_DRAW_INDEX_MULTI_ELEMENT 0x36 +#define PACKET3_MEM_SEMAPHORE 0x39 +#define PACKET3_MPEG_INDEX 0x3A +#define PACKET3_WAIT_REG_MEM 0x3C +#define PACKET3_MEM_WRITE 0x3D +#define PACKET3_INDIRECT_BUFFER 0x32 +#define PACKET3_SURFACE_SYNC 0x43 +# define PACKET3_CB0_DEST_BASE_ENA (1 << 6) +# define PACKET3_CB1_DEST_BASE_ENA (1 << 7) +# define PACKET3_CB2_DEST_BASE_ENA (1 << 8) +# define PACKET3_CB3_DEST_BASE_ENA (1 << 9) +# define PACKET3_CB4_DEST_BASE_ENA (1 << 10) +# define PACKET3_CB5_DEST_BASE_ENA (1 << 11) +# define PACKET3_CB6_DEST_BASE_ENA (1 << 12) +# define PACKET3_CB7_DEST_BASE_ENA (1 << 13) +# define PACKET3_DB_DEST_BASE_ENA (1 << 14) +# define PACKET3_CB8_DEST_BASE_ENA (1 << 15) +# define PACKET3_CB9_DEST_BASE_ENA (1 << 16) +# define PACKET3_CB10_DEST_BASE_ENA (1 << 17) +# define PACKET3_CB11_DEST_BASE_ENA (1 << 17) +# define PACKET3_FULL_CACHE_ENA (1 << 20) +# define PACKET3_TC_ACTION_ENA (1 << 23) +# define PACKET3_VC_ACTION_ENA (1 << 24) +# define PACKET3_CB_ACTION_ENA (1 << 25) +# define PACKET3_DB_ACTION_ENA (1 << 26) +# define PACKET3_SH_ACTION_ENA (1 << 27) +# define PACKET3_SMX_ACTION_ENA (1 << 28) +#define PACKET3_ME_INITIALIZE 0x44 +#define PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16) +#define PACKET3_COND_WRITE 0x45 +#define PACKET3_EVENT_WRITE 0x46 +#define PACKET3_EVENT_WRITE_EOP 0x47 +#define PACKET3_EVENT_WRITE_EOS 0x48 +#define PACKET3_PREAMBLE_CNTL 0x4A +#define PACKET3_RB_OFFSET 0x4B +#define PACKET3_ALU_PS_CONST_BUFFER_COPY 0x4C +#define PACKET3_ALU_VS_CONST_BUFFER_COPY 0x4D +#define PACKET3_ALU_PS_CONST_UPDATE 0x4E +#define PACKET3_ALU_VS_CONST_UPDATE 0x4F +#define PACKET3_ONE_REG_WRITE 0x57 +#define PACKET3_SET_CONFIG_REG 0x68 +#define PACKET3_SET_CONFIG_REG_START 0x00008000 +#define PACKET3_SET_CONFIG_REG_END 0x0000ac00 +#define PACKET3_SET_CONTEXT_REG 0x69 +#define PACKET3_SET_CONTEXT_REG_START 0x00028000 +#define PACKET3_SET_CONTEXT_REG_END 0x00029000 +#define PACKET3_SET_ALU_CONST 0x6A +/* alu const buffers only; no reg file */ +#define PACKET3_SET_BOOL_CONST 0x6B +#define PACKET3_SET_BOOL_CONST_START 0x0003a500 +#define PACKET3_SET_BOOL_CONST_END 0x0003a518 +#define PACKET3_SET_LOOP_CONST 0x6C +#define PACKET3_SET_LOOP_CONST_START 0x0003a200 +#define PACKET3_SET_LOOP_CONST_END 0x0003a500 +#define PACKET3_SET_RESOURCE 0x6D +#define PACKET3_SET_RESOURCE_START 0x00030000 +#define PACKET3_SET_RESOURCE_END 0x00038000 +#define PACKET3_SET_SAMPLER 0x6E +#define PACKET3_SET_SAMPLER_START 0x0003c000 +#define PACKET3_SET_SAMPLER_END 0x0003c600 +#define PACKET3_SET_CTL_CONST 0x6F +#define PACKET3_SET_CTL_CONST_START 0x0003cff0 +#define PACKET3_SET_CTL_CONST_END 0x0003ff0c +#define PACKET3_SET_RESOURCE_OFFSET 0x70 +#define PACKET3_SET_ALU_CONST_VS 0x71 +#define PACKET3_SET_ALU_CONST_DI 0x72 +#define PACKET3_SET_CONTEXT_REG_INDIRECT 0x73 +#define PACKET3_SET_RESOURCE_INDIRECT 0x74 +#define PACKET3_SET_APPEND_CNT 0x75 + +#define SQ_RESOURCE_CONSTANT_WORD7_0 0x3001c +#define S__SQ_CONSTANT_TYPE(x) (((x) & 3) << 30) +#define G__SQ_CONSTANT_TYPE(x) (((x) >> 30) & 3) +#define SQ_TEX_VTX_INVALID_TEXTURE 0x0 +#define SQ_TEX_VTX_INVALID_BUFFER 0x1 +#define SQ_TEX_VTX_VALID_TEXTURE 0x2 +#define SQ_TEX_VTX_VALID_BUFFER 0x3 + +#define SQ_CONST_MEM_BASE 0x8df8 + +#define SQ_ESGS_RING_SIZE 0x8c44 +#define SQ_GSVS_RING_SIZE 0x8c4c +#define SQ_ESTMP_RING_SIZE 0x8c54 +#define SQ_GSTMP_RING_SIZE 0x8c5c +#define SQ_VSTMP_RING_SIZE 0x8c64 +#define SQ_PSTMP_RING_SIZE 0x8c6c +#define SQ_LSTMP_RING_SIZE 0x8e14 +#define SQ_HSTMP_RING_SIZE 0x8e1c +#define VGT_TF_RING_SIZE 0x8988 + +#define SQ_ESGS_RING_ITEMSIZE 0x28900 +#define SQ_GSVS_RING_ITEMSIZE 0x28904 +#define SQ_ESTMP_RING_ITEMSIZE 0x28908 +#define SQ_GSTMP_RING_ITEMSIZE 0x2890c +#define SQ_VSTMP_RING_ITEMSIZE 0x28910 +#define SQ_PSTMP_RING_ITEMSIZE 0x28914 +#define SQ_LSTMP_RING_ITEMSIZE 0x28830 +#define SQ_HSTMP_RING_ITEMSIZE 0x28834 + +#define SQ_GS_VERT_ITEMSIZE 0x2891c +#define SQ_GS_VERT_ITEMSIZE_1 0x28920 +#define SQ_GS_VERT_ITEMSIZE_2 0x28924 +#define SQ_GS_VERT_ITEMSIZE_3 0x28928 +#define SQ_GSVS_RING_OFFSET_1 0x2892c +#define SQ_GSVS_RING_OFFSET_2 0x28930 +#define SQ_GSVS_RING_OFFSET_3 0x28934 + +#define SQ_ALU_CONST_CACHE_PS_0 0x28940 +#define SQ_ALU_CONST_CACHE_PS_1 0x28944 +#define SQ_ALU_CONST_CACHE_PS_2 0x28948 +#define SQ_ALU_CONST_CACHE_PS_3 0x2894c +#define SQ_ALU_CONST_CACHE_PS_4 0x28950 +#define SQ_ALU_CONST_CACHE_PS_5 0x28954 +#define SQ_ALU_CONST_CACHE_PS_6 0x28958 +#define SQ_ALU_CONST_CACHE_PS_7 0x2895c +#define SQ_ALU_CONST_CACHE_PS_8 0x28960 +#define SQ_ALU_CONST_CACHE_PS_9 0x28964 +#define SQ_ALU_CONST_CACHE_PS_10 0x28968 +#define SQ_ALU_CONST_CACHE_PS_11 0x2896c +#define SQ_ALU_CONST_CACHE_PS_12 0x28970 +#define SQ_ALU_CONST_CACHE_PS_13 0x28974 +#define SQ_ALU_CONST_CACHE_PS_14 0x28978 +#define SQ_ALU_CONST_CACHE_PS_15 0x2897c +#define SQ_ALU_CONST_CACHE_VS_0 0x28980 +#define SQ_ALU_CONST_CACHE_VS_1 0x28984 +#define SQ_ALU_CONST_CACHE_VS_2 0x28988 +#define SQ_ALU_CONST_CACHE_VS_3 0x2898c +#define SQ_ALU_CONST_CACHE_VS_4 0x28990 +#define SQ_ALU_CONST_CACHE_VS_5 0x28994 +#define SQ_ALU_CONST_CACHE_VS_6 0x28998 +#define SQ_ALU_CONST_CACHE_VS_7 0x2899c +#define SQ_ALU_CONST_CACHE_VS_8 0x289a0 +#define SQ_ALU_CONST_CACHE_VS_9 0x289a4 +#define SQ_ALU_CONST_CACHE_VS_10 0x289a8 +#define SQ_ALU_CONST_CACHE_VS_11 0x289ac +#define SQ_ALU_CONST_CACHE_VS_12 0x289b0 +#define SQ_ALU_CONST_CACHE_VS_13 0x289b4 +#define SQ_ALU_CONST_CACHE_VS_14 0x289b8 +#define SQ_ALU_CONST_CACHE_VS_15 0x289bc +#define SQ_ALU_CONST_CACHE_GS_0 0x289c0 +#define SQ_ALU_CONST_CACHE_GS_1 0x289c4 +#define SQ_ALU_CONST_CACHE_GS_2 0x289c8 +#define SQ_ALU_CONST_CACHE_GS_3 0x289cc +#define SQ_ALU_CONST_CACHE_GS_4 0x289d0 +#define SQ_ALU_CONST_CACHE_GS_5 0x289d4 +#define SQ_ALU_CONST_CACHE_GS_6 0x289d8 +#define SQ_ALU_CONST_CACHE_GS_7 0x289dc +#define SQ_ALU_CONST_CACHE_GS_8 0x289e0 +#define SQ_ALU_CONST_CACHE_GS_9 0x289e4 +#define SQ_ALU_CONST_CACHE_GS_10 0x289e8 +#define SQ_ALU_CONST_CACHE_GS_11 0x289ec +#define SQ_ALU_CONST_CACHE_GS_12 0x289f0 +#define SQ_ALU_CONST_CACHE_GS_13 0x289f4 +#define SQ_ALU_CONST_CACHE_GS_14 0x289f8 +#define SQ_ALU_CONST_CACHE_GS_15 0x289fc +#define SQ_ALU_CONST_CACHE_HS_0 0x28f00 +#define SQ_ALU_CONST_CACHE_HS_1 0x28f04 +#define SQ_ALU_CONST_CACHE_HS_2 0x28f08 +#define SQ_ALU_CONST_CACHE_HS_3 0x28f0c +#define SQ_ALU_CONST_CACHE_HS_4 0x28f10 +#define SQ_ALU_CONST_CACHE_HS_5 0x28f14 +#define SQ_ALU_CONST_CACHE_HS_6 0x28f18 +#define SQ_ALU_CONST_CACHE_HS_7 0x28f1c +#define SQ_ALU_CONST_CACHE_HS_8 0x28f20 +#define SQ_ALU_CONST_CACHE_HS_9 0x28f24 +#define SQ_ALU_CONST_CACHE_HS_10 0x28f28 +#define SQ_ALU_CONST_CACHE_HS_11 0x28f2c +#define SQ_ALU_CONST_CACHE_HS_12 0x28f30 +#define SQ_ALU_CONST_CACHE_HS_13 0x28f34 +#define SQ_ALU_CONST_CACHE_HS_14 0x28f38 +#define SQ_ALU_CONST_CACHE_HS_15 0x28f3c +#define SQ_ALU_CONST_CACHE_LS_0 0x28f40 +#define SQ_ALU_CONST_CACHE_LS_1 0x28f44 +#define SQ_ALU_CONST_CACHE_LS_2 0x28f48 +#define SQ_ALU_CONST_CACHE_LS_3 0x28f4c +#define SQ_ALU_CONST_CACHE_LS_4 0x28f50 +#define SQ_ALU_CONST_CACHE_LS_5 0x28f54 +#define SQ_ALU_CONST_CACHE_LS_6 0x28f58 +#define SQ_ALU_CONST_CACHE_LS_7 0x28f5c +#define SQ_ALU_CONST_CACHE_LS_8 0x28f60 +#define SQ_ALU_CONST_CACHE_LS_9 0x28f64 +#define SQ_ALU_CONST_CACHE_LS_10 0x28f68 +#define SQ_ALU_CONST_CACHE_LS_11 0x28f6c +#define SQ_ALU_CONST_CACHE_LS_12 0x28f70 +#define SQ_ALU_CONST_CACHE_LS_13 0x28f74 +#define SQ_ALU_CONST_CACHE_LS_14 0x28f78 +#define SQ_ALU_CONST_CACHE_LS_15 0x28f7c + +#define DB_DEPTH_CONTROL 0x28800 +#define DB_DEPTH_VIEW 0x28008 +#define DB_HTILE_DATA_BASE 0x28014 +#define DB_Z_INFO 0x28040 +# define Z_ARRAY_MODE(x) ((x) << 4) +#define DB_STENCIL_INFO 0x28044 +#define DB_Z_READ_BASE 0x28048 +#define DB_STENCIL_READ_BASE 0x2804c +#define DB_Z_WRITE_BASE 0x28050 +#define DB_STENCIL_WRITE_BASE 0x28054 +#define DB_DEPTH_SIZE 0x28058 + +#define SQ_PGM_START_PS 0x28840 +#define SQ_PGM_START_VS 0x2885c +#define SQ_PGM_START_GS 0x28874 +#define SQ_PGM_START_ES 0x2888c +#define SQ_PGM_START_FS 0x288a4 +#define SQ_PGM_START_HS 0x288b8 +#define SQ_PGM_START_LS 0x288d0 + +#define VGT_STRMOUT_CONFIG 0x28b94 +#define VGT_STRMOUT_BUFFER_CONFIG 0x28b98 + +#define CB_TARGET_MASK 0x28238 +#define CB_SHADER_MASK 0x2823c + +#define GDS_ADDR_BASE 0x28720 + +#define CB_IMMED0_BASE 0x28b9c +#define CB_IMMED1_BASE 0x28ba0 +#define CB_IMMED2_BASE 0x28ba4 +#define CB_IMMED3_BASE 0x28ba8 +#define CB_IMMED4_BASE 0x28bac +#define CB_IMMED5_BASE 0x28bb0 +#define CB_IMMED6_BASE 0x28bb4 +#define CB_IMMED7_BASE 0x28bb8 +#define CB_IMMED8_BASE 0x28bbc +#define CB_IMMED9_BASE 0x28bc0 +#define CB_IMMED10_BASE 0x28bc4 +#define CB_IMMED11_BASE 0x28bc8 + +/* all 12 CB blocks have these regs */ +#define CB_COLOR0_BASE 0x28c60 +#define CB_COLOR0_PITCH 0x28c64 +#define CB_COLOR0_SLICE 0x28c68 +#define CB_COLOR0_VIEW 0x28c6c +#define CB_COLOR0_INFO 0x28c70 +# define CB_ARRAY_MODE(x) ((x) << 8) +# define ARRAY_LINEAR_GENERAL 0 +# define ARRAY_LINEAR_ALIGNED 1 +# define ARRAY_1D_TILED_THIN1 2 +# define ARRAY_2D_TILED_THIN1 4 +#define CB_COLOR0_ATTRIB 0x28c74 +#define CB_COLOR0_DIM 0x28c78 +/* only CB0-7 blocks have these regs */ +#define CB_COLOR0_CMASK 0x28c7c +#define CB_COLOR0_CMASK_SLICE 0x28c80 +#define CB_COLOR0_FMASK 0x28c84 +#define CB_COLOR0_FMASK_SLICE 0x28c88 +#define CB_COLOR0_CLEAR_WORD0 0x28c8c +#define CB_COLOR0_CLEAR_WORD1 0x28c90 +#define CB_COLOR0_CLEAR_WORD2 0x28c94 +#define CB_COLOR0_CLEAR_WORD3 0x28c98 + +#define CB_COLOR1_BASE 0x28c9c +#define CB_COLOR2_BASE 0x28cd8 +#define CB_COLOR3_BASE 0x28d14 +#define CB_COLOR4_BASE 0x28d50 +#define CB_COLOR5_BASE 0x28d8c +#define CB_COLOR6_BASE 0x28dc8 +#define CB_COLOR7_BASE 0x28e04 +#define CB_COLOR8_BASE 0x28e40 +#define CB_COLOR9_BASE 0x28e5c +#define CB_COLOR10_BASE 0x28e78 +#define CB_COLOR11_BASE 0x28e94 + +#define CB_COLOR1_PITCH 0x28ca0 +#define CB_COLOR2_PITCH 0x28cdc +#define CB_COLOR3_PITCH 0x28d18 +#define CB_COLOR4_PITCH 0x28d54 +#define CB_COLOR5_PITCH 0x28d90 +#define CB_COLOR6_PITCH 0x28dcc +#define CB_COLOR7_PITCH 0x28e08 +#define CB_COLOR8_PITCH 0x28e44 +#define CB_COLOR9_PITCH 0x28e60 +#define CB_COLOR10_PITCH 0x28e7c +#define CB_COLOR11_PITCH 0x28e98 + +#define CB_COLOR1_SLICE 0x28ca4 +#define CB_COLOR2_SLICE 0x28ce0 +#define CB_COLOR3_SLICE 0x28d1c +#define CB_COLOR4_SLICE 0x28d58 +#define CB_COLOR5_SLICE 0x28d94 +#define CB_COLOR6_SLICE 0x28dd0 +#define CB_COLOR7_SLICE 0x28e0c +#define CB_COLOR8_SLICE 0x28e48 +#define CB_COLOR9_SLICE 0x28e64 +#define CB_COLOR10_SLICE 0x28e80 +#define CB_COLOR11_SLICE 0x28e9c + +#define CB_COLOR1_VIEW 0x28ca8 +#define CB_COLOR2_VIEW 0x28ce4 +#define CB_COLOR3_VIEW 0x28d20 +#define CB_COLOR4_VIEW 0x28d5c +#define CB_COLOR5_VIEW 0x28d98 +#define CB_COLOR6_VIEW 0x28dd4 +#define CB_COLOR7_VIEW 0x28e10 +#define CB_COLOR8_VIEW 0x28e4c +#define CB_COLOR9_VIEW 0x28e68 +#define CB_COLOR10_VIEW 0x28e84 +#define CB_COLOR11_VIEW 0x28ea0 + +#define CB_COLOR1_INFO 0x28cac +#define CB_COLOR2_INFO 0x28ce8 +#define CB_COLOR3_INFO 0x28d24 +#define CB_COLOR4_INFO 0x28d60 +#define CB_COLOR5_INFO 0x28d9c +#define CB_COLOR6_INFO 0x28dd8 +#define CB_COLOR7_INFO 0x28e14 +#define CB_COLOR8_INFO 0x28e50 +#define CB_COLOR9_INFO 0x28e6c +#define CB_COLOR10_INFO 0x28e88 +#define CB_COLOR11_INFO 0x28ea4 + +#define CB_COLOR1_ATTRIB 0x28cb0 +#define CB_COLOR2_ATTRIB 0x28cec +#define CB_COLOR3_ATTRIB 0x28d28 +#define CB_COLOR4_ATTRIB 0x28d64 +#define CB_COLOR5_ATTRIB 0x28da0 +#define CB_COLOR6_ATTRIB 0x28ddc +#define CB_COLOR7_ATTRIB 0x28e18 +#define CB_COLOR8_ATTRIB 0x28e54 +#define CB_COLOR9_ATTRIB 0x28e70 +#define CB_COLOR10_ATTRIB 0x28e8c +#define CB_COLOR11_ATTRIB 0x28ea8 + +#define CB_COLOR1_DIM 0x28cb4 +#define CB_COLOR2_DIM 0x28cf0 +#define CB_COLOR3_DIM 0x28d2c +#define CB_COLOR4_DIM 0x28d68 +#define CB_COLOR5_DIM 0x28da4 +#define CB_COLOR6_DIM 0x28de0 +#define CB_COLOR7_DIM 0x28e1c +#define CB_COLOR8_DIM 0x28e58 +#define CB_COLOR9_DIM 0x28e74 +#define CB_COLOR10_DIM 0x28e90 +#define CB_COLOR11_DIM 0x28eac + +#define CB_COLOR1_CMASK 0x28cb8 +#define CB_COLOR2_CMASK 0x28cf4 +#define CB_COLOR3_CMASK 0x28d30 +#define CB_COLOR4_CMASK 0x28d6c +#define CB_COLOR5_CMASK 0x28da8 +#define CB_COLOR6_CMASK 0x28de4 +#define CB_COLOR7_CMASK 0x28e20 + +#define CB_COLOR1_CMASK_SLICE 0x28cbc +#define CB_COLOR2_CMASK_SLICE 0x28cf8 +#define CB_COLOR3_CMASK_SLICE 0x28d34 +#define CB_COLOR4_CMASK_SLICE 0x28d70 +#define CB_COLOR5_CMASK_SLICE 0x28dac +#define CB_COLOR6_CMASK_SLICE 0x28de8 +#define CB_COLOR7_CMASK_SLICE 0x28e24 + +#define CB_COLOR1_FMASK 0x28cc0 +#define CB_COLOR2_FMASK 0x28cfc +#define CB_COLOR3_FMASK 0x28d38 +#define CB_COLOR4_FMASK 0x28d74 +#define CB_COLOR5_FMASK 0x28db0 +#define CB_COLOR6_FMASK 0x28dec +#define CB_COLOR7_FMASK 0x28e28 + +#define CB_COLOR1_FMASK_SLICE 0x28cc4 +#define CB_COLOR2_FMASK_SLICE 0x28d00 +#define CB_COLOR3_FMASK_SLICE 0x28d3c +#define CB_COLOR4_FMASK_SLICE 0x28d78 +#define CB_COLOR5_FMASK_SLICE 0x28db4 +#define CB_COLOR6_FMASK_SLICE 0x28df0 +#define CB_COLOR7_FMASK_SLICE 0x28e2c + +#define CB_COLOR1_CLEAR_WORD0 0x28cc8 +#define CB_COLOR2_CLEAR_WORD0 0x28d04 +#define CB_COLOR3_CLEAR_WORD0 0x28d40 +#define CB_COLOR4_CLEAR_WORD0 0x28d7c +#define CB_COLOR5_CLEAR_WORD0 0x28db8 +#define CB_COLOR6_CLEAR_WORD0 0x28df4 +#define CB_COLOR7_CLEAR_WORD0 0x28e30 + +#define CB_COLOR1_CLEAR_WORD1 0x28ccc +#define CB_COLOR2_CLEAR_WORD1 0x28d08 +#define CB_COLOR3_CLEAR_WORD1 0x28d44 +#define CB_COLOR4_CLEAR_WORD1 0x28d80 +#define CB_COLOR5_CLEAR_WORD1 0x28dbc +#define CB_COLOR6_CLEAR_WORD1 0x28df8 +#define CB_COLOR7_CLEAR_WORD1 0x28e34 + +#define CB_COLOR1_CLEAR_WORD2 0x28cd0 +#define CB_COLOR2_CLEAR_WORD2 0x28d0c +#define CB_COLOR3_CLEAR_WORD2 0x28d48 +#define CB_COLOR4_CLEAR_WORD2 0x28d84 +#define CB_COLOR5_CLEAR_WORD2 0x28dc0 +#define CB_COLOR6_CLEAR_WORD2 0x28dfc +#define CB_COLOR7_CLEAR_WORD2 0x28e38 + +#define CB_COLOR1_CLEAR_WORD3 0x28cd4 +#define CB_COLOR2_CLEAR_WORD3 0x28d10 +#define CB_COLOR3_CLEAR_WORD3 0x28d4c +#define CB_COLOR4_CLEAR_WORD3 0x28d88 +#define CB_COLOR5_CLEAR_WORD3 0x28dc4 +#define CB_COLOR6_CLEAR_WORD3 0x28e00 +#define CB_COLOR7_CLEAR_WORD3 0x28e3c + +#define SQ_TEX_RESOURCE_WORD0_0 0x30000 +#define SQ_TEX_RESOURCE_WORD1_0 0x30004 +# define TEX_ARRAY_MODE(x) ((x) << 28) +#define SQ_TEX_RESOURCE_WORD2_0 0x30008 +#define SQ_TEX_RESOURCE_WORD3_0 0x3000C +#define SQ_TEX_RESOURCE_WORD4_0 0x30010 +#define SQ_TEX_RESOURCE_WORD5_0 0x30014 +#define SQ_TEX_RESOURCE_WORD6_0 0x30018 +#define SQ_TEX_RESOURCE_WORD7_0 0x3001c + + #endif diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index e57df08d4aeb..87f7e2cc52d4 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -724,8 +724,8 @@ static struct radeon_asic evergreen_asic = { .irq_set = &evergreen_irq_set, .irq_process = &evergreen_irq_process, .get_vblank_counter = &evergreen_get_vblank_counter, - .fence_ring_emit = NULL, - .cs_parse = NULL, + .fence_ring_emit = &r600_fence_ring_emit, + .cs_parse = &evergreen_cs_parse, .copy_blit = NULL, .copy_dma = NULL, .copy = NULL, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 5c40a3dfaca2..c0bbaa64157a 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -314,6 +314,7 @@ void evergreen_hpd_set_polarity(struct radeon_device *rdev, u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc); int evergreen_irq_set(struct radeon_device *rdev); int evergreen_irq_process(struct radeon_device *rdev); +extern int evergreen_cs_parse(struct radeon_cs_parser *p); extern void evergreen_pm_misc(struct radeon_device *rdev); extern void evergreen_pm_prepare(struct radeon_device *rdev); extern void evergreen_pm_finish(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen new file mode 100644 index 000000000000..b5c757f68d3c --- /dev/null +++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen @@ -0,0 +1,611 @@ +evergreen 0x9400 +0x00008040 WAIT_UNTIL +0x00008044 WAIT_UNTIL_POLL_CNTL +0x00008048 WAIT_UNTIL_POLL_MASK +0x0000804c WAIT_UNTIL_POLL_REFDATA +0x000088B0 VGT_VTX_VECT_EJECT_REG +0x000088C4 VGT_CACHE_INVALIDATION +0x000088D4 VGT_GS_VERTEX_REUSE +0x00008958 VGT_PRIMITIVE_TYPE +0x0000895C VGT_INDEX_TYPE +0x00008970 VGT_NUM_INDICES +0x00008974 VGT_NUM_INSTANCES +0x00008990 VGT_COMPUTE_DIM_X +0x00008994 VGT_COMPUTE_DIM_Y +0x00008998 VGT_COMPUTE_DIM_Z +0x0000899C VGT_COMPUTE_START_X +0x000089A0 VGT_COMPUTE_START_Y +0x000089A4 VGT_COMPUTE_START_Z +0x000089AC VGT_COMPUTE_THREAD_GOURP_SIZE +0x00008A14 PA_CL_ENHANCE +0x00008A60 PA_SC_LINE_STIPPLE_VALUE +0x00008B10 PA_SC_LINE_STIPPLE_STATE +0x00008BF0 PA_SC_ENHANCE +0x00008D8C SQ_DYN_GPR_CNTL_PS_FLUSH_REQ +0x00008C00 SQ_CONFIG +0x00008C04 SQ_GPR_RESOURCE_MGMT_1 +0x00008C08 SQ_GPR_RESOURCE_MGMT_2 +0x00008C0C SQ_GPR_RESOURCE_MGMT_3 +0x00008C10 SQ_GLOBAL_GPR_RESOURCE_MGMT_1 +0x00008C14 SQ_GLOBAL_GPR_RESOURCE_MGMT_2 +0x00008C18 SQ_THREAD_RESOURCE_MGMT +0x00008C1C SQ_THREAD_RESOURCE_MGMT_2 +0x00008C20 SQ_STACK_RESOURCE_MGMT_1 +0x00008C24 SQ_STACK_RESOURCE_MGMT_2 +0x00008C28 SQ_STACK_RESOURCE_MGMT_3 +0x00008DF8 SQ_CONST_MEM_BASE +0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS +0x00009100 SPI_CONFIG_CNTL +0x0000913C SPI_CONFIG_CNTL_1 +0x00009700 VC_CNTL +0x00009714 VC_ENHANCE +0x00009830 DB_DEBUG +0x00009834 DB_DEBUG2 +0x00009838 DB_DEBUG3 +0x0000983C DB_DEBUG4 +0x00009854 DB_WATERMARKS +0x0000A400 TD_PS_BORDER_COLOR_INDEX +0x0000A404 TD_PS_BORDER_COLOR_RED +0x0000A408 TD_PS_BORDER_COLOR_GREEN +0x0000A40C TD_PS_BORDER_COLOR_BLUE +0x0000A410 TD_PS_BORDER_COLOR_ALPHA +0x0000A414 TD_VS_BORDER_COLOR_INDEX +0x0000A418 TD_VS_BORDER_COLOR_RED +0x0000A41C TD_VS_BORDER_COLOR_GREEN +0x0000A420 TD_VS_BORDER_COLOR_BLUE +0x0000A424 TD_VS_BORDER_COLOR_ALPHA +0x0000A428 TD_GS_BORDER_COLOR_INDEX +0x0000A42C TD_GS_BORDER_COLOR_RED +0x0000A430 TD_GS_BORDER_COLOR_GREEN +0x0000A434 TD_GS_BORDER_COLOR_BLUE +0x0000A438 TD_GS_BORDER_COLOR_ALPHA +0x0000A43C TD_HS_BORDER_COLOR_INDEX +0x0000A440 TD_HS_BORDER_COLOR_RED +0x0000A444 TD_HS_BORDER_COLOR_GREEN +0x0000A448 TD_HS_BORDER_COLOR_BLUE +0x0000A44C TD_HS_BORDER_COLOR_ALPHA +0x0000A450 TD_LS_BORDER_COLOR_INDEX +0x0000A454 TD_LS_BORDER_COLOR_RED +0x0000A458 TD_LS_BORDER_COLOR_GREEN +0x0000A45C TD_LS_BORDER_COLOR_BLUE +0x0000A460 TD_LS_BORDER_COLOR_ALPHA +0x0000A464 TD_CS_BORDER_COLOR_INDEX +0x0000A468 TD_CS_BORDER_COLOR_RED +0x0000A46C TD_CS_BORDER_COLOR_GREEN +0x0000A470 TD_CS_BORDER_COLOR_BLUE +0x0000A474 TD_CS_BORDER_COLOR_ALPHA +0x00028000 DB_RENDER_CONTROL +0x00028004 DB_COUNT_CONTROL +0x0002800C DB_RENDER_OVERRIDE +0x00028010 DB_RENDER_OVERRIDE2 +0x00028028 DB_STENCIL_CLEAR +0x0002802C DB_DEPTH_CLEAR +0x00028034 PA_SC_SCREEN_SCISSOR_BR +0x00028030 PA_SC_SCREEN_SCISSOR_TL +0x0002805C DB_DEPTH_SLICE +0x00028140 SQ_ALU_CONST_BUFFER_SIZE_PS_0 +0x00028144 SQ_ALU_CONST_BUFFER_SIZE_PS_1 +0x00028148 SQ_ALU_CONST_BUFFER_SIZE_PS_2 +0x0002814C SQ_ALU_CONST_BUFFER_SIZE_PS_3 +0x00028150 SQ_ALU_CONST_BUFFER_SIZE_PS_4 +0x00028154 SQ_ALU_CONST_BUFFER_SIZE_PS_5 +0x00028158 SQ_ALU_CONST_BUFFER_SIZE_PS_6 +0x0002815C SQ_ALU_CONST_BUFFER_SIZE_PS_7 +0x00028160 SQ_ALU_CONST_BUFFER_SIZE_PS_8 +0x00028164 SQ_ALU_CONST_BUFFER_SIZE_PS_9 +0x00028168 SQ_ALU_CONST_BUFFER_SIZE_PS_10 +0x0002816C SQ_ALU_CONST_BUFFER_SIZE_PS_11 +0x00028170 SQ_ALU_CONST_BUFFER_SIZE_PS_12 +0x00028174 SQ_ALU_CONST_BUFFER_SIZE_PS_13 +0x00028178 SQ_ALU_CONST_BUFFER_SIZE_PS_14 +0x0002817C SQ_ALU_CONST_BUFFER_SIZE_PS_15 +0x00028180 SQ_ALU_CONST_BUFFER_SIZE_VS_0 +0x00028184 SQ_ALU_CONST_BUFFER_SIZE_VS_1 +0x00028188 SQ_ALU_CONST_BUFFER_SIZE_VS_2 +0x0002818C SQ_ALU_CONST_BUFFER_SIZE_VS_3 +0x00028190 SQ_ALU_CONST_BUFFER_SIZE_VS_4 +0x00028194 SQ_ALU_CONST_BUFFER_SIZE_VS_5 +0x00028198 SQ_ALU_CONST_BUFFER_SIZE_VS_6 +0x0002819C SQ_ALU_CONST_BUFFER_SIZE_VS_7 +0x000281A0 SQ_ALU_CONST_BUFFER_SIZE_VS_8 +0x000281A4 SQ_ALU_CONST_BUFFER_SIZE_VS_9 +0x000281A8 SQ_ALU_CONST_BUFFER_SIZE_VS_10 +0x000281AC SQ_ALU_CONST_BUFFER_SIZE_VS_11 +0x000281B0 SQ_ALU_CONST_BUFFER_SIZE_VS_12 +0x000281B4 SQ_ALU_CONST_BUFFER_SIZE_VS_13 +0x000281B8 SQ_ALU_CONST_BUFFER_SIZE_VS_14 +0x000281BC SQ_ALU_CONST_BUFFER_SIZE_VS_15 +0x000281C0 SQ_ALU_CONST_BUFFER_SIZE_GS_0 +0x000281C4 SQ_ALU_CONST_BUFFER_SIZE_GS_1 +0x000281C8 SQ_ALU_CONST_BUFFER_SIZE_GS_2 +0x000281CC SQ_ALU_CONST_BUFFER_SIZE_GS_3 +0x000281D0 SQ_ALU_CONST_BUFFER_SIZE_GS_4 +0x000281D4 SQ_ALU_CONST_BUFFER_SIZE_GS_5 +0x000281D8 SQ_ALU_CONST_BUFFER_SIZE_GS_6 +0x000281DC SQ_ALU_CONST_BUFFER_SIZE_GS_7 +0x000281E0 SQ_ALU_CONST_BUFFER_SIZE_GS_8 +0x000281E4 SQ_ALU_CONST_BUFFER_SIZE_GS_9 +0x000281E8 SQ_ALU_CONST_BUFFER_SIZE_GS_10 +0x000281EC SQ_ALU_CONST_BUFFER_SIZE_GS_11 +0x000281F0 SQ_ALU_CONST_BUFFER_SIZE_GS_12 +0x000281F4 SQ_ALU_CONST_BUFFER_SIZE_GS_13 +0x000281F8 SQ_ALU_CONST_BUFFER_SIZE_GS_14 +0x000281FC SQ_ALU_CONST_BUFFER_SIZE_GS_15 +0x00028200 PA_SC_WINDOW_OFFSET +0x00028204 PA_SC_WINDOW_SCISSOR_TL +0x00028208 PA_SC_WINDOW_SCISSOR_BR +0x0002820C PA_SC_CLIPRECT_RULE +0x00028210 PA_SC_CLIPRECT_0_TL +0x00028214 PA_SC_CLIPRECT_0_BR +0x00028218 PA_SC_CLIPRECT_1_TL +0x0002821C PA_SC_CLIPRECT_1_BR +0x00028220 PA_SC_CLIPRECT_2_TL +0x00028224 PA_SC_CLIPRECT_2_BR +0x00028228 PA_SC_CLIPRECT_3_TL +0x0002822C PA_SC_CLIPRECT_3_BR +0x00028230 PA_SC_EDGERULE +0x00028234 PA_SU_HARDWARE_SCREEN_OFFSET +0x00028240 PA_SC_GENERIC_SCISSOR_TL +0x00028244 PA_SC_GENERIC_SCISSOR_BR +0x00028250 PA_SC_VPORT_SCISSOR_0_TL +0x00028254 PA_SC_VPORT_SCISSOR_0_BR +0x00028258 PA_SC_VPORT_SCISSOR_1_TL +0x0002825C PA_SC_VPORT_SCISSOR_1_BR +0x00028260 PA_SC_VPORT_SCISSOR_2_TL +0x00028264 PA_SC_VPORT_SCISSOR_2_BR +0x00028268 PA_SC_VPORT_SCISSOR_3_TL +0x0002826C PA_SC_VPORT_SCISSOR_3_BR +0x00028270 PA_SC_VPORT_SCISSOR_4_TL +0x00028274 PA_SC_VPORT_SCISSOR_4_BR +0x00028278 PA_SC_VPORT_SCISSOR_5_TL +0x0002827C PA_SC_VPORT_SCISSOR_5_BR +0x00028280 PA_SC_VPORT_SCISSOR_6_TL +0x00028284 PA_SC_VPORT_SCISSOR_6_BR +0x00028288 PA_SC_VPORT_SCISSOR_7_TL +0x0002828C PA_SC_VPORT_SCISSOR_7_BR +0x00028290 PA_SC_VPORT_SCISSOR_8_TL +0x00028294 PA_SC_VPORT_SCISSOR_8_BR +0x00028298 PA_SC_VPORT_SCISSOR_9_TL +0x0002829C PA_SC_VPORT_SCISSOR_9_BR +0x000282A0 PA_SC_VPORT_SCISSOR_10_TL +0x000282A4 PA_SC_VPORT_SCISSOR_10_BR +0x000282A8 PA_SC_VPORT_SCISSOR_11_TL +0x000282AC PA_SC_VPORT_SCISSOR_11_BR +0x000282B0 PA_SC_VPORT_SCISSOR_12_TL +0x000282B4 PA_SC_VPORT_SCISSOR_12_BR +0x000282B8 PA_SC_VPORT_SCISSOR_13_TL +0x000282BC PA_SC_VPORT_SCISSOR_13_BR +0x000282C0 PA_SC_VPORT_SCISSOR_14_TL +0x000282C4 PA_SC_VPORT_SCISSOR_14_BR +0x000282C8 PA_SC_VPORT_SCISSOR_15_TL +0x000282CC PA_SC_VPORT_SCISSOR_15_BR +0x000282D0 PA_SC_VPORT_ZMIN_0 +0x000282D4 PA_SC_VPORT_ZMAX_0 +0x000282D8 PA_SC_VPORT_ZMIN_1 +0x000282DC PA_SC_VPORT_ZMAX_1 +0x000282E0 PA_SC_VPORT_ZMIN_2 +0x000282E4 PA_SC_VPORT_ZMAX_2 +0x000282E8 PA_SC_VPORT_ZMIN_3 +0x000282EC PA_SC_VPORT_ZMAX_3 +0x000282F0 PA_SC_VPORT_ZMIN_4 +0x000282F4 PA_SC_VPORT_ZMAX_4 +0x000282F8 PA_SC_VPORT_ZMIN_5 +0x000282FC PA_SC_VPORT_ZMAX_5 +0x00028300 PA_SC_VPORT_ZMIN_6 +0x00028304 PA_SC_VPORT_ZMAX_6 +0x00028308 PA_SC_VPORT_ZMIN_7 +0x0002830C PA_SC_VPORT_ZMAX_7 +0x00028310 PA_SC_VPORT_ZMIN_8 +0x00028314 PA_SC_VPORT_ZMAX_8 +0x00028318 PA_SC_VPORT_ZMIN_9 +0x0002831C PA_SC_VPORT_ZMAX_9 +0x00028320 PA_SC_VPORT_ZMIN_10 +0x00028324 PA_SC_VPORT_ZMAX_10 +0x00028328 PA_SC_VPORT_ZMIN_11 +0x0002832C PA_SC_VPORT_ZMAX_11 +0x00028330 PA_SC_VPORT_ZMIN_12 +0x00028334 PA_SC_VPORT_ZMAX_12 +0x00028338 PA_SC_VPORT_ZMIN_13 +0x0002833C PA_SC_VPORT_ZMAX_13 +0x00028340 PA_SC_VPORT_ZMIN_14 +0x00028344 PA_SC_VPORT_ZMAX_14 +0x00028348 PA_SC_VPORT_ZMIN_15 +0x0002834C PA_SC_VPORT_ZMAX_15 +0x00028350 SX_MISC +0x00028380 SQ_VTX_SEMANTIC_0 +0x00028384 SQ_VTX_SEMANTIC_1 +0x00028388 SQ_VTX_SEMANTIC_2 +0x0002838C SQ_VTX_SEMANTIC_3 +0x00028390 SQ_VTX_SEMANTIC_4 +0x00028394 SQ_VTX_SEMANTIC_5 +0x00028398 SQ_VTX_SEMANTIC_6 +0x0002839C SQ_VTX_SEMANTIC_7 +0x000283A0 SQ_VTX_SEMANTIC_8 +0x000283A4 SQ_VTX_SEMANTIC_9 +0x000283A8 SQ_VTX_SEMANTIC_10 +0x000283AC SQ_VTX_SEMANTIC_11 +0x000283B0 SQ_VTX_SEMANTIC_12 +0x000283B4 SQ_VTX_SEMANTIC_13 +0x000283B8 SQ_VTX_SEMANTIC_14 +0x000283BC SQ_VTX_SEMANTIC_15 +0x000283C0 SQ_VTX_SEMANTIC_16 +0x000283C4 SQ_VTX_SEMANTIC_17 +0x000283C8 SQ_VTX_SEMANTIC_18 +0x000283CC SQ_VTX_SEMANTIC_19 +0x000283D0 SQ_VTX_SEMANTIC_20 +0x000283D4 SQ_VTX_SEMANTIC_21 +0x000283D8 SQ_VTX_SEMANTIC_22 +0x000283DC SQ_VTX_SEMANTIC_23 +0x000283E0 SQ_VTX_SEMANTIC_24 +0x000283E4 SQ_VTX_SEMANTIC_25 +0x000283E8 SQ_VTX_SEMANTIC_26 +0x000283EC SQ_VTX_SEMANTIC_27 +0x000283F0 SQ_VTX_SEMANTIC_28 +0x000283F4 SQ_VTX_SEMANTIC_29 +0x000283F8 SQ_VTX_SEMANTIC_30 +0x000283FC SQ_VTX_SEMANTIC_31 +0x00028400 VGT_MAX_VTX_INDX +0x00028404 VGT_MIN_VTX_INDX +0x00028408 VGT_INDX_OFFSET +0x0002840C VGT_MULTI_PRIM_IB_RESET_INDX +0x00028410 SX_ALPHA_TEST_CONTROL +0x00028414 CB_BLEND_RED +0x00028418 CB_BLEND_GREEN +0x0002841C CB_BLEND_BLUE +0x00028420 CB_BLEND_ALPHA +0x00028430 DB_STENCILREFMASK +0x00028434 DB_STENCILREFMASK_BF +0x00028438 SX_ALPHA_REF +0x0002843C PA_CL_VPORT_XSCALE_0 +0x00028440 PA_CL_VPORT_XOFFSET_0 +0x00028444 PA_CL_VPORT_YSCALE_0 +0x00028448 PA_CL_VPORT_YOFFSET_0 +0x0002844C PA_CL_VPORT_ZSCALE_0 +0x00028450 PA_CL_VPORT_ZOFFSET_0 +0x00028454 PA_CL_VPORT_XSCALE_1 +0x00028458 PA_CL_VPORT_XOFFSET_1 +0x0002845C PA_CL_VPORT_YSCALE_1 +0x00028460 PA_CL_VPORT_YOFFSET_1 +0x00028464 PA_CL_VPORT_ZSCALE_1 +0x00028468 PA_CL_VPORT_ZOFFSET_1 +0x0002846C PA_CL_VPORT_XSCALE_2 +0x00028470 PA_CL_VPORT_XOFFSET_2 +0x00028474 PA_CL_VPORT_YSCALE_2 +0x00028478 PA_CL_VPORT_YOFFSET_2 +0x0002847C PA_CL_VPORT_ZSCALE_2 +0x00028480 PA_CL_VPORT_ZOFFSET_2 +0x00028484 PA_CL_VPORT_XSCALE_3 +0x00028488 PA_CL_VPORT_XOFFSET_3 +0x0002848C PA_CL_VPORT_YSCALE_3 +0x00028490 PA_CL_VPORT_YOFFSET_3 +0x00028494 PA_CL_VPORT_ZSCALE_3 +0x00028498 PA_CL_VPORT_ZOFFSET_3 +0x0002849C PA_CL_VPORT_XSCALE_4 +0x000284A0 PA_CL_VPORT_XOFFSET_4 +0x000284A4 PA_CL_VPORT_YSCALE_4 +0x000284A8 PA_CL_VPORT_YOFFSET_4 +0x000284AC PA_CL_VPORT_ZSCALE_4 +0x000284B0 PA_CL_VPORT_ZOFFSET_4 +0x000284B4 PA_CL_VPORT_XSCALE_5 +0x000284B8 PA_CL_VPORT_XOFFSET_5 +0x000284BC PA_CL_VPORT_YSCALE_5 +0x000284C0 PA_CL_VPORT_YOFFSET_5 +0x000284C4 PA_CL_VPORT_ZSCALE_5 +0x000284C8 PA_CL_VPORT_ZOFFSET_5 +0x000284CC PA_CL_VPORT_XSCALE_6 +0x000284D0 PA_CL_VPORT_XOFFSET_6 +0x000284D4 PA_CL_VPORT_YSCALE_6 +0x000284D8 PA_CL_VPORT_YOFFSET_6 +0x000284DC PA_CL_VPORT_ZSCALE_6 +0x000284E0 PA_CL_VPORT_ZOFFSET_6 +0x000284E4 PA_CL_VPORT_XSCALE_7 +0x000284E8 PA_CL_VPORT_XOFFSET_7 +0x000284EC PA_CL_VPORT_YSCALE_7 +0x000284F0 PA_CL_VPORT_YOFFSET_7 +0x000284F4 PA_CL_VPORT_ZSCALE_7 +0x000284F8 PA_CL_VPORT_ZOFFSET_7 +0x000284FC PA_CL_VPORT_XSCALE_8 +0x00028500 PA_CL_VPORT_XOFFSET_8 +0x00028504 PA_CL_VPORT_YSCALE_8 +0x00028508 PA_CL_VPORT_YOFFSET_8 +0x0002850C PA_CL_VPORT_ZSCALE_8 +0x00028510 PA_CL_VPORT_ZOFFSET_8 +0x00028514 PA_CL_VPORT_XSCALE_9 +0x00028518 PA_CL_VPORT_XOFFSET_9 +0x0002851C PA_CL_VPORT_YSCALE_9 +0x00028520 PA_CL_VPORT_YOFFSET_9 +0x00028524 PA_CL_VPORT_ZSCALE_9 +0x00028528 PA_CL_VPORT_ZOFFSET_9 +0x0002852C PA_CL_VPORT_XSCALE_10 +0x00028530 PA_CL_VPORT_XOFFSET_10 +0x00028534 PA_CL_VPORT_YSCALE_10 +0x00028538 PA_CL_VPORT_YOFFSET_10 +0x0002853C PA_CL_VPORT_ZSCALE_10 +0x00028540 PA_CL_VPORT_ZOFFSET_10 +0x00028544 PA_CL_VPORT_XSCALE_11 +0x00028548 PA_CL_VPORT_XOFFSET_11 +0x0002854C PA_CL_VPORT_YSCALE_11 +0x00028550 PA_CL_VPORT_YOFFSET_11 +0x00028554 PA_CL_VPORT_ZSCALE_11 +0x00028558 PA_CL_VPORT_ZOFFSET_11 +0x0002855C PA_CL_VPORT_XSCALE_12 +0x00028560 PA_CL_VPORT_XOFFSET_12 +0x00028564 PA_CL_VPORT_YSCALE_12 +0x00028568 PA_CL_VPORT_YOFFSET_12 +0x0002856C PA_CL_VPORT_ZSCALE_12 +0x00028570 PA_CL_VPORT_ZOFFSET_12 +0x00028574 PA_CL_VPORT_XSCALE_13 +0x00028578 PA_CL_VPORT_XOFFSET_13 +0x0002857C PA_CL_VPORT_YSCALE_13 +0x00028580 PA_CL_VPORT_YOFFSET_13 +0x00028584 PA_CL_VPORT_ZSCALE_13 +0x00028588 PA_CL_VPORT_ZOFFSET_13 +0x0002858C PA_CL_VPORT_XSCALE_14 +0x00028590 PA_CL_VPORT_XOFFSET_14 +0x00028594 PA_CL_VPORT_YSCALE_14 +0x00028598 PA_CL_VPORT_YOFFSET_14 +0x0002859C PA_CL_VPORT_ZSCALE_14 +0x000285A0 PA_CL_VPORT_ZOFFSET_14 +0x000285A4 PA_CL_VPORT_XSCALE_15 +0x000285A8 PA_CL_VPORT_XOFFSET_15 +0x000285AC PA_CL_VPORT_YSCALE_15 +0x000285B0 PA_CL_VPORT_YOFFSET_15 +0x000285B4 PA_CL_VPORT_ZSCALE_15 +0x000285B8 PA_CL_VPORT_ZOFFSET_15 +0x000285BC PA_CL_UCP_0_X +0x000285C0 PA_CL_UCP_0_Y +0x000285C4 PA_CL_UCP_0_Z +0x000285C8 PA_CL_UCP_0_W +0x000285CC PA_CL_UCP_1_X +0x000285D0 PA_CL_UCP_1_Y +0x000285D4 PA_CL_UCP_1_Z +0x000285D8 PA_CL_UCP_1_W +0x000285DC PA_CL_UCP_2_X +0x000285E0 PA_CL_UCP_2_Y +0x000285E4 PA_CL_UCP_2_Z +0x000285E8 PA_CL_UCP_2_W +0x000285EC PA_CL_UCP_3_X +0x000285F0 PA_CL_UCP_3_Y +0x000285F4 PA_CL_UCP_3_Z +0x000285F8 PA_CL_UCP_3_W +0x000285FC PA_CL_UCP_4_X +0x00028600 PA_CL_UCP_4_Y +0x00028604 PA_CL_UCP_4_Z +0x00028608 PA_CL_UCP_4_W +0x0002860C PA_CL_UCP_5_X +0x00028610 PA_CL_UCP_5_Y +0x00028614 PA_CL_UCP_5_Z +0x00028618 PA_CL_UCP_5_W +0x0002861C SPI_VS_OUT_ID_0 +0x00028620 SPI_VS_OUT_ID_1 +0x00028624 SPI_VS_OUT_ID_2 +0x00028628 SPI_VS_OUT_ID_3 +0x0002862C SPI_VS_OUT_ID_4 +0x00028630 SPI_VS_OUT_ID_5 +0x00028634 SPI_VS_OUT_ID_6 +0x00028638 SPI_VS_OUT_ID_7 +0x0002863C SPI_VS_OUT_ID_8 +0x00028640 SPI_VS_OUT_ID_9 +0x00028644 SPI_PS_INPUT_CNTL_0 +0x00028648 SPI_PS_INPUT_CNTL_1 +0x0002864C SPI_PS_INPUT_CNTL_2 +0x00028650 SPI_PS_INPUT_CNTL_3 +0x00028654 SPI_PS_INPUT_CNTL_4 +0x00028658 SPI_PS_INPUT_CNTL_5 +0x0002865C SPI_PS_INPUT_CNTL_6 +0x00028660 SPI_PS_INPUT_CNTL_7 +0x00028664 SPI_PS_INPUT_CNTL_8 +0x00028668 SPI_PS_INPUT_CNTL_9 +0x0002866C SPI_PS_INPUT_CNTL_10 +0x00028670 SPI_PS_INPUT_CNTL_11 +0x00028674 SPI_PS_INPUT_CNTL_12 +0x00028678 SPI_PS_INPUT_CNTL_13 +0x0002867C SPI_PS_INPUT_CNTL_14 +0x00028680 SPI_PS_INPUT_CNTL_15 +0x00028684 SPI_PS_INPUT_CNTL_16 +0x00028688 SPI_PS_INPUT_CNTL_17 +0x0002868C SPI_PS_INPUT_CNTL_18 +0x00028690 SPI_PS_INPUT_CNTL_19 +0x00028694 SPI_PS_INPUT_CNTL_20 +0x00028698 SPI_PS_INPUT_CNTL_21 +0x0002869C SPI_PS_INPUT_CNTL_22 +0x000286A0 SPI_PS_INPUT_CNTL_23 +0x000286A4 SPI_PS_INPUT_CNTL_24 +0x000286A8 SPI_PS_INPUT_CNTL_25 +0x000286AC SPI_PS_INPUT_CNTL_26 +0x000286B0 SPI_PS_INPUT_CNTL_27 +0x000286B4 SPI_PS_INPUT_CNTL_28 +0x000286B8 SPI_PS_INPUT_CNTL_29 +0x000286BC SPI_PS_INPUT_CNTL_30 +0x000286C0 SPI_PS_INPUT_CNTL_31 +0x000286C4 SPI_VS_OUT_CONFIG +0x000286C8 SPI_THREAD_GROUPING +0x000286CC SPI_PS_IN_CONTROL_0 +0x000286D0 SPI_PS_IN_CONTROL_1 +0x000286D4 SPI_INTERP_CONTROL_0 +0x000286D8 SPI_INPUT_Z +0x000286DC SPI_FOG_CNTL +0x000286E0 SPI_BARYC_CNTL +0x000286E4 SPI_PS_IN_CONTROL_2 +0x000286E8 SPI_COMPUTE_INPUT_CNTL +0x000286EC SPI_COMPUTE_NUM_THREAD_X +0x000286F0 SPI_COMPUTE_NUM_THREAD_Y +0x000286F4 SPI_COMPUTE_NUM_THREAD_Z +0x000286F8 GDS_ADDR_SIZE +0x00028780 CB_BLEND0_CONTROL +0x00028784 CB_BLEND1_CONTROL +0x00028788 CB_BLEND2_CONTROL +0x0002878C CB_BLEND3_CONTROL +0x00028790 CB_BLEND4_CONTROL +0x00028794 CB_BLEND5_CONTROL +0x00028798 CB_BLEND6_CONTROL +0x0002879C CB_BLEND7_CONTROL +0x000287CC CS_COPY_STATE +0x000287D0 GFX_COPY_STATE +0x000287D4 PA_CL_POINT_X_RAD +0x000287D8 PA_CL_POINT_Y_RAD +0x000287DC PA_CL_POINT_SIZE +0x000287E0 PA_CL_POINT_CULL_RAD +0x00028808 CB_COLOR_CONTROL +0x0002880C DB_SHADER_CONTROL +0x00028810 PA_CL_CLIP_CNTL +0x00028814 PA_SU_SC_MODE_CNTL +0x00028818 PA_CL_VTE_CNTL +0x0002881C PA_CL_VS_OUT_CNTL +0x00028820 PA_CL_NANINF_CNTL +0x00028824 PA_SU_LINE_STIPPLE_CNTL +0x00028828 PA_SU_LINE_STIPPLE_SCALE +0x0002882C PA_SU_PRIM_FILTER_CNTL +0x00028838 SQ_DYN_GPR_RESOURCE_LIMIT_1 +0x00028844 SQ_PGM_RESOURCES_PS +0x00028848 SQ_PGM_RESOURCES_2_PS +0x0002884C SQ_PGM_EXPORTS_PS +0x0002885C SQ_PGM_RESOURCES_VS +0x00028860 SQ_PGM_RESOURCES_2_VS +0x00028878 SQ_PGM_RESOURCES_GS +0x0002887C SQ_PGM_RESOURCES_2_GS +0x00028890 SQ_PGM_RESOURCES_ES +0x00028894 SQ_PGM_RESOURCES_2_ES +0x000288A8 SQ_PGM_RESOURCES_FS +0x000288BC SQ_PGM_RESOURCES_HS +0x000288C0 SQ_PGM_RESOURCES_2_HS +0x000288D0 SQ_PGM_RESOURCES_LS +0x000288D4 SQ_PGM_RESOURCES_2_LS +0x000288E8 SQ_LDS_ALLOC +0x000288EC SQ_LDS_ALLOC_PS +0x000288F0 SQ_VTX_SEMANTIC_CLEAR +0x00028A00 PA_SU_POINT_SIZE +0x00028A04 PA_SU_POINT_MINMAX +0x00028A08 PA_SU_LINE_CNTL +0x00028A0C PA_SC_LINE_STIPPLE +0x00028A10 VGT_OUTPUT_PATH_CNTL +0x00028A14 VGT_HOS_CNTL +0x00028A18 VGT_HOS_MAX_TESS_LEVEL +0x00028A1C VGT_HOS_MIN_TESS_LEVEL +0x00028A20 VGT_HOS_REUSE_DEPTH +0x00028A24 VGT_GROUP_PRIM_TYPE +0x00028A28 VGT_GROUP_FIRST_DECR +0x00028A2C VGT_GROUP_DECR +0x00028A30 VGT_GROUP_VECT_0_CNTL +0x00028A34 VGT_GROUP_VECT_1_CNTL +0x00028A38 VGT_GROUP_VECT_0_FMT_CNTL +0x00028A3C VGT_GROUP_VECT_1_FMT_CNTL +0x00028A40 VGT_GS_MODE +0x00028A48 PA_SC_MODE_CNTL_0 +0x00028A4C PA_SC_MODE_CNTL_1 +0x00028A50 VGT_ENHANCE +0x00028A54 VGT_GS_PER_ES +0x00028A58 VGT_ES_PER_GS +0x00028A5C VGT_GS_PER_VS +0x00028A6C VGT_GS_OUT_PRIM_TYPE +0x00028A84 VGT_PRIMITIVEID_EN +0x00028A94 VGT_MULTI_PRIM_IB_RESET_EN +0x00028AA0 VGT_INSTANCE_STEP_RATE_0 +0x00028AA4 VGT_INSTANCE_STEP_RATE_1 +0x00028AB4 VGT_REUSE_OFF +0x00028AB8 VGT_VTX_CNT_EN +0x00028ABC DB_HTILE_SURFACE +0x00028AC0 DB_SRESULTS_COMPARE_STATE0 +0x00028AC4 DB_SRESULTS_COMPARE_STATE1 +0x00028AC8 DB_PRELOAD_CONTROL +0x00028B38 VGT_GS_MAX_VERT_OUT +0x00028B54 VGT_SHADER_STAGES_EN +0x00028B58 VGT_LS_HS_CONFIG +0x00028B5C VGT_LS_SIZE +0x00028B60 VGT_HS_SIZE +0x00028B64 VGT_LS_HS_ALLOC +0x00028B68 VGT_HS_PATCH_CONST +0x00028B6C VGT_TF_PARAM +0x00028B70 DB_ALPHA_TO_MASK +0x00028B74 VGT_DISPATCH_INITIATOR +0x00028B78 PA_SU_POLY_OFFSET_DB_FMT_CNTL +0x00028B7C PA_SU_POLY_OFFSET_CLAMP +0x00028B80 PA_SU_POLY_OFFSET_FRONT_SCALE +0x00028B84 PA_SU_POLY_OFFSET_FRONT_OFFSET +0x00028B88 PA_SU_POLY_OFFSET_BACK_SCALE +0x00028B8C PA_SU_POLY_OFFSET_BACK_OFFSET +0x00028B74 VGT_GS_INSTANCE_CNT +0x00028C00 PA_SC_LINE_CNTL +0x00028C08 PA_SU_VTX_CNTL +0x00028C0C PA_CL_GB_VERT_CLIP_ADJ +0x00028C10 PA_CL_GB_VERT_DISC_ADJ +0x00028C14 PA_CL_GB_HORZ_CLIP_ADJ +0x00028C18 PA_CL_GB_HORZ_DISC_ADJ +0x00028C1C PA_SC_AA_SAMPLE_LOCS_0 +0x00028C20 PA_SC_AA_SAMPLE_LOCS_1 +0x00028C24 PA_SC_AA_SAMPLE_LOCS_2 +0x00028C28 PA_SC_AA_SAMPLE_LOCS_3 +0x00028C2C PA_SC_AA_SAMPLE_LOCS_4 +0x00028C30 PA_SC_AA_SAMPLE_LOCS_5 +0x00028C34 PA_SC_AA_SAMPLE_LOCS_6 +0x00028C38 PA_SC_AA_SAMPLE_LOCS_7 +0x00028C3C PA_SC_AA_MASK +0x00028C8C CB_COLOR0_CLEAR_WORD0 +0x00028C90 CB_COLOR0_CLEAR_WORD1 +0x00028C94 CB_COLOR0_CLEAR_WORD2 +0x00028C98 CB_COLOR0_CLEAR_WORD3 +0x00028CC8 CB_COLOR1_CLEAR_WORD0 +0x00028CCC CB_COLOR1_CLEAR_WORD1 +0x00028CD0 CB_COLOR1_CLEAR_WORD2 +0x00028CD4 CB_COLOR1_CLEAR_WORD3 +0x00028D04 CB_COLOR2_CLEAR_WORD0 +0x00028D08 CB_COLOR2_CLEAR_WORD1 +0x00028D0C CB_COLOR2_CLEAR_WORD2 +0x00028D10 CB_COLOR2_CLEAR_WORD3 +0x00028D40 CB_COLOR3_CLEAR_WORD0 +0x00028D44 CB_COLOR3_CLEAR_WORD1 +0x00028D48 CB_COLOR3_CLEAR_WORD2 +0x00028D4C CB_COLOR3_CLEAR_WORD3 +0x00028D7C CB_COLOR4_CLEAR_WORD0 +0x00028D80 CB_COLOR4_CLEAR_WORD1 +0x00028D84 CB_COLOR4_CLEAR_WORD2 +0x00028D88 CB_COLOR4_CLEAR_WORD3 +0x00028DB8 CB_COLOR5_CLEAR_WORD0 +0x00028DBC CB_COLOR5_CLEAR_WORD1 +0x00028DC0 CB_COLOR5_CLEAR_WORD2 +0x00028DC4 CB_COLOR5_CLEAR_WORD3 +0x00028DF4 CB_COLOR6_CLEAR_WORD0 +0x00028DF8 CB_COLOR6_CLEAR_WORD1 +0x00028DFC CB_COLOR6_CLEAR_WORD2 +0x00028E00 CB_COLOR6_CLEAR_WORD3 +0x00028E30 CB_COLOR7_CLEAR_WORD0 +0x00028E34 CB_COLOR7_CLEAR_WORD1 +0x00028E38 CB_COLOR7_CLEAR_WORD2 +0x00028E3C CB_COLOR7_CLEAR_WORD3 +0x00028F80 SQ_ALU_CONST_BUFFER_SIZE_HS_0 +0x00028F84 SQ_ALU_CONST_BUFFER_SIZE_HS_1 +0x00028F88 SQ_ALU_CONST_BUFFER_SIZE_HS_2 +0x00028F8C SQ_ALU_CONST_BUFFER_SIZE_HS_3 +0x00028F90 SQ_ALU_CONST_BUFFER_SIZE_HS_4 +0x00028F94 SQ_ALU_CONST_BUFFER_SIZE_HS_5 +0x00028F98 SQ_ALU_CONST_BUFFER_SIZE_HS_6 +0x00028F9C SQ_ALU_CONST_BUFFER_SIZE_HS_7 +0x00028FA0 SQ_ALU_CONST_BUFFER_SIZE_HS_8 +0x00028FA4 SQ_ALU_CONST_BUFFER_SIZE_HS_9 +0x00028FA8 SQ_ALU_CONST_BUFFER_SIZE_HS_10 +0x00028FAC SQ_ALU_CONST_BUFFER_SIZE_HS_11 +0x00028FB0 SQ_ALU_CONST_BUFFER_SIZE_HS_12 +0x00028FB4 SQ_ALU_CONST_BUFFER_SIZE_HS_13 +0x00028FB8 SQ_ALU_CONST_BUFFER_SIZE_HS_14 +0x00028FBC SQ_ALU_CONST_BUFFER_SIZE_HS_15 +0x00028FC0 SQ_ALU_CONST_BUFFER_SIZE_LS_0 +0x00028FC4 SQ_ALU_CONST_BUFFER_SIZE_LS_1 +0x00028FC8 SQ_ALU_CONST_BUFFER_SIZE_LS_2 +0x00028FCC SQ_ALU_CONST_BUFFER_SIZE_LS_3 +0x00028FD0 SQ_ALU_CONST_BUFFER_SIZE_LS_4 +0x00028FD4 SQ_ALU_CONST_BUFFER_SIZE_LS_5 +0x00028FD8 SQ_ALU_CONST_BUFFER_SIZE_LS_6 +0x00028FDC SQ_ALU_CONST_BUFFER_SIZE_LS_7 +0x00028FE0 SQ_ALU_CONST_BUFFER_SIZE_LS_8 +0x00028FE4 SQ_ALU_CONST_BUFFER_SIZE_LS_9 +0x00028FE8 SQ_ALU_CONST_BUFFER_SIZE_LS_10 +0x00028FEC SQ_ALU_CONST_BUFFER_SIZE_LS_11 +0x00028FF0 SQ_ALU_CONST_BUFFER_SIZE_LS_12 +0x00028FF4 SQ_ALU_CONST_BUFFER_SIZE_LS_13 +0x00028FF8 SQ_ALU_CONST_BUFFER_SIZE_LS_14 +0x00028FFC SQ_ALU_CONST_BUFFER_SIZE_LS_15 +0x0003CFF0 SQ_VTX_BASE_VTX_LOC +0x0003CFF4 SQ_VTX_START_INST_LOC +0x0003FF00 SQ_TEX_SAMPLER_CLEAR +0x0003FF04 SQ_TEX_RESOURCE_CLEAR +0x0003FF08 SQ_LOOP_BOOL_CLEAR -- GitLab From 483d67ff0a208b43f0b97fca91d3a142afaba7fa Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Mon, 10 May 2010 03:51:02 -0300 Subject: [PATCH 351/842] V4L/DVB: bw-qcam: convert to V4L2 Note: due to lack of hardware I was not able to test this conversion. But it is pretty straightforward, so I do not expect any problems. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/Kconfig | 2 +- drivers/media/video/bw-qcam.c | 759 ++++++++++++++++++---------------- drivers/media/video/bw-qcam.h | 69 ---- 3 files changed, 415 insertions(+), 415 deletions(-) delete mode 100644 drivers/media/video/bw-qcam.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index ad9e6f9c22e9..42d198d5a87e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -646,7 +646,7 @@ config VIDEO_PMS config VIDEO_BWQCAM tristate "Quickcam BW Video For Linux" - depends on PARPORT && VIDEO_V4L1 + depends on PARPORT && VIDEO_V4L2 help Say Y have if you the black and white version of the QuickCam camera. See the next option for the color version. diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 3c9e754d73a0..935e0c9a9674 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -66,19 +66,58 @@ OTHER DEALINGS IN THE SOFTWARE. #include <linux/delay.h> #include <linux/errno.h> #include <linux/fs.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/parport.h> #include <linux/sched.h> -#include <linux/videodev.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> +#include <linux/version.h> +#include <linux/videodev2.h> #include <linux/mutex.h> #include <asm/uaccess.h> - -#include "bw-qcam.h" +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-device.h> + +/* One from column A... */ +#define QC_NOTSET 0 +#define QC_UNIDIR 1 +#define QC_BIDIR 2 +#define QC_SERIAL 3 + +/* ... and one from column B */ +#define QC_ANY 0x00 +#define QC_FORCE_UNIDIR 0x10 +#define QC_FORCE_BIDIR 0x20 +#define QC_FORCE_SERIAL 0x30 +/* in the port_mode member */ + +#define QC_MODE_MASK 0x07 +#define QC_FORCE_MASK 0x70 + +#define MAX_HEIGHT 243 +#define MAX_WIDTH 336 + +/* Bit fields for status flags */ +#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ + +struct qcam { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct pardevice *pdev; + struct parport *pport; + struct mutex lock; + int width, height; + int bpp; + int mode; + int contrast, brightness, whitebal; + int port_mode; + int transfer_scale; + int top, left; + int status; + unsigned int saved_bits; + unsigned long in_use; +}; static unsigned int maxpoll = 250; /* Maximum busy-loop count for qcam I/O */ static unsigned int yieldlines = 4; /* Yield after this many during capture */ @@ -93,22 +132,26 @@ module_param(video_nr, int, 0); * immediately attempt to initialize qcam */ module_param(force_init, int, 0); -static inline int read_lpstatus(struct qcam_device *q) +#define MAX_CAMS 4 +static struct qcam *qcams[MAX_CAMS]; +static unsigned int num_cams; + +static inline int read_lpstatus(struct qcam *q) { return parport_read_status(q->pport); } -static inline int read_lpdata(struct qcam_device *q) +static inline int read_lpdata(struct qcam *q) { return parport_read_data(q->pport); } -static inline void write_lpdata(struct qcam_device *q, int d) +static inline void write_lpdata(struct qcam *q, int d) { parport_write_data(q->pport, d); } -static inline void write_lpcontrol(struct qcam_device *q, int d) +static void write_lpcontrol(struct qcam *q, int d) { if (d & 0x20) { /* Set bidirectional mode to reverse (data in) */ @@ -124,126 +167,11 @@ static inline void write_lpcontrol(struct qcam_device *q, int d) parport_write_control(q->pport, d); } -static int qc_waithand(struct qcam_device *q, int val); -static int qc_command(struct qcam_device *q, int command); -static int qc_readparam(struct qcam_device *q); -static int qc_setscanmode(struct qcam_device *q); -static int qc_readbytes(struct qcam_device *q, char buffer[]); - -static struct video_device qcam_template; - -static int qc_calibrate(struct qcam_device *q) -{ - /* - * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 - * The white balance is an individiual value for each - * quickcam. - */ - - int value; - int count = 0; - - qc_command(q, 27); /* AutoAdjustOffset */ - qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ - - /* GetOffset (33) will read 255 until autocalibration */ - /* is finished. After that, a value of 1-254 will be */ - /* returned. */ - - do { - qc_command(q, 33); - value = qc_readparam(q); - mdelay(1); - schedule(); - count++; - } while (value == 0xff && count < 2048); - - q->whitebal = value; - return value; -} - -/* Initialize the QuickCam driver control structure. This is where - * defaults are set for people who don't have a config file.*/ - -static struct qcam_device *qcam_init(struct parport *port) -{ - struct qcam_device *q; - - q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); - if (q == NULL) - return NULL; - - q->pport = port; - q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, - NULL, 0, NULL); - if (q->pdev == NULL) { - printk(KERN_ERR "bw-qcam: couldn't register for %s.\n", - port->name); - kfree(q); - return NULL; - } - - memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); - - mutex_init(&q->lock); - - q->port_mode = (QC_ANY | QC_NOTSET); - q->width = 320; - q->height = 240; - q->bpp = 4; - q->transfer_scale = 2; - q->contrast = 192; - q->brightness = 180; - q->whitebal = 105; - q->top = 1; - q->left = 14; - q->mode = -1; - q->status = QC_PARAM_CHANGE; - return q; -} - - -/* qc_command is probably a bit of a misnomer -- it's used to send - * bytes *to* the camera. Generally, these bytes are either commands - * or arguments to commands, so the name fits, but it still bugs me a - * bit. See the documentation for a list of commands. */ - -static int qc_command(struct qcam_device *q, int command) -{ - int n1, n2; - int cmd; - - write_lpdata(q, command); - write_lpcontrol(q, 6); - - n1 = qc_waithand(q, 1); - - write_lpcontrol(q, 0xe); - n2 = qc_waithand(q, 0); - - cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); - return cmd; -} - -static int qc_readparam(struct qcam_device *q) -{ - int n1, n2; - int cmd; - - write_lpcontrol(q, 6); - n1 = qc_waithand(q, 1); - - write_lpcontrol(q, 0xe); - n2 = qc_waithand(q, 0); - - cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); - return cmd; -} /* qc_waithand busy-waits for a handshake signal from the QuickCam. * Almost all communication with the camera requires handshaking. */ -static int qc_waithand(struct qcam_device *q, int val) +static int qc_waithand(struct qcam *q, int val) { int status; int runs = 0; @@ -286,7 +214,7 @@ static int qc_waithand(struct qcam_device *q, int val) * (bit 3 of status register). It also returns the last value read, * since this data is useful. */ -static unsigned int qc_waithand2(struct qcam_device *q, int val) +static unsigned int qc_waithand2(struct qcam *q, int val) { unsigned int status; int runs = 0; @@ -309,6 +237,43 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val) return status; } +/* qc_command is probably a bit of a misnomer -- it's used to send + * bytes *to* the camera. Generally, these bytes are either commands + * or arguments to commands, so the name fits, but it still bugs me a + * bit. See the documentation for a list of commands. */ + +static int qc_command(struct qcam *q, int command) +{ + int n1, n2; + int cmd; + + write_lpdata(q, command); + write_lpcontrol(q, 6); + + n1 = qc_waithand(q, 1); + + write_lpcontrol(q, 0xe); + n2 = qc_waithand(q, 0); + + cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); + return cmd; +} + +static int qc_readparam(struct qcam *q) +{ + int n1, n2; + int cmd; + + write_lpcontrol(q, 6); + n1 = qc_waithand(q, 1); + + write_lpcontrol(q, 0xe); + n2 = qc_waithand(q, 0); + + cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); + return cmd; +} + /* Try to detect a QuickCam. It appears to flash the upper 4 bits of the status register at 5-10 Hz. This is only used in the autoprobe @@ -317,7 +282,7 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val) almost completely safe, while their method screws up my printer if I plug it in before the camera. */ -static int qc_detect(struct qcam_device *q) +static int qc_detect(struct qcam *q) { int reg, lastreg; int count = 0; @@ -358,41 +323,6 @@ static int qc_detect(struct qcam_device *q) } } - -/* Reset the QuickCam. This uses the same sequence the Windows - * QuickPic program uses. Someone with a bi-directional port should - * check that bi-directional mode is detected right, and then - * implement bi-directional mode in qc_readbyte(). */ - -static void qc_reset(struct qcam_device *q) -{ - switch (q->port_mode & QC_FORCE_MASK) { - case QC_FORCE_UNIDIR: - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; - break; - - case QC_FORCE_BIDIR: - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; - break; - - case QC_ANY: - write_lpcontrol(q, 0x20); - write_lpdata(q, 0x75); - - if (read_lpdata(q) != 0x75) - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; - else - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; - break; - } - - write_lpcontrol(q, 0xb); - udelay(250); - write_lpcontrol(q, 0xe); - qc_setscanmode(q); /* in case port_mode changed */ -} - - /* Decide which scan mode to use. There's no real requirement that * the scanmode match the resolution in q->height and q-> width -- the * camera takes the picture at the resolution specified in the @@ -402,7 +332,7 @@ static void qc_reset(struct qcam_device *q) * returned. If the scan is smaller, then the rest of the image * returned contains garbage. */ -static int qc_setscanmode(struct qcam_device *q) +static int qc_setscanmode(struct qcam *q) { int old_mode = q->mode; @@ -442,10 +372,45 @@ static int qc_setscanmode(struct qcam_device *q) } +/* Reset the QuickCam. This uses the same sequence the Windows + * QuickPic program uses. Someone with a bi-directional port should + * check that bi-directional mode is detected right, and then + * implement bi-directional mode in qc_readbyte(). */ + +static void qc_reset(struct qcam *q) +{ + switch (q->port_mode & QC_FORCE_MASK) { + case QC_FORCE_UNIDIR: + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; + break; + + case QC_FORCE_BIDIR: + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; + break; + + case QC_ANY: + write_lpcontrol(q, 0x20); + write_lpdata(q, 0x75); + + if (read_lpdata(q) != 0x75) + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; + else + q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; + break; + } + + write_lpcontrol(q, 0xb); + udelay(250); + write_lpcontrol(q, 0xe); + qc_setscanmode(q); /* in case port_mode changed */ +} + + + /* Reset the QuickCam and program for brightness, contrast, * white-balance, and resolution. */ -static void qc_set(struct qcam_device *q) +static void qc_set(struct qcam *q) { int val; int val2; @@ -499,7 +464,7 @@ static void qc_set(struct qcam_device *q) the supplied buffer. It returns the number of bytes read, or -1 on error. */ -static inline int qc_readbytes(struct qcam_device *q, char buffer[]) +static inline int qc_readbytes(struct qcam *q, char buffer[]) { int ret = 1; unsigned int hi, lo; @@ -590,7 +555,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[]) * n=2^(bit depth)-1. Ask me for more details if you don't understand * this. */ -static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len) +static long qc_capture(struct qcam *q, char __user *buf, unsigned long len) { int i, j, k, yield; int bytes; @@ -674,171 +639,206 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le * Video4linux interfacing */ -static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg) +static int qcam_querycap(struct file *file, void *priv, + struct v4l2_capability *vcap) { - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; - strcpy(b->name, "Quickcam"); - b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES|VID_TYPE_MONOCHROME; - b->channels = 1; - b->audios = 0; - b->maxwidth = 320; - b->maxheight = 240; - b->minwidth = 80; - b->minheight = 60; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - /* Good question.. its composite or SVHS so.. */ - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Camera"); - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; - if (v->tuner) - return -EINVAL; - strcpy(v->name, "Format"); - v->rangelow = 0; - v->rangehigh = 0; - v->flags = 0; - v->mode = VIDEO_MODE_AUTO; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; - if (v->tuner) - return -EINVAL; - if (v->mode != VIDEO_MODE_AUTO) - return -EINVAL; - return 0; - } - case VIDIOCGPICT: - { - struct video_picture *p = arg; - p->colour = 0x8000; - p->hue = 0x8000; - p->brightness = qcam->brightness << 8; - p->contrast = qcam->contrast << 8; - p->whiteness = qcam->whitebal << 8; - p->depth = qcam->bpp; - p->palette = VIDEO_PALETTE_GREY; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture *p = arg; - if (p->palette != VIDEO_PALETTE_GREY) - return -EINVAL; - if (p->depth != 4 && p->depth != 6) - return -EINVAL; - - /* - * Now load the camera. - */ - - qcam->brightness = p->brightness >> 8; - qcam->contrast = p->contrast >> 8; - qcam->whitebal = p->whiteness >> 8; - qcam->bpp = p->depth; - - mutex_lock(&qcam->lock); - qc_setscanmode(qcam); - mutex_unlock(&qcam->lock); - qcam->status |= QC_PARAM_CHANGE; + struct qcam *qcam = video_drvdata(file); - return 0; - } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; - if (vw->height < 60 || vw->height > 240) - return -EINVAL; - if (vw->width < 80 || vw->width > 320) - return -EINVAL; - - qcam->width = 320; - qcam->height = 240; - qcam->transfer_scale = 4; - - if (vw->width >= 160 && vw->height >= 120) - qcam->transfer_scale = 2; - if (vw->width >= 320 && vw->height >= 240) { - qcam->width = 320; - qcam->height = 240; - qcam->transfer_scale = 1; - } - mutex_lock(&qcam->lock); - qc_setscanmode(qcam); - mutex_unlock(&qcam->lock); + strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); + strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card)); + strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); + vcap->version = KERNEL_VERSION(0, 0, 2); + vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; + return 0; +} - /* We must update the camera before we grab. We could - just have changed the grab size */ - qcam->status |= QC_PARAM_CHANGE; +static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + if (vin->index > 0) + return -EINVAL; + strlcpy(vin->name, "Camera", sizeof(vin->name)); + vin->type = V4L2_INPUT_TYPE_CAMERA; + vin->audioset = 0; + vin->tuner = 0; + vin->std = 0; + vin->status = 0; + return 0; +} - /* Ok we figured out what to use from our wide choice */ - return 0; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; +static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) +{ + *inp = 0; + return 0; +} - memset(vw, 0, sizeof(*vw)); - vw->width = qcam->width / qcam->transfer_scale; - vw->height = qcam->height / qcam->transfer_scale; - return 0; - } - case VIDIOCKEY: - return 0; - case VIDIOCCAPTURE: - case VIDIOCGFBUF: - case VIDIOCSFBUF: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; +static int qcam_s_input(struct file *file, void *fh, unsigned int inp) +{ + return (inp > 0) ? -EINVAL : 0; +} + +static int qcam_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 180); + case V4L2_CID_CONTRAST: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192); + case V4L2_CID_GAMMA: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 105); + } + return -EINVAL; +} + +static int qcam_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = qcam->brightness; + break; + case V4L2_CID_CONTRAST: + ctrl->value = qcam->contrast; + break; + case V4L2_CID_GAMMA: + ctrl->value = qcam->whitebal; + break; default: - return -ENOIOCTLCMD; + ret = -EINVAL; + break; } + return ret; +} + +static int qcam_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + mutex_lock(&qcam->lock); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + qcam->brightness = ctrl->value; + break; + case V4L2_CID_CONTRAST: + qcam->contrast = ctrl->value; + break; + case V4L2_CID_GAMMA: + qcam->whitebal = ctrl->value; + break; + default: + ret = -EINVAL; + break; + } + if (ret == 0) { + qc_setscanmode(qcam); + qcam->status |= QC_PARAM_CHANGE; + } + mutex_unlock(&qcam->lock); + return ret; +} + +static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + pix->width = qcam->width / qcam->transfer_scale; + pix->height = qcam->height / qcam->transfer_scale; + pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = qcam->width; + pix->sizeimage = qcam->width * qcam->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + if (pix->height <= 60 || pix->width <= 80) { + pix->height = 60; + pix->width = 80; + } else if (pix->height <= 120 || pix->width <= 160) { + pix->height = 120; + pix->width = 160; + } else { + pix->height = 240; + pix->width = 320; + } + if (pix->pixelformat != V4L2_PIX_FMT_Y4 && + pix->pixelformat != V4L2_PIX_FMT_Y6) + pix->pixelformat = V4L2_PIX_FMT_Y4; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = pix->width; + pix->sizeimage = pix->width * pix->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + int ret = qcam_try_fmt_vid_cap(file, fh, fmt); + + if (ret) + return ret; + qcam->width = 320; + qcam->height = 240; + if (pix->height == 60) + qcam->transfer_scale = 4; + else if (pix->height == 120) + qcam->transfer_scale = 2; + else + qcam->transfer_scale = 1; + if (pix->pixelformat == V4L2_PIX_FMT_Y6) + qcam->bpp = 6; + else + qcam->bpp = 4; + + mutex_lock(&qcam->lock); + qc_setscanmode(qcam); + /* We must update the camera before we grab. We could + just have changed the grab size */ + qcam->status |= QC_PARAM_CHANGE; + mutex_unlock(&qcam->lock); return 0; } -static long qcam_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) +static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { - return video_usercopy(file, cmd, arg, qcam_do_ioctl); + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "4-Bit Monochrome", V4L2_PIX_FMT_Y4, + { 0, 0, 0, 0 } + }, + { 0, 0, 0, + "6-Bit Monochrome", V4L2_PIX_FMT_Y6, + { 0, 0, 0, 0 } + }, + }; + enum v4l2_buf_type type = fmt->type; + + if (fmt->index > 1) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; } static ssize_t qcam_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct video_device *v = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)v; + struct qcam *qcam = video_drvdata(file); int len; parport_claim_or_block(qcam->pdev); @@ -858,43 +858,112 @@ static ssize_t qcam_read(struct file *file, char __user *buf, return len; } -static int qcam_exclusive_open(struct file *file) +static const struct v4l2_file_operations qcam_fops = { + .owner = THIS_MODULE, + .ioctl = video_ioctl2, + .read = qcam_read, +}; + +static const struct v4l2_ioctl_ops qcam_ioctl_ops = { + .vidioc_querycap = qcam_querycap, + .vidioc_g_input = qcam_g_input, + .vidioc_s_input = qcam_s_input, + .vidioc_enum_input = qcam_enum_input, + .vidioc_queryctrl = qcam_queryctrl, + .vidioc_g_ctrl = qcam_g_ctrl, + .vidioc_s_ctrl = qcam_s_ctrl, + .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, +}; + +/* Initialize the QuickCam driver control structure. This is where + * defaults are set for people who don't have a config file.*/ + +static struct qcam *qcam_init(struct parport *port) { - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; + struct qcam *qcam; + struct v4l2_device *v4l2_dev; + + qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL); + if (qcam == NULL) + return NULL; + + v4l2_dev = &qcam->v4l2_dev; + strlcpy(v4l2_dev->name, "bw-qcam", sizeof(v4l2_dev->name)); - return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0; + if (v4l2_device_register(NULL, v4l2_dev) < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return NULL; + } + + qcam->pport = port; + qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, + NULL, 0, NULL); + if (qcam->pdev == NULL) { + v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); + kfree(qcam); + return NULL; + } + + strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name)); + qcam->vdev.v4l2_dev = v4l2_dev; + qcam->vdev.fops = &qcam_fops; + qcam->vdev.ioctl_ops = &qcam_ioctl_ops; + qcam->vdev.release = video_device_release_empty; + video_set_drvdata(&qcam->vdev, qcam); + + mutex_init(&qcam->lock); + + qcam->port_mode = (QC_ANY | QC_NOTSET); + qcam->width = 320; + qcam->height = 240; + qcam->bpp = 4; + qcam->transfer_scale = 2; + qcam->contrast = 192; + qcam->brightness = 180; + qcam->whitebal = 105; + qcam->top = 1; + qcam->left = 14; + qcam->mode = -1; + qcam->status = QC_PARAM_CHANGE; + return qcam; } -static int qcam_exclusive_release(struct file *file) +static int qc_calibrate(struct qcam *q) { - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; + /* + * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 + * The white balance is an individual value for each + * quickcam. + */ - clear_bit(0, &qcam->in_use); - return 0; -} + int value; + int count = 0; -static const struct v4l2_file_operations qcam_fops = { - .owner = THIS_MODULE, - .open = qcam_exclusive_open, - .release = qcam_exclusive_release, - .ioctl = qcam_ioctl, - .read = qcam_read, -}; -static struct video_device qcam_template = { - .name = "Connectix Quickcam", - .fops = &qcam_fops, - .release = video_device_release_empty, -}; + qc_command(q, 27); /* AutoAdjustOffset */ + qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ -#define MAX_CAMS 4 -static struct qcam_device *qcams[MAX_CAMS]; -static unsigned int num_cams; + /* GetOffset (33) will read 255 until autocalibration */ + /* is finished. After that, a value of 1-254 will be */ + /* returned. */ + + do { + qc_command(q, 33); + value = qc_readparam(q); + mdelay(1); + schedule(); + count++; + } while (value == 0xff && count < 2048); + + q->whitebal = value; + return value; +} static int init_bwqcam(struct parport *port) { - struct qcam_device *qcam; + struct qcam *qcam; if (num_cams == MAX_CAMS) { printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); @@ -919,7 +988,7 @@ static int init_bwqcam(struct parport *port) parport_release(qcam->pdev); - printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name); + v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name); if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { parport_unregister_device(qcam->pdev); @@ -932,7 +1001,7 @@ static int init_bwqcam(struct parport *port) return 0; } -static void close_bwqcam(struct qcam_device *qcam) +static void close_bwqcam(struct qcam *qcam) { video_unregister_device(&qcam->vdev); parport_unregister_device(qcam->pdev); @@ -983,7 +1052,7 @@ static void bwqcam_detach(struct parport *port) { int i; for (i = 0; i < num_cams; i++) { - struct qcam_device *qcam = qcams[i]; + struct qcam *qcam = qcams[i]; if (qcam && qcam->pdev->port == port) { qcams[i] = NULL; close_bwqcam(qcam); diff --git a/drivers/media/video/bw-qcam.h b/drivers/media/video/bw-qcam.h deleted file mode 100644 index 8a60c5de0935..000000000000 --- a/drivers/media/video/bw-qcam.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Video4Linux bw-qcam driver - * - * Derived from code.. - */ - -/****************************************************************** - -Copyright (C) 1996 by Scott Laird - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -******************************************************************/ - -/* One from column A... */ -#define QC_NOTSET 0 -#define QC_UNIDIR 1 -#define QC_BIDIR 2 -#define QC_SERIAL 3 - -/* ... and one from column B */ -#define QC_ANY 0x00 -#define QC_FORCE_UNIDIR 0x10 -#define QC_FORCE_BIDIR 0x20 -#define QC_FORCE_SERIAL 0x30 -/* in the port_mode member */ - -#define QC_MODE_MASK 0x07 -#define QC_FORCE_MASK 0x70 - -#define MAX_HEIGHT 243 -#define MAX_WIDTH 336 - -/* Bit fields for status flags */ -#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ - -struct qcam_device { - struct video_device vdev; - struct pardevice *pdev; - struct parport *pport; - struct mutex lock; - int width, height; - int bpp; - int mode; - int contrast, brightness, whitebal; - int port_mode; - int transfer_scale; - int top, left; - int status; - unsigned int saved_bits; - unsigned long in_use; -}; -- GitLab From d71964fb9731412ce1f86cd7d9b71f1f94a04b0d Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Mon, 10 May 2010 03:55:25 -0300 Subject: [PATCH 352/842] V4L/DVB: c-qcam: convert to V4L2 Note: due to lack of hardware this conversion is untested. However, it is pretty straightforward so I do not expect any problems. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/Kconfig | 2 +- drivers/media/video/c-qcam.c | 634 ++++++++++++++++++----------------- 2 files changed, 331 insertions(+), 305 deletions(-) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 42d198d5a87e..bdbc9d305419 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -656,7 +656,7 @@ config VIDEO_BWQCAM config VIDEO_CQCAM tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)" - depends on EXPERIMENTAL && PARPORT && VIDEO_V4L1 + depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2 help This is the video4linux driver for the colour version of the Connectix QuickCam. If you have one of these cameras, say Y here, diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 8f1dd88b32a6..6e4b19698c13 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -33,15 +33,17 @@ #include <linux/mm.h> #include <linux/parport.h> #include <linux/sched.h> -#include <linux/videodev.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> #include <linux/mutex.h> #include <linux/jiffies.h> - +#include <linux/version.h> +#include <linux/videodev2.h> #include <asm/uaccess.h> +#include <media/v4l2-device.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> -struct qcam_device { +struct qcam { + struct v4l2_device v4l2_dev; struct video_device vdev; struct pardevice *pdev; struct parport *pport; @@ -51,7 +53,6 @@ struct qcam_device { int contrast, brightness, whitebal; int top, left; unsigned int bidirectional; - unsigned long in_use; struct mutex lock; }; @@ -68,33 +69,45 @@ struct qcam_device { #define QC_DECIMATION_2 2 #define QC_DECIMATION_4 4 -#define BANNER "Colour QuickCam for Video4Linux v0.05" +#define BANNER "Colour QuickCam for Video4Linux v0.06" static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; static int probe = 2; static int force_rgb; static int video_nr = -1; -static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i) +/* FIXME: parport=auto would never have worked, surely? --RR */ +MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n" + "probe=<0|1|2> for camera detection method\n" + "force_rgb=<0|1> for RGB data format (default BGR)"); +module_param_array(parport, int, NULL, 0); +module_param(probe, int, 0); +module_param(force_rgb, bool, 0); +module_param(video_nr, int, 0); + +static struct qcam *qcams[MAX_CAMS]; +static unsigned int num_cams; + +static inline void qcam_set_ack(struct qcam *qcam, unsigned int i) { /* note: the QC specs refer to the PCAck pin by voltage, not software level. PC ports have builtin inverters. */ parport_frob_control(qcam->pport, 8, i ? 8 : 0); } -static inline unsigned int qcam_ready1(struct qcam_device *qcam) +static inline unsigned int qcam_ready1(struct qcam *qcam) { return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0; } -static inline unsigned int qcam_ready2(struct qcam_device *qcam) +static inline unsigned int qcam_ready2(struct qcam *qcam) { return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0; } -static unsigned int qcam_await_ready1(struct qcam_device *qcam, - int value) +static unsigned int qcam_await_ready1(struct qcam *qcam, int value) { + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; unsigned long oldjiffies = jiffies; unsigned int i; @@ -112,14 +125,15 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam, } /* Probably somebody pulled the plug out. Not much we can do. */ - printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value, + v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value, parport_read_status(qcam->pport), parport_read_control(qcam->pport)); return 1; } -static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) +static unsigned int qcam_await_ready2(struct qcam *qcam, int value) { + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; unsigned long oldjiffies = jiffies; unsigned int i; @@ -137,14 +151,14 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) } /* Probably somebody pulled the plug out. Not much we can do. */ - printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value, + v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value, parport_read_status(qcam->pport), parport_read_control(qcam->pport), parport_read_data(qcam->pport)); return 1; } -static int qcam_read_data(struct qcam_device *qcam) +static int qcam_read_data(struct qcam *qcam) { unsigned int idata; @@ -159,21 +173,22 @@ static int qcam_read_data(struct qcam_device *qcam) return idata; } -static int qcam_write_data(struct qcam_device *qcam, unsigned int data) +static int qcam_write_data(struct qcam *qcam, unsigned int data) { + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; unsigned int idata; parport_write_data(qcam->pport, data); idata = qcam_read_data(qcam); if (data != idata) { - printk(KERN_WARNING "cqcam: sent %x but received %x\n", data, + v4l2_warn(v4l2_dev, "sent %x but received %x\n", data, idata); return 1; } return 0; } -static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data) +static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data) { if (qcam_write_data(qcam, cmd)) return -1; @@ -182,14 +197,14 @@ static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned return 0; } -static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd) +static inline int qcam_get(struct qcam *qcam, unsigned int cmd) { if (qcam_write_data(qcam, cmd)) return -1; return qcam_read_data(qcam); } -static int qc_detect(struct qcam_device *qcam) +static int qc_detect(struct qcam *qcam) { unsigned int stat, ostat, i, count = 0; @@ -246,7 +261,7 @@ static int qc_detect(struct qcam_device *qcam) return 0; } -static void qc_reset(struct qcam_device *qcam) +static void qc_reset(struct qcam *qcam) { parport_write_control(qcam->pport, 0xc); parport_write_control(qcam->pport, 0x8); @@ -258,55 +273,55 @@ static void qc_reset(struct qcam_device *qcam) /* Reset the QuickCam and program for brightness, contrast, * white-balance, and resolution. */ -static void qc_setup(struct qcam_device *q) +static void qc_setup(struct qcam *qcam) { - qc_reset(q); + qc_reset(qcam); /* Set the brightness. */ - qcam_set(q, 11, q->brightness); + qcam_set(qcam, 11, qcam->brightness); /* Set the height and width. These refer to the actual CCD area *before* applying the selected decimation. */ - qcam_set(q, 17, q->ccd_height); - qcam_set(q, 19, q->ccd_width / 2); + qcam_set(qcam, 17, qcam->ccd_height); + qcam_set(qcam, 19, qcam->ccd_width / 2); /* Set top and left. */ - qcam_set(q, 0xd, q->top); - qcam_set(q, 0xf, q->left); + qcam_set(qcam, 0xd, qcam->top); + qcam_set(qcam, 0xf, qcam->left); /* Set contrast and white balance. */ - qcam_set(q, 0x19, q->contrast); - qcam_set(q, 0x1f, q->whitebal); + qcam_set(qcam, 0x19, qcam->contrast); + qcam_set(qcam, 0x1f, qcam->whitebal); /* Set the speed. */ - qcam_set(q, 45, 2); + qcam_set(qcam, 45, 2); } /* Read some bytes from the camera and put them in the buffer. nbytes should be a multiple of 3, because bidirectional mode gives us three bytes at a time. */ -static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes) +static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes) { unsigned int bytes = 0; - qcam_set_ack(q, 0); - if (q->bidirectional) { + qcam_set_ack(qcam, 0); + if (qcam->bidirectional) { /* It's a bidirectional port */ while (bytes < nbytes) { unsigned int lo1, hi1, lo2, hi2; unsigned char r, g, b; - if (qcam_await_ready2(q, 1)) + if (qcam_await_ready2(qcam, 1)) return bytes; - lo1 = parport_read_data(q->pport) >> 1; - hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; - qcam_set_ack(q, 1); - if (qcam_await_ready2(q, 0)) + lo1 = parport_read_data(qcam->pport) >> 1; + hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; + qcam_set_ack(qcam, 1); + if (qcam_await_ready2(qcam, 0)) return bytes; - lo2 = parport_read_data(q->pport) >> 1; - hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; - qcam_set_ack(q, 0); + lo2 = parport_read_data(qcam->pport) >> 1; + hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; + qcam_set_ack(qcam, 0); r = lo1 | ((hi1 & 1) << 7); g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1); b = lo2 | ((hi2 & 1) << 7); @@ -328,14 +343,14 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u while (bytes < nbytes) { unsigned int hi, lo; - if (qcam_await_ready1(q, 1)) + if (qcam_await_ready1(qcam, 1)) return bytes; - hi = (parport_read_status(q->pport) & 0xf0); - qcam_set_ack(q, 1); - if (qcam_await_ready1(q, 0)) + hi = (parport_read_status(qcam->pport) & 0xf0); + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) return bytes; - lo = (parport_read_status(q->pport) & 0xf0); - qcam_set_ack(q, 0); + lo = (parport_read_status(qcam->pport) & 0xf0); + qcam_set_ack(qcam, 0); /* flip some bits */ rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; if (i >= 2) { @@ -361,10 +376,11 @@ get_fragment: #define BUFSZ 150 -static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len) +static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len) { + struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; unsigned lines, pixelsperline, bitsperxfer; - unsigned int is_bi_dir = q->bidirectional; + unsigned int is_bi_dir = qcam->bidirectional; size_t wantlen, outptr = 0; char tmpbuf[BUFSZ]; @@ -373,10 +389,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le /* Wait for camera to become ready */ for (;;) { - int i = qcam_get(q, 41); + int i = qcam_get(qcam, 41); if (i == -1) { - qc_setup(q); + qc_setup(qcam); return -EIO; } if ((i & 0x80) == 0) @@ -384,25 +400,25 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le schedule(); } - if (qcam_set(q, 7, (q->mode | (is_bi_dir ? 1 : 0)) + 1)) + if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1)) return -EIO; - lines = q->height; - pixelsperline = q->width; + lines = qcam->height; + pixelsperline = qcam->width; bitsperxfer = (is_bi_dir) ? 24 : 8; if (is_bi_dir) { /* Turn the port around */ - parport_data_reverse(q->pport); + parport_data_reverse(qcam->pport); mdelay(3); - qcam_set_ack(q, 0); - if (qcam_await_ready1(q, 1)) { - qc_setup(q); + qcam_set_ack(qcam, 0); + if (qcam_await_ready1(qcam, 1)) { + qc_setup(qcam); return -EIO; } - qcam_set_ack(q, 1); - if (qcam_await_ready1(q, 0)) { - qc_setup(q); + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) { + qc_setup(qcam); return -EIO; } } @@ -413,7 +429,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le size_t t, s; s = (wantlen > BUFSZ) ? BUFSZ : wantlen; - t = qcam_read_bytes(q, tmpbuf, s); + t = qcam_read_bytes(qcam, tmpbuf, s); if (outptr < len) { size_t sz = len - outptr; @@ -432,10 +448,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le len = outptr; if (wantlen) { - printk(KERN_ERR "qcam: short read.\n"); + v4l2_err(v4l2_dev, "short read.\n"); if (is_bi_dir) - parport_data_forward(q->pport); - qc_setup(q); + parport_data_forward(qcam->pport); + qc_setup(qcam); return len; } @@ -443,49 +459,49 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le int l; do { - l = qcam_read_bytes(q, tmpbuf, 3); + l = qcam_read_bytes(qcam, tmpbuf, 3); cond_resched(); } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); if (force_rgb) { if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - printk(KERN_ERR "qcam: bad EOF\n"); + v4l2_err(v4l2_dev, "bad EOF\n"); } else { if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) - printk(KERN_ERR "qcam: bad EOF\n"); + v4l2_err(v4l2_dev, "bad EOF\n"); } - qcam_set_ack(q, 0); - if (qcam_await_ready1(q, 1)) { - printk(KERN_ERR "qcam: no ack after EOF\n"); - parport_data_forward(q->pport); - qc_setup(q); + qcam_set_ack(qcam, 0); + if (qcam_await_ready1(qcam, 1)) { + v4l2_err(v4l2_dev, "no ack after EOF\n"); + parport_data_forward(qcam->pport); + qc_setup(qcam); return len; } - parport_data_forward(q->pport); + parport_data_forward(qcam->pport); mdelay(3); - qcam_set_ack(q, 1); - if (qcam_await_ready1(q, 0)) { - printk(KERN_ERR "qcam: no ack to port turnaround\n"); - qc_setup(q); + qcam_set_ack(qcam, 1); + if (qcam_await_ready1(qcam, 0)) { + v4l2_err(v4l2_dev, "no ack to port turnaround\n"); + qc_setup(qcam); return len; } } else { int l; do { - l = qcam_read_bytes(q, tmpbuf, 1); + l = qcam_read_bytes(qcam, tmpbuf, 1); cond_resched(); } while (l && tmpbuf[0] == 0x7e); - l = qcam_read_bytes(q, tmpbuf + 1, 2); + l = qcam_read_bytes(qcam, tmpbuf + 1, 2); if (force_rgb) { if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - printk(KERN_ERR "qcam: bad EOF\n"); + v4l2_err(v4l2_dev, "bad EOF\n"); } else { if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) - printk(KERN_ERR "qcam: bad EOF\n"); + v4l2_err(v4l2_dev, "bad EOF\n"); } } - qcam_write_data(q, 0); + qcam_write_data(qcam, 0); return len; } @@ -493,184 +509,202 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le * Video4linux interfacing */ -static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg) +static int qcam_querycap(struct file *file, void *priv, + struct v4l2_capability *vcap) { - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; + struct qcam *qcam = video_drvdata(file); - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; + strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); + strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card)); + strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); + vcap->version = KERNEL_VERSION(0, 0, 3); + vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; + return 0; +} - strcpy(b->name, "Quickcam"); - b->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; - b->channels = 1; - b->audios = 0; - b->maxwidth = 320; - b->maxheight = 240; - b->minwidth = 80; - b->minheight = 60; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - /* Good question.. its composite or SVHS so.. */ - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Camera"); - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; +static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) +{ + if (vin->index > 0) + return -EINVAL; + strlcpy(vin->name, "Camera", sizeof(vin->name)); + vin->type = V4L2_INPUT_TYPE_CAMERA; + vin->audioset = 0; + vin->tuner = 0; + vin->std = 0; + vin->status = 0; + return 0; +} - if (v->channel != 0) - return -EINVAL; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; - - if (v->tuner) - return -EINVAL; - memset(v, 0, sizeof(*v)); - strcpy(v->name, "Format"); - v->mode = VIDEO_MODE_AUTO; - return 0; +static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) +{ + *inp = 0; + return 0; +} + +static int qcam_s_input(struct file *file, void *fh, unsigned int inp) +{ + return (inp > 0) ? -EINVAL : 0; +} + +static int qcam_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240); + case V4L2_CID_CONTRAST: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192); + case V4L2_CID_GAMMA: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); } - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; - - if (v->tuner) - return -EINVAL; - if (v->mode != VIDEO_MODE_AUTO) - return -EINVAL; - return 0; + return -EINVAL; +} + +static int qcam_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = qcam->brightness; + break; + case V4L2_CID_CONTRAST: + ctrl->value = qcam->contrast; + break; + case V4L2_CID_GAMMA: + ctrl->value = qcam->whitebal; + break; + default: + ret = -EINVAL; + break; } - case VIDIOCGPICT: - { - struct video_picture *p = arg; - - p->colour = 0x8000; - p->hue = 0x8000; - p->brightness = qcam->brightness << 8; - p->contrast = qcam->contrast << 8; - p->whiteness = qcam->whitebal << 8; - p->depth = 24; - p->palette = VIDEO_PALETTE_RGB24; - return 0; + return ret; +} + +static int qcam_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct qcam *qcam = video_drvdata(file); + int ret = 0; + + mutex_lock(&qcam->lock); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + qcam->brightness = ctrl->value; + break; + case V4L2_CID_CONTRAST: + qcam->contrast = ctrl->value; + break; + case V4L2_CID_GAMMA: + qcam->whitebal = ctrl->value; + break; + default: + ret = -EINVAL; + break; } - case VIDIOCSPICT: - { - struct video_picture *p = arg; - - /* - * Sanity check args - */ - if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24) - return -EINVAL; - - /* - * Now load the camera. - */ - qcam->brightness = p->brightness >> 8; - qcam->contrast = p->contrast >> 8; - qcam->whitebal = p->whiteness >> 8; - - mutex_lock(&qcam->lock); + if (ret == 0) { parport_claim_or_block(qcam->pdev); qc_setup(qcam); parport_release(qcam->pdev); - mutex_unlock(&qcam->lock); - return 0; } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; - if (vw->height < 60 || vw->height > 240) - return -EINVAL; - if (vw->width < 80 || vw->width > 320) - return -EINVAL; - - qcam->width = 80; - qcam->height = 60; - qcam->mode = QC_DECIMATION_4; + mutex_unlock(&qcam->lock); + return ret; +} - if (vw->width >= 160 && vw->height >= 120) { - qcam->width = 160; - qcam->height = 120; - qcam->mode = QC_DECIMATION_2; - } - if (vw->width >= 320 && vw->height >= 240) { - qcam->width = 320; - qcam->height = 240; - qcam->mode = QC_DECIMATION_1; - } - qcam->mode |= QC_MILLIONS; -#if 0 - if (vw->width >= 640 && vw->height >= 480) { - qcam->width = 640; - qcam->height = 480; - qcam->mode = QC_BILLIONS | QC_DECIMATION_1; - } -#endif - /* Ok we figured out what to use from our - wide choice */ - mutex_lock(&qcam->lock); - parport_claim_or_block(qcam->pdev); - qc_setup(qcam); - parport_release(qcam->pdev); - mutex_unlock(&qcam->lock); - return 0; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; - memset(vw, 0, sizeof(*vw)); - vw->width = qcam->width; - vw->height = qcam->height; - return 0; +static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + pix->width = qcam->width; + pix->height = qcam->height; + pix->pixelformat = V4L2_PIX_FMT_RGB24; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = 3 * qcam->width; + pix->sizeimage = 3 * qcam->width * qcam->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + if (pix->height < 60 || pix->width < 80) { + pix->height = 60; + pix->width = 80; + } else if (pix->height < 120 || pix->width < 160) { + pix->height = 120; + pix->width = 160; + } else { + pix->height = 240; + pix->width = 320; } - case VIDIOCKEY: - return 0; - case VIDIOCCAPTURE: - case VIDIOCGFBUF: - case VIDIOCSFBUF: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; + pix->pixelformat = V4L2_PIX_FMT_RGB24; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = 3 * pix->width; + pix->sizeimage = 3 * pix->width * pix->height; + /* Just a guess */ + pix->colorspace = V4L2_COLORSPACE_SRGB; + return 0; +} + +static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct qcam *qcam = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + int ret = qcam_try_fmt_vid_cap(file, fh, fmt); + + if (ret) + return ret; + switch (pix->height) { + case 60: + qcam->mode = QC_DECIMATION_4; + break; + case 120: + qcam->mode = QC_DECIMATION_2; + break; default: - return -ENOIOCTLCMD; + qcam->mode = QC_DECIMATION_1; + break; } + + mutex_lock(&qcam->lock); + qcam->mode |= QC_MILLIONS; + qcam->height = pix->height; + qcam->width = pix->width; + parport_claim_or_block(qcam->pdev); + qc_setup(qcam); + parport_release(qcam->pdev); + mutex_unlock(&qcam->lock); return 0; } -static long qcam_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) +static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { - return video_usercopy(file, cmd, arg, qcam_do_ioctl); + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "RGB 8:8:8", V4L2_PIX_FMT_RGB24, + { 0, 0, 0, 0 } + }, + }; + enum v4l2_buf_type type = fmt->type; + + if (fmt->index > 0) + return -EINVAL; + + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; } static ssize_t qcam_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct video_device *v = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)v; + struct qcam *qcam = video_drvdata(file); int len; mutex_lock(&qcam->lock); @@ -682,81 +716,80 @@ static ssize_t qcam_read(struct file *file, char __user *buf, return len; } -static int qcam_exclusive_open(struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; - - return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0; -} - -static int qcam_exclusive_release(struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct qcam_device *qcam = (struct qcam_device *)dev; - - clear_bit(0, &qcam->in_use); - return 0; -} - -/* video device template */ static const struct v4l2_file_operations qcam_fops = { .owner = THIS_MODULE, - .open = qcam_exclusive_open, - .release = qcam_exclusive_release, - .ioctl = qcam_ioctl, + .ioctl = video_ioctl2, .read = qcam_read, }; -static struct video_device qcam_template = { - .name = "Colour QuickCam", - .fops = &qcam_fops, - .release = video_device_release_empty, +static const struct v4l2_ioctl_ops qcam_ioctl_ops = { + .vidioc_querycap = qcam_querycap, + .vidioc_g_input = qcam_g_input, + .vidioc_s_input = qcam_s_input, + .vidioc_enum_input = qcam_enum_input, + .vidioc_queryctrl = qcam_queryctrl, + .vidioc_g_ctrl = qcam_g_ctrl, + .vidioc_s_ctrl = qcam_s_ctrl, + .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, }; /* Initialize the QuickCam driver control structure. */ -static struct qcam_device *qcam_init(struct parport *port) +static struct qcam *qcam_init(struct parport *port) { - struct qcam_device *q; + struct qcam *qcam; + struct v4l2_device *v4l2_dev; - q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); - if (q == NULL) + qcam = kzalloc(sizeof(*qcam), GFP_KERNEL); + if (qcam == NULL) return NULL; - q->pport = port; - q->pdev = parport_register_device(port, "c-qcam", NULL, NULL, + v4l2_dev = &qcam->v4l2_dev; + strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name)); + + if (v4l2_device_register(NULL, v4l2_dev) < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return NULL; + } + + qcam->pport = port; + qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL, NULL, 0, NULL); - q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0; + qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0; - if (q->pdev == NULL) { - printk(KERN_ERR "c-qcam: couldn't register for %s.\n", - port->name); - kfree(q); + if (qcam->pdev == NULL) { + v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); + kfree(qcam); return NULL; } - memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); - - mutex_init(&q->lock); - q->width = q->ccd_width = 320; - q->height = q->ccd_height = 240; - q->mode = QC_MILLIONS | QC_DECIMATION_1; - q->contrast = 192; - q->brightness = 240; - q->whitebal = 128; - q->top = 1; - q->left = 14; - return q; + strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name)); + qcam->vdev.v4l2_dev = v4l2_dev; + qcam->vdev.fops = &qcam_fops; + qcam->vdev.ioctl_ops = &qcam_ioctl_ops; + qcam->vdev.release = video_device_release_empty; + video_set_drvdata(&qcam->vdev, qcam); + + mutex_init(&qcam->lock); + qcam->width = qcam->ccd_width = 320; + qcam->height = qcam->ccd_height = 240; + qcam->mode = QC_MILLIONS | QC_DECIMATION_1; + qcam->contrast = 192; + qcam->brightness = 240; + qcam->whitebal = 128; + qcam->top = 1; + qcam->left = 14; + return qcam; } -static struct qcam_device *qcams[MAX_CAMS]; -static unsigned int num_cams; - static int init_cqcam(struct parport *port) { - struct qcam_device *qcam; + struct qcam *qcam; + struct v4l2_device *v4l2_dev; if (parport[0] != -1) { /* The user gave specific instructions */ @@ -777,6 +810,8 @@ static int init_cqcam(struct parport *port) if (qcam == NULL) return -ENODEV; + v4l2_dev = &qcam->v4l2_dev; + parport_claim_or_block(qcam->pdev); qc_reset(qcam); @@ -793,14 +828,14 @@ static int init_cqcam(struct parport *port) parport_release(qcam->pdev); if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { - printk(KERN_ERR "Unable to register Colour QuickCam on %s\n", + v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n", qcam->pport->name); parport_unregister_device(qcam->pdev); kfree(qcam); return -ENODEV; } - printk(KERN_INFO "%s: Colour QuickCam found on %s\n", + v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n", video_device_node_name(&qcam->vdev), qcam->pport->name); qcams[num_cams++] = qcam; @@ -808,7 +843,7 @@ static int init_cqcam(struct parport *port) return 0; } -static void close_cqcam(struct qcam_device *qcam) +static void close_cqcam(struct qcam *qcam) { video_unregister_device(&qcam->vdev); parport_unregister_device(qcam->pdev); @@ -833,7 +868,7 @@ static struct parport_driver cqcam_driver = { static int __init cqcam_init(void) { - printk(BANNER "\n"); + printk(KERN_INFO BANNER "\n"); return parport_register_driver(&cqcam_driver); } @@ -852,14 +887,5 @@ MODULE_AUTHOR("Philip Blundell <philb@gnu.org>"); MODULE_DESCRIPTION(BANNER); MODULE_LICENSE("GPL"); -/* FIXME: parport=auto would never have worked, surely? --RR */ -MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n" - "probe=<0|1|2> for camera detection method\n" - "force_rgb=<0|1> for RGB data format (default BGR)"); -module_param_array(parport, int, NULL, 0); -module_param(probe, int, 0); -module_param(force_rgb, bool, 0); -module_param(video_nr, int, 0); - module_init(cqcam_init); module_exit(cqcam_cleanup); -- GitLab From e4425eab6b2da050bae55cffa01e573767a819a1 Mon Sep 17 00:00:00 2001 From: Abylay Ospan <aospan@netup.ru> Date: Wed, 12 May 2010 04:24:09 -0300 Subject: [PATCH 353/842] V4L/DVB: cx23885: Check register errors Fix kernel Oops when number of NetUP Dual DVB-S2-CI cards more than DVB_MAX_ADAPTERS limit. [mchehab@redhat.com: move the return to the proper place] Signed-off-by: Abylay Ospan <aospan@netup.ru> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/cx23885/cx23885-dvb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 9e1460828b2f..0a199d774d9b 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -991,6 +991,8 @@ static int dvb_register(struct cx23885_tsport *port) ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, &dev->pci->dev, adapter_nr, 0, cx23885_dvb_fe_ioctl_override); + if (!ret) + return ret; /* init CI & MAC */ switch (dev->board) { -- GitLab From c641a18969178ac1649e022156c85adb7c889451 Mon Sep 17 00:00:00 2001 From: Mike Isely <isely@pobox.com> Date: Sat, 15 May 2010 00:07:04 -0300 Subject: [PATCH 354/842] V4L/DVB: pvrusb2: Fix Gotview hardware support pvrusb2: Fix RF tuner problem with gotview hardware - this bug was introduced when switching over to the subdev model of driver control Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 6bc16c13ccef..3092abfd66a2 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -117,6 +117,7 @@ static const struct pvr2_device_desc pvr2_device_24xxx = { static const struct pvr2_device_client_desc pvr2_cli_gotview_2[] = { { .module_id = PVR2_CLIENT_ID_CX25840 }, { .module_id = PVR2_CLIENT_ID_TUNER }, + { .module_id = PVR2_CLIENT_ID_DEMOD }, }; static const struct pvr2_device_desc pvr2_device_gotview_2 = { -- GitLab From 6861800c1512ca8452c5f350a7c0af445ece773b Mon Sep 17 00:00:00 2001 From: Mike Isely <isely@pobox.com> Date: Sat, 15 May 2010 00:09:47 -0300 Subject: [PATCH 355/842] V4L/DVB: pvrusb2: Avoid using stack allocated buffers when performing USB I/O Drivers shouldn't assume that the stack is DMA-safe. [mchehab@redhat.com: fix patch description] Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 301ef197d038..d13232d51823 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -4084,12 +4084,20 @@ void pvr2_hdw_device_reset(struct pvr2_hdw *hdw) void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val) { - char da[1]; + char *da; unsigned int pipe; int ret; if (!hdw->usb_dev) return; + da = kmalloc(16, GFP_KERNEL); + + if (da == NULL) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Unable to allocate memory to control CPU reset"); + return; + } + pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val); da[0] = val ? 0x01 : 0x00; @@ -4103,6 +4111,8 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val) "cpureset_assert(%d) error=%d",val,ret); pvr2_hdw_render_useless(hdw); } + + kfree(da); } -- GitLab From 8fd0444817e557568d8bddd77828d9ae0d606e04 Mon Sep 17 00:00:00 2001 From: Mike Isely <isely@pobox.com> Date: Sat, 15 May 2010 00:13:35 -0300 Subject: [PATCH 356/842] V4L/DVB: pvrusb2: New feature to mark specific hardware support as experimental This adds a flag in the device attribute structure which can be used to mark support for a particular device as experimental. Any devices flagged in this way, when encountered at run-time, will generate a warning message to the kernel log. Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/pvrusb2/pvrusb2-devattr.h | 5 +++++ drivers/media/video/pvrusb2/pvrusb2-hdw.c | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index e5b9594eb5f6..273c8d4b3853 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -177,6 +177,11 @@ struct pvr2_device_desc { unsigned int flag_has_composite:1; /* Has composite input */ unsigned int flag_has_svideo:1; /* Has s-video input */ unsigned int flag_fx2_16kb:1; /* 16KB FX2 firmware OK here */ + + /* If this driver is considered experimental, i.e. not all aspects + are working correctly and/or it is untested, mark that fact + with this flag. */ + unsigned int flag_is_experimental:1; }; extern struct usb_device_id pvr2_device_table[]; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index d13232d51823..2c3f845c3e5c 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2459,6 +2459,19 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw,hdw_desc->description); pvr2_trace(PVR2_TRACE_INFO, "Hardware description: %s", hdw_desc->description); + if (hdw_desc->flag_is_experimental) { + pvr2_trace(PVR2_TRACE_INFO, "**********"); + pvr2_trace(PVR2_TRACE_INFO, + "WARNING: Support for this device (%s) is" + " experimental.", hdw_desc->description); + pvr2_trace(PVR2_TRACE_INFO, + "Important functionality might not be" + " entirely working."); + pvr2_trace(PVR2_TRACE_INFO, + "Please consider contacting the driver author to" + " help with further stabilization of the driver."); + pvr2_trace(PVR2_TRACE_INFO, "**********"); + } if (!hdw) goto fail; init_timer(&hdw->quiescent_timer); -- GitLab From d72baad3f0e59041d68db7524537046e3a4121a2 Mon Sep 17 00:00:00 2001 From: Mike Isely <isely@pobox.com> Date: Sat, 15 May 2010 00:15:38 -0300 Subject: [PATCH 357/842] V4L/DVB: pvrusb2: Fix kernel oops at device unregistration pvrusb2: Fix oops caused by touching deleted memory after unregistration. This bug was introduced when we had started using video_device_node_name() - that function was being called potentially after the underlying structure (referenced by that function) had been deleted. The fix rearranges things slightly so that the function is called before destruction takes place. Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 5ffa0d2b0b0d..aaafa0398fd5 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -883,6 +883,17 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) { struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw; enum pvr2_config cfg = dip->config; + char msg[80]; + unsigned int mcnt; + + /* Construct the unregistration message *before* we actually + perform the unregistration step. By doing it this way we don't + have to worry about potentially touching deleted resources. */ + mcnt = scnprintf(msg, sizeof(msg) - 1, + "pvrusb2: unregistered device %s [%s]", + video_device_node_name(&dip->devbase), + pvr2_config_get_name(cfg)); + msg[mcnt] = 0; pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1); @@ -894,9 +905,7 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) are gone. */ video_unregister_device(&dip->devbase); - printk(KERN_INFO "pvrusb2: unregistered device %s [%s]\n", - video_device_node_name(&dip->devbase), - pvr2_config_get_name(cfg)); + printk(KERN_INFO "%s\n", msg); } -- GitLab From 28c4a5e6d32410f7c0b8fa9cc52eac424229f10a Mon Sep 17 00:00:00 2001 From: Mike Isely <isely@pobox.com> Date: Sat, 15 May 2010 00:23:46 -0300 Subject: [PATCH 358/842] V4L/DVB: pvrusb2: Fix USB parent device reference count pvrusb2: Correctly reference count pointer to parent USB device when linked from sysfs interface. This is technically a pretty nasty problem, however as far as I know nobody had been getting burned by it (yet). Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 71f50565f637..bf478510a3b1 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -511,6 +511,7 @@ static void pvr2_sysfs_release(struct device *class_dev) static void class_dev_destroy(struct pvr2_sysfs *sfp) { + struct device *dev; if (!sfp->class_dev) return; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC pvr2_sysfs_tear_down_debugifc(sfp); @@ -542,6 +543,9 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) } pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); dev_set_drvdata(sfp->class_dev, NULL); + dev = sfp->class_dev->parent; + sfp->class_dev->parent = NULL; + put_device(dev); device_unregister(sfp->class_dev); sfp->class_dev = NULL; } @@ -631,10 +635,11 @@ static void class_dev_create(struct pvr2_sysfs *sfp, pvr2_sysfs_trace("Creating class_dev id=%p",class_dev); class_dev->class = &class_ptr->class; + dev_set_name(class_dev, "%s", pvr2_hdw_get_device_identifier(sfp->channel.hdw)); - class_dev->parent = &usb_dev->dev; + class_dev->parent = get_device(&usb_dev->dev); sfp->class_dev = class_dev; dev_set_drvdata(class_dev, sfp); @@ -775,7 +780,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) struct pvr2_sysfs_class *clp; clp = kzalloc(sizeof(*clp),GFP_KERNEL); if (!clp) return clp; - pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp); + pvr2_sysfs_trace("Creating and registering pvr2_sysfs_class id=%p", + clp); clp->class.name = "pvrusb2"; clp->class.class_release = pvr2_sysfs_class_release; clp->class.dev_release = pvr2_sysfs_release; @@ -791,6 +797,7 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) { + pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp); class_unregister(&clp->class); } -- GitLab From 7a6ac34848226e315e0d70333bb4ab83190d9f1d Mon Sep 17 00:00:00 2001 From: Mike Isely <isely@pobox.com> Date: Sat, 15 May 2010 00:28:44 -0300 Subject: [PATCH 359/842] V4L/DVB: pvrusb2: Fix minor internal array allocation pvrusb2: Need one extra attribute slot allocated so that worst case still has a trailing null pointer. This wasn't causing visible symptoms; it was found through inspection while investigating other issues. Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index bf478510a3b1..3d7e5aab547f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -74,7 +74,7 @@ struct pvr2_sysfs_ctl_item { int ctl_id; struct pvr2_sysfs *chptr; struct pvr2_sysfs_ctl_item *item_next; - struct attribute *attr_gen[7]; + struct attribute *attr_gen[8]; struct attribute_group grp; int created_ok; char name[80]; -- GitLab From e3a5ee73e7223cda78f2770572c5ad01928496d6 Mon Sep 17 00:00:00 2001 From: Mike Isely <isely@pobox.com> Date: Sat, 15 May 2010 00:30:29 -0300 Subject: [PATCH 360/842] V4L/DVB: pvrusb2: Fix kernel oops on device tear-down pvrusb2: Delete sysfs class device as the _very_ last step, after we're sure that all driver contexts have gone away first. This is important because it appears that there isn't any protection from a struct device instance reference a deleted struct class instance. The assumption in the kernel code appears to be that the class instance is assumed to be around for the life of the device. So we can't let the class instance go away until all referencing device instances are gone; this is ensured by delaying removal of the class instance until after the driver contexts have all gone away. This bug has been present for a very long time but it didn't apparently become malignant until recently (probably because of other changes in the kernel). Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/pvrusb2/pvrusb2-main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index eeacd0f67855..2254194aad57 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -153,12 +153,12 @@ static void __exit pvr_exit(void) usb_deregister(&pvr_driver); + pvr2_context_global_done(); + #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS pvr2_sysfs_class_destroy(class_ptr); #endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ - pvr2_context_global_done(); - pvr2_trace(PVR2_TRACE_INIT,"pvr_exit complete"); } -- GitLab From 040000ae7d27d9229959f4a4e9d67cf6c93e8ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= <moinejf@free.fr> Date: Fri, 7 May 2010 15:27:44 -0300 Subject: [PATCH 361/842] V4L/DVB: gspca - sonixb: Have 0c45:602e handled by sonixb instead of sn9c102 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change fixes the Debian Bug #579332 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=579332 Signed-off-by: Jean-François Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/gspca/sonixb.c | 2 -- drivers/media/video/sn9c102/sn9c102_devtable.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 785eeb4c2014..95354a339e3d 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1453,9 +1453,7 @@ static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)}, -#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)}, -#endif {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)}, diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 522ba3f4c285..b6643ca7656a 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -62,8 +62,8 @@ static const struct usb_device_id sn9c102_id_table[] = { #if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */ -#endif { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* SN9C103 */ { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, -- GitLab From 6804675e3644361b1d509cac5427bab42a0bc6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= <moinejf@free.fr> Date: Fri, 7 May 2010 15:35:08 -0300 Subject: [PATCH 362/842] V4L/DVB: gspca - sonixj: Add information about some potential JPEG webcams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/gspca/sonixj.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index bb923efb75bd..4bb6479dc920 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -3022,16 +3022,18 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */ /* {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */ /* {USB_DEVICE(0x0c45, 0x60cc), BS(SN9C105, HV7131GP)}, */ +/* {USB_DEVICE(0x0c45, 0x60ce), BS(SN9C105, SP80708)}, */ {USB_DEVICE(0x0c45, 0x60ec), BS(SN9C105, MO4000)}, /* {USB_DEVICE(0x0c45, 0x60ef), BS(SN9C105, ICM105C)}, */ /* {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */ +/* {USB_DEVICE(0x0c45, 0x60f2), BS(SN9C105, OV7660)}, */ {USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)}, {USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)}, #endif {USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)}, /*sn9c128*/ -/* {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, P1030xC)}, */ +/* {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)}, * / GC0305*/ /* {USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */ {USB_DEVICE(0x0c45, 0x610a), BS(SN9C120, OV7648)}, /*sn9c128*/ {USB_DEVICE(0x0c45, 0x610b), BS(SN9C120, OV7660)}, /*sn9c128*/ @@ -3058,6 +3060,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)}, {USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)}, {USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)}, /*sn9c120b*/ + /* or GC0305 / GC0307 */ {USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)}, /*sn9c120b*/ {USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)}, /*sn9c120b*/ {USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)}, /*sn9c120b*/ -- GitLab From c4f95d84b8dedf28adda927561f7e09b1d5ea626 Mon Sep 17 00:00:00 2001 From: Warren Bosworth Focke <wbfocke@gmail.com> Date: Fri, 7 May 2010 15:40:04 -0300 Subject: [PATCH 363/842] V4L/DVB: gspca - sonixj: Add webcam 0c45:60ce MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Warren Bosworth Focke <wbfocke@gmail.com> Signed-off-by: Jean-François Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- Documentation/video4linux/gspca.txt | 1 + drivers/media/video/gspca/sonixj.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 8f3f5d33327c..f13eb036c439 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -290,6 +290,7 @@ sonixb 0c45:602e Genius VideoCam Messenger sonixj 0c45:6040 Speed NVC 350K sonixj 0c45:607c Sonix sn9c102p Hv7131R sonixj 0c45:60c0 Sangha Sn535 +sonixj 0c45:60ce USB-PC-Camera-168 (TALK-5067) sonixj 0c45:60ec SN9C105+MO4000 sonixj 0c45:60fb Surfer NoName sonixj 0c45:60fc LG-LIC300 diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 4bb6479dc920..176c5b3d5e6f 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -3022,7 +3022,7 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */ /* {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */ /* {USB_DEVICE(0x0c45, 0x60cc), BS(SN9C105, HV7131GP)}, */ -/* {USB_DEVICE(0x0c45, 0x60ce), BS(SN9C105, SP80708)}, */ + {USB_DEVICE(0x0c45, 0x60ce), BS(SN9C105, SP80708)}, {USB_DEVICE(0x0c45, 0x60ec), BS(SN9C105, MO4000)}, /* {USB_DEVICE(0x0c45, 0x60ef), BS(SN9C105, ICM105C)}, */ /* {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */ -- GitLab From 9d78f46071b2cbc91eaf533e1ea441af36eed06a Mon Sep 17 00:00:00 2001 From: Oliver Endriss <o.endriss@gmx.de> Date: Sun, 16 May 2010 05:08:49 -0300 Subject: [PATCH 364/842] V4L/DVB: ngene: Support new device 'Digital Devices DuoFlex S2 miniPCIe' Add subsystem id DD10/DD20 'Digital Devices DuoFlex S2 miniPCIe'. Signed-off-by: Oliver Endriss <o.endriss@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/ngene/ngene-cards.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index 692c3e226e83..4692a41ad95b 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -217,6 +217,19 @@ static struct ngene_info ngene_info_cineS2v5 = { .fw_version = 15, }; +static struct ngene_info ngene_info_duoFlexS2 = { + .type = NGENE_SIDEWINDER, + .name = "Digital Devices DuoFlex S2 miniPCIe", + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08}, + .tsf = {3, 3}, + .fw_version = 15, +}; + static struct ngene_info ngene_info_m780 = { .type = NGENE_APP, .name = "Aver M780 ATSC/QAM-B", @@ -256,6 +269,8 @@ static const struct pci_device_id ngene_id_tbl[] __devinitdata = { NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2), NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5), + NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2), + NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2), NGENE_ID(0x1461, 0x062e, ngene_info_m780), {0} }; -- GitLab From eb05d155bc9f51ff701c09bc9b5e4b4f5a4b4d9f Mon Sep 17 00:00:00 2001 From: Oliver Endriss <o.endriss@gmx.de> Date: Sun, 16 May 2010 05:17:49 -0300 Subject: [PATCH 365/842] V4L/DVB: ngene: Do not call demuxer with interrupts disabled It is neither a good idea nor necessary to call the demuxer with interrupts disabled. Signed-off-by: Oliver Endriss <o.endriss@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/ngene/ngene-core.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index c8b4dfa0ab5f..46749d6ef1ee 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -147,24 +147,24 @@ static void demux_tasklet(unsigned long data) } else { if (chan->HWState == HWSTATE_RUN) { u32 Flags = 0; + IBufferExchange *exch1 = chan->pBufferExchange; + IBufferExchange *exch2 = chan->pBufferExchange2; if (Cur->ngeneBuffer.SR.Flags & 0x01) Flags |= BEF_EVEN_FIELD; if (Cur->ngeneBuffer.SR.Flags & 0x20) Flags |= BEF_OVERFLOW; - if (chan->pBufferExchange) - chan->pBufferExchange(chan, - Cur->Buffer1, - chan-> - Capture1Length, - Cur->ngeneBuffer. - SR.Clock, Flags); - if (chan->pBufferExchange2) - chan->pBufferExchange2(chan, - Cur->Buffer2, - chan-> - Capture2Length, - Cur->ngeneBuffer. - SR.Clock, Flags); + spin_unlock_irq(&chan->state_lock); + if (exch1) + exch1(chan, Cur->Buffer1, + chan->Capture1Length, + Cur->ngeneBuffer.SR.Clock, + Flags); + if (exch2) + exch2(chan, Cur->Buffer2, + chan->Capture2Length, + Cur->ngeneBuffer.SR.Clock, + Flags); + spin_lock_irq(&chan->state_lock); } else if (chan->HWState != HWSTATE_STOP) chan->HWState = HWSTATE_RUN; } -- GitLab From 4387418129895fd9aa2e2f6368ea69e9c4ddd0f2 Mon Sep 17 00:00:00 2001 From: Oliver Endriss <o.endriss@gmx.de> Date: Sun, 16 May 2010 05:29:14 -0300 Subject: [PATCH 366/842] V4L/DVB: ngene: Implement support for MSI Add MSI support, may be enabled with firmware version 18. Signed-off-by: Oliver Endriss <o.endriss@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/ngene/ngene-core.c | 33 +++++++++++++++++++++++++++- drivers/media/dvb/ngene/ngene.h | 2 ++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 46749d6ef1ee..35bed6095b1e 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1299,11 +1299,14 @@ static void ngene_stop(struct ngene *dev) ngwritel(0, NGENE_EVENT); ngwritel(0, NGENE_EVENT_HI); free_irq(dev->pci_dev->irq, dev); + if (dev->msi_enabled) + pci_disable_msi(dev->pci_dev); } static int ngene_start(struct ngene *dev) { int stat; + unsigned long flags; int i; pci_set_master(dev->pci_dev); @@ -1333,6 +1336,28 @@ static int ngene_start(struct ngene *dev) if (stat < 0) goto fail; +#ifdef CONFIG_PCI_MSI + /* enable MSI if kernel and card support it */ + if (dev->card_info->msi_supported) { + ngwritel(0, NGENE_INT_ENABLE); + free_irq(dev->pci_dev->irq, dev); + stat = pci_enable_msi(dev->pci_dev); + if (stat) { + printk(KERN_INFO DEVICE_NAME + ": MSI not available\n"); + flags = IRQF_SHARED; + } else { + flags = 0; + dev->msi_enabled = true; + } + stat = request_irq(dev->pci_dev->irq, irq_handler, + flags, "nGene", dev); + if (stat < 0) + goto fail2; + ngwritel(1, NGENE_INT_ENABLE); + } +#endif + stat = ngene_i2c_init(dev, 0); if (stat < 0) goto fail; @@ -1358,10 +1383,16 @@ static int ngene_start(struct ngene *dev) bconf = BUFFER_CONFIG_3333; stat = ngene_command_config_buf(dev, bconf); } - return stat; + if (!stat) + return stat; + + /* otherwise error: fall through */ fail: ngwritel(0, NGENE_INT_ENABLE); free_irq(dev->pci_dev->irq, dev); +fail2: + if (dev->msi_enabled) + pci_disable_msi(dev->pci_dev); return stat; } diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h index 676fcbb79026..b951d59e3617 100644 --- a/drivers/media/dvb/ngene/ngene.h +++ b/drivers/media/dvb/ngene/ngene.h @@ -725,6 +725,7 @@ struct ngene { u32 device_version; u32 fw_interface_version; u32 icounts; + bool msi_enabled; u8 *CmdDoneByte; int BootFirmware; @@ -797,6 +798,7 @@ struct ngene_info { #define NGENE_VBOX_V2 7 int fw_version; + bool msi_supported; char *name; int io_type[MAX_STREAM]; -- GitLab From 5a2a1848a7d744a437f96b79a655c13b8090e74d Mon Sep 17 00:00:00 2001 From: Oliver Endriss <o.endriss@gmx.de> Date: Sun, 16 May 2010 06:07:07 -0300 Subject: [PATCH 367/842] V4L/DVB: ngene: Make command timeout workaround configurable Make command timeout workaround configurable, activate it for firmware version <= 17. Signed-off-by: Oliver Endriss <o.endriss@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/ngene/ngene-core.c | 9 ++++----- drivers/media/dvb/ngene/ngene-dvb.c | 14 +++----------- drivers/media/dvb/ngene/ngene.h | 1 + 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 35bed6095b1e..2bdcf59829d1 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -53,8 +53,6 @@ MODULE_PARM_DESC(debug, "Print debugging information."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define COMMAND_TIMEOUT_WORKAROUND - #define dprintk if (debug) printk #define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) @@ -1252,14 +1250,17 @@ static int ngene_load_firm(struct ngene *dev) version = 15; size = 23466; fw_name = "ngene_15.fw"; + dev->cmd_timeout_workaround = true; break; case 16: size = 23498; fw_name = "ngene_16.fw"; + dev->cmd_timeout_workaround = true; break; case 17: size = 24446; fw_name = "ngene_17.fw"; + dev->cmd_timeout_workaround = true; break; } @@ -1410,10 +1411,8 @@ static void release_channel(struct ngene_channel *chan) struct ngene_info *ni = dev->card_info; int io = ni->io_type[chan->number]; -#ifdef COMMAND_TIMEOUT_WORKAROUND - if (chan->running) + if (chan->dev->cmd_timeout_workaround && chan->running) set_transfer(chan, 0); -#endif tasklet_kill(&chan->demux_tasklet); diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c index 96013eb353cd..61a932c1cfff 100644 --- a/drivers/media/dvb/ngene/ngene-dvb.c +++ b/drivers/media/dvb/ngene/ngene-dvb.c @@ -44,8 +44,6 @@ #include "ngene.h" -#define COMMAND_TIMEOUT_WORKAROUND - /****************************************************************************/ /* COMMAND API interface ****************************************************/ @@ -69,9 +67,7 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) struct ngene_channel *chan = priv; -#ifdef COMMAND_TIMEOUT_WORKAROUND if (chan->users > 0) -#endif dvb_dmx_swfilter(&chan->demux, buf, len); return NULL; } @@ -106,11 +102,8 @@ int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed) struct ngene_channel *chan = dvbdmx->priv; if (chan->users == 0) { -#ifdef COMMAND_TIMEOUT_WORKAROUND - if (!chan->running) -#endif + if (!chan->dev->cmd_timeout_workaround || !chan->running) set_transfer(chan, 1); - /* msleep(10); */ } return ++chan->users; @@ -124,9 +117,8 @@ int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed) if (--chan->users) return chan->users; -#ifndef COMMAND_TIMEOUT_WORKAROUND - set_transfer(chan, 0); -#endif + if (!chan->dev->cmd_timeout_workaround) + set_transfer(chan, 0); return 0; } diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h index b951d59e3617..8fb4200f83f8 100644 --- a/drivers/media/dvb/ngene/ngene.h +++ b/drivers/media/dvb/ngene/ngene.h @@ -726,6 +726,7 @@ struct ngene { u32 fw_interface_version; u32 icounts; bool msi_enabled; + bool cmd_timeout_workaround; u8 *CmdDoneByte; int BootFirmware; -- GitLab From 478b3a42bdcd8d1cb57c91cabdc8b6164c639e42 Mon Sep 17 00:00:00 2001 From: Oliver Endriss <o.endriss@gmx.de> Date: Wed, 19 May 2010 04:15:44 -0300 Subject: [PATCH 368/842] V4L/DVB: ngene: MSI cleanup MSI cleanup. Signed-off-by: Oliver Endriss <o.endriss@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/ngene/ngene-core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 2bdcf59829d1..dcf1f45ff07c 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1300,8 +1300,10 @@ static void ngene_stop(struct ngene *dev) ngwritel(0, NGENE_EVENT); ngwritel(0, NGENE_EVENT_HI); free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI if (dev->msi_enabled) pci_disable_msi(dev->pci_dev); +#endif } static int ngene_start(struct ngene *dev) @@ -1339,7 +1341,7 @@ static int ngene_start(struct ngene *dev) #ifdef CONFIG_PCI_MSI /* enable MSI if kernel and card support it */ - if (dev->card_info->msi_supported) { + if (pci_msi_enabled() && dev->card_info->msi_supported) { ngwritel(0, NGENE_INT_ENABLE); free_irq(dev->pci_dev->irq, dev); stat = pci_enable_msi(dev->pci_dev); @@ -1391,9 +1393,11 @@ static int ngene_start(struct ngene *dev) fail: ngwritel(0, NGENE_INT_ENABLE); free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI fail2: if (dev->msi_enabled) pci_disable_msi(dev->pci_dev); +#endif return stat; } -- GitLab From 51ff9ef13366b3752a8ab6229c466fd1bd671d3a Mon Sep 17 00:00:00 2001 From: Oliver Endriss <o.endriss@gmx.de> Date: Wed, 19 May 2010 04:17:18 -0300 Subject: [PATCH 369/842] V4L/DVB: ngene: Remove debug message Remove debug message. Signed-off-by: Oliver Endriss <o.endriss@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/ngene/ngene-core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index dcf1f45ff07c..4caeb163a666 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -570,11 +570,7 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream, u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700); u16 BsSDO = 0x9B00; - /* down(&dev->stream_mutex); */ - while (down_trylock(&dev->stream_mutex)) { - printk(KERN_INFO DEVICE_NAME ": SC locked\n"); - msleep(1); - } + down(&dev->stream_mutex); memset(&com, 0, sizeof(com)); com.cmd.hdr.Opcode = CMD_CONTROL; com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2; -- GitLab From f1158af2b2e064532470516943511863a873c5e5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 06:54:46 -0300 Subject: [PATCH 370/842] V4L/DVB: V4L2 Spec: Improve the VIDIOC_QUERY_DV_PRESET description Make explicit what should happen when the input signal is missing, unreliable or does not map to a supported preset. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- Documentation/DocBook/v4l/vidioc-query-dv-preset.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml index 87e4f0f6151c..402229ee06f6 100644 --- a/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml +++ b/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml @@ -53,8 +53,10 @@ input</refpurpose> automatically, similar to sensing the video standard. To do so, applications call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a &v4l2-dv-preset; type. Once the hardware detects a preset, that preset is -returned in the preset field of &v4l2-dv-preset;. When detection is not -possible or fails, the value V4L2_DV_INVALID is returned.</para> +returned in the preset field of &v4l2-dv-preset;. If the preset could not be +detected because there was no signal, or the signal was unreliable, or the +signal did not map to a supported preset, then the value V4L2_DV_INVALID is +returned.</para> </refsect1> <refsect1> -- GitLab From c463d93f22254f46168b49ad1149d1ec1e904711 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 09:47:23 -0300 Subject: [PATCH 371/842] V4L/DVB: saa7115: add s_mbus_fmt op Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/saa7115.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 53b6fcde3800..d4cc20859975 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1136,6 +1136,15 @@ static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } +static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +{ + if (fmt->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; + fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + return saa711x_set_size(sd, fmt->width, fmt->height); +} + static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) { if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -1558,6 +1567,7 @@ static const struct v4l2_subdev_video_ops saa711x_video_ops = { .s_crystal_freq = saa711x_s_crystal_freq, .g_fmt = saa711x_g_fmt, .s_fmt = saa711x_s_fmt, + .s_mbus_fmt = saa711x_s_mbus_fmt, .s_stream = saa711x_s_stream, .querystd = saa711x_querystd, .g_input_status = saa711x_g_input_status, -- GitLab From 96fd004fe40b8e3beff2a6e27ae0411a4d315f1e Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 09:48:50 -0300 Subject: [PATCH 372/842] V4L/DVB: cx25840: add support for s_mbus_fmt Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/cx25840/cx25840-core.c | 96 +++++++++++++--------- 1 file changed, 55 insertions(+), 41 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 8b6fb3544376..f0cbc9d066bd 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1025,59 +1025,72 @@ static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) return 0; } -static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - struct v4l2_pix_format *pix; int HSC, VSC, Vsrc, Hsrc, filter, Vlines; int is_50Hz = !(state->std & V4L2_STD_525_60); - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - pix = &(fmt->fmt.pix); + if (fmt->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; - Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; - Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; + fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; - Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; + Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; + Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; - Vlines = pix->height + (is_50Hz ? 4 : 7); + Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; + Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; - if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || - (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { - v4l_err(client, "%dx%d is not a valid size!\n", - pix->width, pix->height); - return -ERANGE; - } + Vlines = fmt->height + (is_50Hz ? 4 : 7); - HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); - VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); - VSC &= 0x1fff; + if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || + (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { + v4l_err(client, "%dx%d is not a valid size!\n", + fmt->width, fmt->height); + return -ERANGE; + } - if (pix->width >= 385) - filter = 0; - else if (pix->width > 192) - filter = 1; - else if (pix->width > 96) - filter = 2; - else - filter = 3; - - v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", - pix->width, pix->height, HSC, VSC); - - /* HSCALE=HSC */ - cx25840_write(client, 0x418, HSC & 0xff); - cx25840_write(client, 0x419, (HSC >> 8) & 0xff); - cx25840_write(client, 0x41a, HSC >> 16); - /* VSCALE=VSC */ - cx25840_write(client, 0x41c, VSC & 0xff); - cx25840_write(client, 0x41d, VSC >> 8); - /* VS_INTRLACE=1 VFILT=filter */ - cx25840_write(client, 0x41e, 0x8 | filter); - break; + HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); + VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); + VSC &= 0x1fff; + + if (fmt->width >= 385) + filter = 0; + else if (fmt->width > 192) + filter = 1; + else if (fmt->width > 96) + filter = 2; + else + filter = 3; + + v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", + fmt->width, fmt->height, HSC, VSC); + + /* HSCALE=HSC */ + cx25840_write(client, 0x418, HSC & 0xff); + cx25840_write(client, 0x419, (HSC >> 8) & 0xff); + cx25840_write(client, 0x41a, HSC >> 16); + /* VSCALE=VSC */ + cx25840_write(client, 0x41c, VSC & 0xff); + cx25840_write(client, 0x41d, VSC >> 8); + /* VS_INTRLACE=1 VFILT=filter */ + cx25840_write(client, 0x41e, 0x8 | filter); + return 0; +} + +static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + struct v4l2_mbus_framefmt mbus_fmt; + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + mbus_fmt.width = fmt->fmt.pix.width; + mbus_fmt.height = fmt->fmt.pix.height; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + return cx25840_s_mbus_fmt(sd, &mbus_fmt); default: return -EINVAL; @@ -1629,6 +1642,7 @@ static const struct v4l2_subdev_video_ops cx25840_video_ops = { .s_routing = cx25840_s_video_routing, .g_fmt = cx25840_g_fmt, .s_fmt = cx25840_s_fmt, + .s_mbus_fmt = cx25840_s_mbus_fmt, .s_stream = cx25840_s_stream, }; -- GitLab From 6c69db9de7a8934bdeb690663fab6fe046203ac4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 09:50:34 -0300 Subject: [PATCH 373/842] V4L/DVB: saa717x: add support for s_mbus_fmt Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/saa717x.c | 47 +++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index d521c648e157..422a3e222afa 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c @@ -1199,28 +1199,32 @@ static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * } #endif -static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { - struct v4l2_pix_format *pix; int prescale, h_scale, v_scale; - pix = &fmt->fmt.pix; v4l2_dbg(1, debug, sd, "decoder set size\n"); + if (fmt->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; + /* FIXME need better bounds checking here */ - if (pix->width < 1 || pix->width > 1440) + if (fmt->width < 1 || fmt->width > 1440) return -EINVAL; - if (pix->height < 1 || pix->height > 960) + if (fmt->height < 1 || fmt->height > 960) return -EINVAL; + fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + /* scaling setting */ /* NTSC and interlace only */ - prescale = SAA717X_NTSC_WIDTH / pix->width; + prescale = SAA717X_NTSC_WIDTH / fmt->width; if (prescale == 0) prescale = 1; - h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width; + h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / fmt->width; /* interlace */ - v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height; + v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / fmt->height; /* Horizontal prescaling etc */ set_h_prescale(sd, 0, prescale); @@ -1241,22 +1245,32 @@ static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) /* set video output size */ /* video number of pixels at output */ /* TASK A */ - saa717x_write(sd, 0x5C, (u8)(pix->width & 0xFF)); - saa717x_write(sd, 0x5D, (u8)((pix->width >> 8) & 0xFF)); + saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF)); + saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF)); /* TASK B */ - saa717x_write(sd, 0x9C, (u8)(pix->width & 0xFF)); - saa717x_write(sd, 0x9D, (u8)((pix->width >> 8) & 0xFF)); + saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF)); + saa717x_write(sd, 0x9D, (u8)((fmt->width >> 8) & 0xFF)); /* video number of lines at output */ /* TASK A */ - saa717x_write(sd, 0x5E, (u8)(pix->height & 0xFF)); - saa717x_write(sd, 0x5F, (u8)((pix->height >> 8) & 0xFF)); + saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF)); + saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF)); /* TASK B */ - saa717x_write(sd, 0x9E, (u8)(pix->height & 0xFF)); - saa717x_write(sd, 0x9F, (u8)((pix->height >> 8) & 0xFF)); + saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF)); + saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF)); return 0; } +static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + struct v4l2_mbus_framefmt mbus_fmt; + + mbus_fmt.width = fmt->fmt.pix.width; + mbus_fmt.height = fmt->fmt.pix.height; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + return saa717x_s_mbus_fmt(sd, &mbus_fmt); +} + static int saa717x_s_radio(struct v4l2_subdev *sd) { struct saa717x_state *decoder = to_state(sd); @@ -1404,6 +1418,7 @@ static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = { static const struct v4l2_subdev_video_ops saa717x_video_ops = { .s_routing = saa717x_s_video_routing, .s_fmt = saa717x_s_fmt, + .s_mbus_fmt = saa717x_s_mbus_fmt, .s_stream = saa717x_s_stream, }; -- GitLab From 475977ac3db72c008f5aaa5f19bd991b72f26e42 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 16:28:51 -0300 Subject: [PATCH 374/842] V4L/DVB: ivtv: convert to use s_mbus_fmt Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/ivtv/ivtv-controls.c | 10 +++++----- drivers/media/video/ivtv/ivtv-ioctl.c | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index b59475bfc243..b588e30cbcf0 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -267,13 +267,13 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) if (p.video_encoding != itv->params.video_encoding) { int is_mpeg1 = p.video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_format fmt; + struct v4l2_mbus_framefmt fmt; /* fix videodecoder resolution */ - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1); - fmt.fmt.pix.height = itv->params.height; - v4l2_subdev_call(itv->sd_video, video, s_fmt, &fmt); + fmt.width = itv->params.width / (is_mpeg1 ? 2 : 1); + fmt.height = itv->params.height; + fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt); } err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index fa9f0d958f96..11ac2fa33ef7 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -569,6 +569,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f struct ivtv_open_id *id = fh; struct ivtv *itv = id->itv; struct cx2341x_mpeg_params *p = &itv->params; + struct v4l2_mbus_framefmt mbus_fmt; int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); int w = fmt->fmt.pix.width; int h = fmt->fmt.pix.height; @@ -586,7 +587,10 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f p->height = h; if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) fmt->fmt.pix.width /= 2; - v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt); + mbus_fmt.width = fmt->fmt.pix.width; + mbus_fmt.height = h; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt); return ivtv_g_fmt_vid_cap(file, fh, fmt); } -- GitLab From e17ad1de031f2d5cade70eb0469a53f17d90d7c2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 09:54:58 -0300 Subject: [PATCH 375/842] V4L/DVB: cx18: add s_mbus_fmt support Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/cx18/cx18-av-core.c | 126 +++++++++++++----------- 1 file changed, 69 insertions(+), 57 deletions(-) diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index 0e5006b14279..39f484621a45 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -1028,80 +1028,91 @@ static int cx18_av_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) return cx18_av_g_sliced_fmt(sd, &fmt->fmt.sliced); } -static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct cx18_av_state *state = to_cx18_av_state(sd); struct cx18 *cx = v4l2_get_subdevdata(sd); - - struct v4l2_pix_format *pix; int HSC, VSC, Vsrc, Hsrc, filter, Vlines; int is_50Hz = !(state->std & V4L2_STD_525_60); - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - pix = &(fmt->fmt.pix); + if (fmt->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; - Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4; - Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4; + fmt->field = V4L2_FIELD_INTERLACED; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4; - Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4; + Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4; + Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4; - /* - * This adjustment reflects the excess of vactive, set in - * cx18_av_std_setup(), above standard values: - * - * 480 + 1 for 60 Hz systems - * 576 + 3 for 50 Hz systems - */ - Vlines = pix->height + (is_50Hz ? 3 : 1); + Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4; + Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4; - /* - * Invalid height and width scaling requests are: - * 1. width less than 1/16 of the source width - * 2. width greater than the source width - * 3. height less than 1/8 of the source height - * 4. height greater than the source height - */ - if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || - (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { - CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n", - pix->width, pix->height); - return -ERANGE; - } + /* + * This adjustment reflects the excess of vactive, set in + * cx18_av_std_setup(), above standard values: + * + * 480 + 1 for 60 Hz systems + * 576 + 3 for 50 Hz systems + */ + Vlines = fmt->height + (is_50Hz ? 3 : 1); - HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); - VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); - VSC &= 0x1fff; + /* + * Invalid height and width scaling requests are: + * 1. width less than 1/16 of the source width + * 2. width greater than the source width + * 3. height less than 1/8 of the source height + * 4. height greater than the source height + */ + if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || + (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { + CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n", + fmt->width, fmt->height); + return -ERANGE; + } - if (pix->width >= 385) - filter = 0; - else if (pix->width > 192) - filter = 1; - else if (pix->width > 96) - filter = 2; - else - filter = 3; + HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); + VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); + VSC &= 0x1fff; - CX18_DEBUG_INFO_DEV(sd, - "decoder set size %dx%d -> scale %ux%u\n", - pix->width, pix->height, HSC, VSC); - - /* HSCALE=HSC */ - cx18_av_write(cx, 0x418, HSC & 0xff); - cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff); - cx18_av_write(cx, 0x41a, HSC >> 16); - /* VSCALE=VSC */ - cx18_av_write(cx, 0x41c, VSC & 0xff); - cx18_av_write(cx, 0x41d, VSC >> 8); - /* VS_INTRLACE=1 VFILT=filter */ - cx18_av_write(cx, 0x41e, 0x8 | filter); - break; + if (fmt->width >= 385) + filter = 0; + else if (fmt->width > 192) + filter = 1; + else if (fmt->width > 96) + filter = 2; + else + filter = 3; + + CX18_DEBUG_INFO_DEV(sd, + "decoder set size %dx%d -> scale %ux%u\n", + fmt->width, fmt->height, HSC, VSC); + + /* HSCALE=HSC */ + cx18_av_write(cx, 0x418, HSC & 0xff); + cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff); + cx18_av_write(cx, 0x41a, HSC >> 16); + /* VSCALE=VSC */ + cx18_av_write(cx, 0x41c, VSC & 0xff); + cx18_av_write(cx, 0x41d, VSC >> 8); + /* VS_INTRLACE=1 VFILT=filter */ + cx18_av_write(cx, 0x41e, 0x8 | filter); + return 0; +} + +static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + struct v4l2_mbus_framefmt mbus_fmt; + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + mbus_fmt.width = fmt->fmt.pix.width; + mbus_fmt.height = fmt->fmt.pix.height; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + return cx18_av_s_mbus_fmt(sd, &mbus_fmt); default: return -EINVAL; } - return 0; } static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable) @@ -1400,6 +1411,7 @@ static const struct v4l2_subdev_video_ops cx18_av_video_ops = { .s_stream = cx18_av_s_stream, .g_fmt = cx18_av_g_fmt, .s_fmt = cx18_av_s_fmt, + .s_mbus_fmt = cx18_av_s_mbus_fmt, }; static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = { -- GitLab From 9e36eabc8a6fb87d9b97057e0d0f5195c475fbdc Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 16:37:53 -0300 Subject: [PATCH 376/842] V4L/DVB: cx18: remove old g/s_fmt from the cx18_av subdev cx18 has now switched over completely to the new mediabus subdev ops. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/cx18/cx18-av-core.c | 25 ------------------------ drivers/media/video/cx18/cx18-controls.c | 11 +++++------ drivers/media/video/cx18/cx18-ioctl.c | 8 +++++--- 3 files changed, 10 insertions(+), 34 deletions(-) diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index 39f484621a45..54371f6d6b5f 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -1021,13 +1021,6 @@ static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) return -EINVAL; } -static int cx18_av_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - return cx18_av_g_sliced_fmt(sd, &fmt->fmt.sliced); -} - static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct cx18_av_state *state = to_cx18_av_state(sd); @@ -1099,22 +1092,6 @@ static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return 0; } -static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - struct v4l2_mbus_framefmt mbus_fmt; - - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - mbus_fmt.width = fmt->fmt.pix.width; - mbus_fmt.height = fmt->fmt.pix.height; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - return cx18_av_s_mbus_fmt(sd, &mbus_fmt); - - default: - return -EINVAL; - } -} - static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable) { struct cx18 *cx = v4l2_get_subdevdata(sd); @@ -1409,8 +1386,6 @@ static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = { static const struct v4l2_subdev_video_ops cx18_av_video_ops = { .s_routing = cx18_av_s_video_routing, .s_stream = cx18_av_s_stream, - .g_fmt = cx18_av_g_fmt, - .s_fmt = cx18_av_s_fmt, .s_mbus_fmt = cx18_av_s_mbus_fmt, }; diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c index 4b4b46544d5a..67043c7b452b 100644 --- a/drivers/media/video/cx18/cx18-controls.c +++ b/drivers/media/video/cx18/cx18-controls.c @@ -297,14 +297,13 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) if (p.video_encoding != cx->params.video_encoding) { int is_mpeg1 = p.video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_format fmt; + struct v4l2_mbus_framefmt fmt; /* fix videodecoder resolution */ - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = cx->params.width - / (is_mpeg1 ? 2 : 1); - fmt.fmt.pix.height = cx->params.height; - v4l2_subdev_call(cx->sd_av, video, s_fmt, &fmt); + fmt.width = cx->params.width / (is_mpeg1 ? 2 : 1); + fmt.height = cx->params.height; + fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); } priv.cx = cx; priv.s = &cx->streams[id->type]; diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 2530fc54daaf..b5b221c8a725 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -274,6 +274,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, { struct cx18_open_id *id = fh; struct cx18 *cx = id->cx; + struct v4l2_mbus_framefmt mbus_fmt; int ret; int w, h; @@ -293,9 +294,10 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, if (atomic_read(&cx->ana_capturing) > 0) return -EBUSY; - cx->params.width = w; - cx->params.height = h; - v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt); + mbus_fmt.width = cx->params.width = w; + mbus_fmt.height = cx->params.height = h; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); return cx18_g_fmt_vid_cap(file, fh, fmt); } -- GitLab From 60298c99f792bb2fe12137360d448c72234b2d0b Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 16:39:01 -0300 Subject: [PATCH 377/842] V4L/DVB: saa7127: remove obsolete g_fmt support Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/saa7127.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 87986ad62f86..79fffcf39ba8 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -645,13 +645,6 @@ static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } -static int saa7127_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - return saa7127_g_sliced_fmt(sd, &fmt->fmt.sliced); -} - static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data) { switch (data->id) { @@ -731,7 +724,6 @@ static const struct v4l2_subdev_core_ops saa7127_core_ops = { }; static const struct v4l2_subdev_video_ops saa7127_video_ops = { - .g_fmt = saa7127_g_fmt, .s_std_output = saa7127_s_std_output, .s_routing = saa7127_s_routing, .s_stream = saa7127_s_stream, -- GitLab From 66e9df07d362b63a594e8663260e0430ba4a17bf Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 16:40:23 -0300 Subject: [PATCH 378/842] V4L/DVB: saa717x: remove obsolete s_fmt op Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/saa717x.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index 422a3e222afa..78d69950c00a 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c @@ -1261,16 +1261,6 @@ static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return 0; } -static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - struct v4l2_mbus_framefmt mbus_fmt; - - mbus_fmt.width = fmt->fmt.pix.width; - mbus_fmt.height = fmt->fmt.pix.height; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - return saa717x_s_mbus_fmt(sd, &mbus_fmt); -} - static int saa717x_s_radio(struct v4l2_subdev *sd) { struct saa717x_state *decoder = to_state(sd); @@ -1417,7 +1407,6 @@ static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = { static const struct v4l2_subdev_video_ops saa717x_video_ops = { .s_routing = saa717x_s_video_routing, - .s_fmt = saa717x_s_fmt, .s_mbus_fmt = saa717x_s_mbus_fmt, .s_stream = saa717x_s_stream, }; -- GitLab From 3a21ceed7f373894a7c537b4dbbe484f36e7ae24 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 17:08:58 -0300 Subject: [PATCH 379/842] V4L/DVB: v4l2-mediabus.h: add two helper functions Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- include/media/v4l2-mediabus.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h index 0dbe02ada259..d8e1608fee59 100644 --- a/include/media/v4l2-mediabus.h +++ b/include/media/v4l2-mediabus.h @@ -58,4 +58,24 @@ struct v4l2_mbus_framefmt { enum v4l2_colorspace colorspace; }; +static inline void v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt, + const struct v4l2_mbus_framefmt *mbus_fmt) +{ + pix_fmt->width = mbus_fmt->width; + pix_fmt->height = mbus_fmt->height; + pix_fmt->field = mbus_fmt->field; + pix_fmt->colorspace = mbus_fmt->colorspace; +} + +static inline void v4l2_fill_mbus_format(struct v4l2_mbus_framefmt *mbus_fmt, + const struct v4l2_pix_format *pix_fmt, + enum v4l2_mbus_pixelcode code) +{ + mbus_fmt->width = pix_fmt->width; + mbus_fmt->height = pix_fmt->height; + mbus_fmt->field = pix_fmt->field; + mbus_fmt->colorspace = pix_fmt->colorspace; + mbus_fmt->code = code; +} + #endif -- GitLab From 51623ef9aedd8b786a12a4475201827ee85d285c Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 09:39:58 -0300 Subject: [PATCH 380/842] V4L/DVB: saa6752hs: add g/s_mbus_fmt support Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/saa7134/saa6752hs.c | 64 ++++++++++++++++++------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 1eabff6b2456..852040b6b5a6 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -846,24 +846,38 @@ static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_control return 0; } -static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) { struct saa6752hs_state *h = to_state(sd); if (h->video_format == SAA6752HS_VF_UNKNOWN) h->video_format = SAA6752HS_VF_D1; - f->fmt.pix.width = - v4l2_format_table[h->video_format].fmt.pix.width; - f->fmt.pix.height = - v4l2_format_table[h->video_format].fmt.pix.height; + f->width = v4l2_format_table[h->video_format].fmt.pix.width; + f->height = v4l2_format_table[h->video_format].fmt.pix.height; + f->code = V4L2_MBUS_FMT_FIXED; + f->field = V4L2_FIELD_INTERLACED; + f->colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } -static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_mbus_framefmt mbus_fmt; + int err = saa6752hs_g_mbus_fmt(sd, &mbus_fmt); + + f->fmt.pix.width = mbus_fmt.width; + f->fmt.pix.height = mbus_fmt.height; + return err; +} + +static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) { struct saa6752hs_state *h = to_state(sd); int dist_352, dist_480, dist_720; + if (f->code != V4L2_MBUS_FMT_FIXED) + return -EINVAL; + /* FIXME: translate and round width/height into EMPRESS subsample type: @@ -876,31 +890,43 @@ static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) D1 | 720x576 | 720x480 */ - dist_352 = abs(f->fmt.pix.width - 352); - dist_480 = abs(f->fmt.pix.width - 480); - dist_720 = abs(f->fmt.pix.width - 720); + dist_352 = abs(f->width - 352); + dist_480 = abs(f->width - 480); + dist_720 = abs(f->width - 720); if (dist_720 < dist_480) { - f->fmt.pix.width = 720; - f->fmt.pix.height = 576; + f->width = 720; + f->height = 576; h->video_format = SAA6752HS_VF_D1; } else if (dist_480 < dist_352) { - f->fmt.pix.width = 480; - f->fmt.pix.height = 576; + f->width = 480; + f->height = 576; h->video_format = SAA6752HS_VF_2_3_D1; } else { - f->fmt.pix.width = 352; - if (abs(f->fmt.pix.height - 576) < - abs(f->fmt.pix.height - 288)) { - f->fmt.pix.height = 576; + f->width = 352; + if (abs(f->height - 576) < + abs(f->height - 288)) { + f->height = 576; h->video_format = SAA6752HS_VF_1_2_D1; } else { - f->fmt.pix.height = 288; + f->height = 288; h->video_format = SAA6752HS_VF_SIF; } } + f->field = V4L2_FIELD_INTERLACED; + f->colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } +static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_mbus_framefmt mbus_fmt; + + mbus_fmt.width = f->fmt.pix.width; + mbus_fmt.height = f->fmt.pix.height; + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + return saa6752hs_s_mbus_fmt(sd, &mbus_fmt); +} + static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct saa6752hs_state *h = to_state(sd); @@ -934,6 +960,8 @@ static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { static const struct v4l2_subdev_video_ops saa6752hs_video_ops = { .s_fmt = saa6752hs_s_fmt, .g_fmt = saa6752hs_g_fmt, + .s_mbus_fmt = saa6752hs_s_mbus_fmt, + .g_mbus_fmt = saa6752hs_g_mbus_fmt, }; static const struct v4l2_subdev_ops saa6752hs_ops = { -- GitLab From 31bf95fb5725013fd7d95d6d5b1e45f4c88b1f56 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 09:41:41 -0300 Subject: [PATCH 381/842] V4L/DVB: saa7134: convert to use the new mbus API Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/saa7134/saa6752hs.c | 22 ------------------- drivers/media/video/saa7134/saa7134-empress.c | 9 ++++++-- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 852040b6b5a6..40fd31ca7716 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -860,16 +860,6 @@ static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm return 0; } -static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) -{ - struct v4l2_mbus_framefmt mbus_fmt; - int err = saa6752hs_g_mbus_fmt(sd, &mbus_fmt); - - f->fmt.pix.width = mbus_fmt.width; - f->fmt.pix.height = mbus_fmt.height; - return err; -} - static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) { struct saa6752hs_state *h = to_state(sd); @@ -917,16 +907,6 @@ static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm return 0; } -static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) -{ - struct v4l2_mbus_framefmt mbus_fmt; - - mbus_fmt.width = f->fmt.pix.width; - mbus_fmt.height = f->fmt.pix.height; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - return saa6752hs_s_mbus_fmt(sd, &mbus_fmt); -} - static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct saa6752hs_state *h = to_state(sd); @@ -958,8 +938,6 @@ static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { }; static const struct v4l2_subdev_video_ops saa6752hs_video_ops = { - .s_fmt = saa6752hs_s_fmt, - .g_fmt = saa6752hs_g_fmt, .s_mbus_fmt = saa6752hs_s_mbus_fmt, .g_mbus_fmt = saa6752hs_g_mbus_fmt, }; diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index ea877a50f52d..e763f9fd0133 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -223,9 +223,11 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = file->private_data; + struct v4l2_mbus_framefmt mbus_fmt; - saa_call_all(dev, video, g_fmt, f); + saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; @@ -236,8 +238,11 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = file->private_data; + struct v4l2_mbus_framefmt mbus_fmt; - saa_call_all(dev, video, s_fmt, f); + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); + saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; -- GitLab From fa190ee91fcc3800f2c5d14810dc1b48a4b5d4e5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 17:16:18 -0300 Subject: [PATCH 382/842] V4L/DVB: pvrusb2: convert to s_mbus_fmt Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 2c3f845c3e5c..70ea578d6266 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -3069,14 +3069,14 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw) } if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) { - struct v4l2_format fmt; + struct v4l2_mbus_framefmt fmt; memset(&fmt, 0, sizeof(fmt)); - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = hdw->res_hor_val; - fmt.fmt.pix.height = hdw->res_ver_val; + fmt.width = hdw->res_hor_val; + fmt.height = hdw->res_ver_val; + fmt.code = V4L2_MBUS_FMT_FIXED; pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)", - fmt.fmt.pix.width, fmt.fmt.pix.height); - v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_fmt, &fmt); + fmt.width, fmt.height); + v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_mbus_fmt, &fmt); } if (hdw->srate_dirty || hdw->force_dirty) { -- GitLab From cc99113b8cfb8b9685490db0b9bf0d26c9705ad3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 10:09:28 -0300 Subject: [PATCH 383/842] V4L/DVB: cx23885: convert to s_mbus_fmt Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/cx23885/cx23885-video.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 543b854f6a62..4e44dcda3875 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -976,6 +976,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, { struct cx23885_fh *fh = priv; struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct v4l2_mbus_framefmt mbus_fmt; int err; dprintk(2, "%s()\n", __func__); @@ -989,7 +990,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, fh->vidq.field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, fh->width, fh->height, fh->vidq.field); - call_all(dev, video, s_fmt, f); + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); + call_all(dev, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); return 0; } -- GitLab From 112cb4a8a092a6338a0e2309aac134e502f2a489 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 10:11:01 -0300 Subject: [PATCH 384/842] V4L/DVB: cx231xx: convert to s_mbus_fmt Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/cx231xx/cx231xx-video.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index 2782709b263f..e76014561aa7 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -993,6 +993,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct cx231xx *dev = fh->dev; int rc; struct cx231xx_fmt *fmt; + struct v4l2_mbus_framefmt mbus_fmt; rc = check_dev(dev); if (rc < 0) @@ -1026,7 +1027,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->format = fmt; get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - call_all(dev, video, s_fmt, f); + v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); + call_all(dev, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); /* Set the correct alternate setting for this resolution */ cx231xx_resolution_set(dev); -- GitLab From c1658cafd1910cbec1b546ecd1f76e8fc99fc513 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 17:20:00 -0300 Subject: [PATCH 385/842] V4L/DVB: cx24850: remove obsolete g/s_fmt ops Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/cx25840/cx25840-core.c | 31 ---------------------- 1 file changed, 31 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index f0cbc9d066bd..bb4872b2ceb0 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1014,17 +1014,6 @@ static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) /* ----------------------------------------------------------------------- */ -static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - switch (fmt->type) { - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - return cx25840_g_sliced_fmt(sd, &fmt->fmt.sliced); - default: - return -EINVAL; - } - return 0; -} - static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct cx25840_state *state = to_state(sd); @@ -1081,24 +1070,6 @@ static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return 0; } -static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - struct v4l2_mbus_framefmt mbus_fmt; - - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - mbus_fmt.width = fmt->fmt.pix.width; - mbus_fmt.height = fmt->fmt.pix.height; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - return cx25840_s_mbus_fmt(sd, &mbus_fmt); - - default: - return -EINVAL; - } - - return 0; -} - /* ----------------------------------------------------------------------- */ static void log_video_status(struct i2c_client *client) @@ -1640,8 +1611,6 @@ static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { static const struct v4l2_subdev_video_ops cx25840_video_ops = { .s_routing = cx25840_s_video_routing, - .g_fmt = cx25840_g_fmt, - .s_fmt = cx25840_s_fmt, .s_mbus_fmt = cx25840_s_mbus_fmt, .s_stream = cx25840_s_stream, }; -- GitLab From 029ed3261021c76f0b8538a2f715d89506555676 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 17:20:35 -0300 Subject: [PATCH 386/842] V4L/DVB: saa7115: remove obsolete g/s_fmt ops Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/saa7115.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index d4cc20859975..76da74368680 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1117,13 +1117,6 @@ static int saa711x_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } -static int saa711x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - return saa711x_g_sliced_fmt(sd, &fmt->fmt.sliced); -} - static int saa711x_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) { saa711x_set_lcr(sd, NULL); @@ -1145,14 +1138,6 @@ static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return saa711x_set_size(sd, fmt->width, fmt->height); } -static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return saa711x_set_size(sd, fmt->fmt.pix.width, fmt->fmt.pix.height); -} - /* Decode the sliced VBI data stream as created by the saa7115. The format is described in the saa7115 datasheet in Tables 25 and 26 and in Figure 33. @@ -1565,8 +1550,6 @@ static const struct v4l2_subdev_audio_ops saa711x_audio_ops = { static const struct v4l2_subdev_video_ops saa711x_video_ops = { .s_routing = saa711x_s_routing, .s_crystal_freq = saa711x_s_crystal_freq, - .g_fmt = saa711x_g_fmt, - .s_fmt = saa711x_s_fmt, .s_mbus_fmt = saa711x_s_mbus_fmt, .s_stream = saa711x_s_stream, .querystd = saa711x_querystd, -- GitLab From 260bb38a21a19edc8a328f3ac8dd45c184d01216 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 19:02:11 -0300 Subject: [PATCH 387/842] V4L/DVB: v4l2-mediabus.h: added V4L2_MBUS_FMT_SGRBG8_1X8 Needed for mt9v011. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- include/media/v4l2-mediabus.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h index d8e1608fee59..865cda7cd611 100644 --- a/include/media/v4l2-mediabus.h +++ b/include/media/v4l2-mediabus.h @@ -40,6 +40,7 @@ enum v4l2_mbus_pixelcode { V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, + V4L2_MBUS_FMT_SGRBG8_1X8, }; /** -- GitLab From ea01b11a07961aabbaec58d572b24f3df4b8065c Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 10:19:25 -0300 Subject: [PATCH 388/842] V4L/DVB: mt9v011: add enum/try/s_mbus_fmt support Note that this driver is only used by em28xx and that em28xx does not actually call the enum/try/s_fmt ops of mt9v011. So these functions have never been tested. And in fact the driver really implements cropping instead of scaling. So it seems to be doing the wrong thing :-( Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/mt9v011.c | 37 ++++++++++++++++------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index 72e55be0b4ab..f5e778d5ca9f 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c @@ -392,27 +392,25 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return 0; } -static int mt9v011_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt) +static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, + enum v4l2_mbus_pixelcode *code) { - if (fmt->index > 0) + if (index > 0) return -EINVAL; - fmt->flags = 0; - strcpy(fmt->description, "8 bpp Bayer GRGR..BGBG"); - fmt->pixelformat = V4L2_PIX_FMT_SGRBG8; - + *code = V4L2_MBUS_FMT_SGRBG8_1X8; return 0; } -static int mt9v011_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->pixelformat != V4L2_PIX_FMT_SGRBG8) + if (fmt->code != V4L2_MBUS_FMT_SGRBG8_1X8) return -EINVAL; - v4l_bound_align_image(&pix->width, 48, 639, 1, - &pix->height, 32, 480, 1, 0); + v4l_bound_align_image(&fmt->width, 48, 639, 1, + &fmt->height, 32, 480, 1, 0); + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; return 0; } @@ -455,18 +453,17 @@ static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) return 0; } -static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { - struct v4l2_pix_format *pix = &fmt->fmt.pix; struct mt9v011 *core = to_mt9v011(sd); int rc; - rc = mt9v011_try_fmt(sd, fmt); + rc = mt9v011_try_mbus_fmt(sd, fmt); if (rc < 0) return -EINVAL; - core->width = pix->width; - core->height = pix->height; + core->width = fmt->width; + core->height = fmt->height; set_res(sd); @@ -549,9 +546,9 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = { }; static const struct v4l2_subdev_video_ops mt9v011_video_ops = { - .enum_fmt = mt9v011_enum_fmt, - .try_fmt = mt9v011_try_fmt, - .s_fmt = mt9v011_s_fmt, + .enum_mbus_fmt = mt9v011_enum_mbus_fmt, + .try_mbus_fmt = mt9v011_try_mbus_fmt, + .s_mbus_fmt = mt9v011_s_mbus_fmt, .g_parm = mt9v011_g_parm, .s_parm = mt9v011_s_parm, }; -- GitLab From 468df208e84d1e7c65b0d005dbbf09f5aea92409 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 17:26:00 -0300 Subject: [PATCH 389/842] V4L/DVB: tvp5150: remove obsolete g/s_fmt ops Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/tvp5150.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 47f0582d50a5..1654f65cca7c 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -934,17 +934,6 @@ static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } -static int tvp5150_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - switch (fmt->type) { - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - return tvp5150_s_sliced_fmt(sd, &fmt->fmt.sliced); - - default: - return -EINVAL; - } -} - static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) { int i, mask = 0; @@ -960,13 +949,6 @@ static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f return 0; } -static int tvp5150_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - return tvp5150_g_sliced_fmt(sd, &fmt->fmt.sliced); -} - static int tvp5150_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { @@ -1054,8 +1036,6 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { static const struct v4l2_subdev_video_ops tvp5150_video_ops = { .s_routing = tvp5150_s_routing, - .g_fmt = tvp5150_g_fmt, - .s_fmt = tvp5150_s_fmt, }; static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { -- GitLab From cf69b808caf8e729949cf20446bec0b9ace033b7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 07:39:32 -0300 Subject: [PATCH 390/842] V4L/DVB: au8522_decoder: g/s_fmt doesn't do anything: remove g/s_fmt is going to disappear, so if it is not doing anything, then just remove it. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/frontends/au8522_decoder.c | 26 -------------------- 1 file changed, 26 deletions(-) diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c index 68dba3a4b4da..29cdbfe36852 100644 --- a/drivers/media/dvb/frontends/au8522_decoder.c +++ b/drivers/media/dvb/frontends/au8522_decoder.c @@ -567,30 +567,6 @@ static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) /* ----------------------------------------------------------------------- */ -static int au8522_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - switch (fmt->type) { - default: - return -EINVAL; - } - return 0; -} - -static int au8522_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) -{ - switch (fmt->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - /* Not yet implemented */ - break; - default: - return -EINVAL; - } - - return 0; -} - -/* ----------------------------------------------------------------------- */ - #ifdef CONFIG_VIDEO_ADV_DEBUG static int au8522_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) @@ -772,8 +748,6 @@ static const struct v4l2_subdev_audio_ops au8522_audio_ops = { static const struct v4l2_subdev_video_ops au8522_video_ops = { .s_routing = au8522_s_video_routing, - .g_fmt = au8522_g_fmt, - .s_fmt = au8522_s_fmt, .s_stream = au8522_s_stream, }; -- GitLab From 3805f201934e5384f6e941222dc1968cb638a88c Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sat, 8 May 2010 17:55:00 -0300 Subject: [PATCH 391/842] V4L/DVB: v4l2-subdev.h: fix enum_mbus_fmt prototype enum_mbus_fmt received an index argument that was defined as an int instead of an unsigned int. This is now fixed. This had the knock-on effect that the index argument in the callback get_formats in soc_camera.h also had to be changed to unsigned int. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Acked-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/ak881x.c | 2 +- drivers/media/video/mt9m001.c | 4 ++-- drivers/media/video/mt9m111.c | 4 ++-- drivers/media/video/mt9t031.c | 2 +- drivers/media/video/mt9t112.c | 4 ++-- drivers/media/video/mt9v022.c | 4 ++-- drivers/media/video/mx3_camera.c | 4 ++-- drivers/media/video/ov772x.c | 4 ++-- drivers/media/video/ov9640.c | 4 ++-- drivers/media/video/pxa_camera.c | 4 ++-- drivers/media/video/rj54n1cb0c.c | 4 ++-- drivers/media/video/sh_mobile_ceu_camera.c | 4 ++-- drivers/media/video/soc_camera.c | 3 ++- drivers/media/video/soc_camera_platform.c | 2 +- drivers/media/video/tw9910.c | 2 +- include/media/soc_camera.h | 2 +- include/media/v4l2-subdev.h | 2 +- 17 files changed, 28 insertions(+), 27 deletions(-) diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c index 35390d4717b9..3006a2c80f47 100644 --- a/drivers/media/video/ak881x.c +++ b/drivers/media/video/ak881x.c @@ -141,7 +141,7 @@ static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd, return ak881x_try_g_mbus_fmt(sd, mf); } -static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, int index, +static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { if (index) diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index b62c0bd3f8ea..992ab8cb89ae 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -701,13 +701,13 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { #endif }; -static int mt9m001_enum_fmt(struct v4l2_subdev *sd, int index, +static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { struct i2c_client *client = sd->priv; struct mt9m001 *mt9m001 = to_mt9m001(client); - if ((unsigned int)index >= mt9m001->num_fmts) + if (index >= mt9m001->num_fmts) return -EINVAL; *code = mt9m001->fmts[index].code; diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index d35f536f9fc3..bac0c5d4070c 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -999,10 +999,10 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { #endif }; -static int mt9m111_enum_fmt(struct v4l2_subdev *sd, int index, +static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - if ((unsigned int)index >= ARRAY_SIZE(mt9m111_colour_fmts)) + if (index >= ARRAY_SIZE(mt9m111_colour_fmts)) return -EINVAL; *code = mt9m111_colour_fmts[index].code; diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 78b4e091d2d5..f26933a8fd8a 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -798,7 +798,7 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { #endif }; -static int mt9t031_enum_fmt(struct v4l2_subdev *sd, int index, +static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { if (index) diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 7438f8d775ba..abe5505b9f79 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -1017,10 +1017,10 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd, return 0; } -static int mt9t112_enum_fmt(struct v4l2_subdev *sd, int index, +static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - if ((unsigned int)index >= ARRAY_SIZE(mt9t112_cfmts)) + if (index >= ARRAY_SIZE(mt9t112_cfmts)) return -EINVAL; *code = mt9t112_cfmts[index].code; diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index e5bae4c9393b..c409d05d465a 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -838,13 +838,13 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { #endif }; -static int mt9v022_enum_fmt(struct v4l2_subdev *sd, int index, +static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { struct i2c_client *client = sd->priv; struct mt9v022 *mt9v022 = to_mt9v022(client); - if ((unsigned int)index >= mt9v022->num_fmts) + if (index >= mt9v022->num_fmts) return -EINVAL; *code = mt9v022->fmts[index].code; diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index d477e3058002..a9be14c23912 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -672,7 +672,7 @@ static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) fmt->packing == SOC_MBUS_PACKING_EXTEND16); } -static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, +static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); @@ -689,7 +689,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, fmt = soc_mbus_get_fmtdesc(code); if (!fmt) { dev_err(icd->dev.parent, - "Invalid format code #%d: %d\n", idx, code); + "Invalid format code #%u: %d\n", idx, code); return 0; } diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 7f8ece30c77b..86b0186c360c 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -1092,10 +1092,10 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { #endif }; -static int ov772x_enum_fmt(struct v4l2_subdev *sd, int index, +static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - if ((unsigned int)index >= ARRAY_SIZE(ov772x_cfmts)) + if (index >= ARRAY_SIZE(ov772x_cfmts)) return -EINVAL; *code = ov772x_cfmts[index].code; diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 36599a65f548..58811c044c6a 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -614,10 +614,10 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd, return 0; } -static int ov9640_enum_fmt(struct v4l2_subdev *sd, int index, +static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - if ((unsigned int)index >= ARRAY_SIZE(ov9640_codes)) + if (index >= ARRAY_SIZE(ov9640_codes)) return -EINVAL; *code = ov9640_codes[index]; diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 7fe70e718656..fb242f6cfb1f 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -1247,7 +1247,7 @@ static bool pxa_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) fmt->packing == SOC_MBUS_PACKING_EXTEND16); } -static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, +static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); @@ -1264,7 +1264,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, fmt = soc_mbus_get_fmtdesc(code); if (!fmt) { - dev_err(dev, "Invalid format code #%d: %d\n", idx, code); + dev_err(dev, "Invalid format code #%u: %d\n", idx, code); return 0; } diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index bbd9c11e2c5a..64eb05ce5603 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -481,10 +481,10 @@ static int reg_write_multiple(struct i2c_client *client, return 0; } -static int rj54n1_enum_fmt(struct v4l2_subdev *sd, int index, +static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { - if ((unsigned int)index >= ARRAY_SIZE(rj54n1_colour_fmts)) + if (index >= ARRAY_SIZE(rj54n1_colour_fmts)) return -EINVAL; *code = rj54n1_colour_fmts[index].code; diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 4ac3b482fbb4..961bfa2fea97 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -878,7 +878,7 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); -static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, +static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); @@ -897,7 +897,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, fmt = soc_mbus_get_fmtdesc(code); if (!fmt) { dev_err(icd->dev.parent, - "Invalid format code #%d: %d\n", idx, code); + "Invalid format code #%u: %d\n", idx, code); return -EINVAL; } diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index db1ca0e90d76..475757bfd7ba 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -200,7 +200,8 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - int i, fmts = 0, raw_fmts = 0, ret; + unsigned int i, fmts = 0, raw_fmts = 0; + int ret; enum v4l2_mbus_pixelcode code; while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code)) diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index 10b003a8be83..248c986f0989 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -71,7 +71,7 @@ static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd, static struct v4l2_subdev_core_ops platform_subdev_core_ops; -static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, int index, +static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 76be733eabfd..2f3b1942e027 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -903,7 +903,7 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { #endif }; -static int tw9910_enum_fmt(struct v4l2_subdev *sd, int index, +static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code) { if (index) diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index c9a5bbfa6ab5..b8289c2f609b 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -66,7 +66,7 @@ struct soc_camera_host_ops { * .get_formats() fail, .put_formats() will not be called at all, the * failing .get_formats() must then clean up internally. */ - int (*get_formats)(struct soc_camera_device *, int, + int (*get_formats)(struct soc_camera_device *, unsigned int, struct soc_camera_format_xlate *); void (*put_formats)(struct soc_camera_device *); int (*cropcap)(struct soc_camera_device *, struct v4l2_cropcap *); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index a88889355ae0..02c6f4d11ed3 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -246,7 +246,7 @@ struct v4l2_subdev_video_ops { struct v4l2_dv_timings *timings); int (*g_dv_timings)(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); - int (*enum_mbus_fmt)(struct v4l2_subdev *sd, int index, + int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code); int (*g_mbus_fmt)(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt); -- GitLab From 2db4e78f14a5b4741b09d03e6d17610537a9af27 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 06:30:15 -0300 Subject: [PATCH 392/842] V4L/DVB: tvp514x: do NOT change the std as a side effect Several calls (try_fmt, g_parm among others) changed the current standard as a side effect of that call. But the standard may only be changed by s_std. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Reviewed-by: Vaibhav Hiremath <hvaibhav@ti.com> Tested-by: Vaibhav Hiremath <hvaibhav@ti.com> Acked-by: Vaibhav Hiremath <hvaibhav@ti.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/tvp514x.c | 53 +++++++++++------------------------ 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index e826114b7fb8..40d84d73edf8 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -366,13 +366,13 @@ static int tvp514x_write_regs(struct v4l2_subdev *sd, } /** - * tvp514x_get_current_std() : Get the current standard detected by TVP5146/47 + * tvp514x_query_current_std() : Query the current standard detected by TVP5146/47 * @sd: ptr to v4l2_subdev struct * - * Get current standard detected by TVP5146/47, STD_INVALID if there is no + * Returns the current standard detected by TVP5146/47, STD_INVALID if there is no * standard detected. */ -static enum tvp514x_std tvp514x_get_current_std(struct v4l2_subdev *sd) +static enum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd) { u8 std, std_status; @@ -518,7 +518,7 @@ static int tvp514x_detect(struct v4l2_subdev *sd, * @std_id: standard V4L2 std_id ioctl enum * * Returns the current standard detected by TVP5146/47. If no active input is - * detected, returns -EINVAL + * detected then *std_id is set to 0 and the function returns 0. */ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) { @@ -530,10 +530,12 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) if (std_id == NULL) return -EINVAL; - /* get the current standard */ - current_std = tvp514x_get_current_std(sd); + *std_id = V4L2_STD_UNKNOWN; + + /* query the current standard */ + current_std = tvp514x_query_current_std(sd); if (current_std == STD_INVALID) - return -EINVAL; + return 0; input_sel = decoder->input; @@ -575,12 +577,11 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) /* check whether signal is locked */ sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1); if (lock_mask != (sync_lock_status & lock_mask)) - return -EINVAL; /* No input detected */ + return 0; /* No input detected */ - decoder->current_std = current_std; *std_id = decoder->std_list[current_std].standard.id; - v4l2_dbg(1, debug, sd, "Current STD: %s", + v4l2_dbg(1, debug, sd, "Current STD: %s\n", decoder->std_list[current_std].standard.name); return 0; } @@ -637,7 +638,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, int err; enum tvp514x_input input_sel; enum tvp514x_output output_sel; - enum tvp514x_std current_std = STD_INVALID; u8 sync_lock_status, lock_mask; int try_count = LOCK_RETRY_COUNT; @@ -721,11 +721,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, /* Allow decoder to sync up with new input */ msleep(LOCK_RETRY_DELAY); - /* get the current standard for future reference */ - current_std = tvp514x_get_current_std(sd); - if (current_std == STD_INVALID) - continue; - sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1); if (lock_mask == (sync_lock_status & lock_mask)) @@ -733,15 +728,13 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, break; } - if ((current_std == STD_INVALID) || (try_count < 0)) + if (try_count < 0) return -EINVAL; - decoder->current_std = current_std; decoder->input = input; decoder->output = output; - v4l2_dbg(1, debug, sd, "Input set to: %d, std : %d", - input_sel, current_std); + v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel); return 0; } @@ -1018,11 +1011,8 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) pix = &f->fmt.pix; /* Calculate height and width based on current standard */ - current_std = tvp514x_get_current_std(sd); - if (current_std == STD_INVALID) - return -EINVAL; + current_std = decoder->current_std; - decoder->current_std = current_std; pix->width = decoder->std_list[current_std].width; pix->height = decoder->std_list[current_std].height; @@ -1132,15 +1122,8 @@ tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) /* only capture is supported */ return -EINVAL; - memset(a, 0, sizeof(*a)); - a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - /* get the current standard */ - current_std = tvp514x_get_current_std(sd); - if (current_std == STD_INVALID) - return -EINVAL; - - decoder->current_std = current_std; + current_std = decoder->current_std; cparm = &a->parm.capture; cparm->capability = V4L2_CAP_TIMEPERFRAME; @@ -1175,11 +1158,7 @@ tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) timeperframe = &a->parm.capture.timeperframe; /* get the current standard */ - current_std = tvp514x_get_current_std(sd); - if (current_std == STD_INVALID) - return -EINVAL; - - decoder->current_std = current_std; + current_std = decoder->current_std; *timeperframe = decoder->std_list[current_std].standard.frameperiod; -- GitLab From a75ffc124611a535aec8f403817d382d106c68d7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 06:32:47 -0300 Subject: [PATCH 393/842] V4L/DVB: tvp514x: make std_list const Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Reviewed-by: Vaibhav Hiremath <hvaibhav@ti.com> Tested-by: Vaibhav Hiremath <hvaibhav@ti.com> Acked-by: Vaibhav Hiremath <hvaibhav@ti.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/tvp514x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index 40d84d73edf8..b802da713114 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -111,7 +111,7 @@ struct tvp514x_decoder { enum tvp514x_std current_std; int num_stds; - struct tvp514x_std_info *std_list; + const struct tvp514x_std_info *std_list; /* Input and Output Routing parameters */ u32 input; u32 output; @@ -223,7 +223,7 @@ static const struct v4l2_fmtdesc tvp514x_fmt_list[] = { * Currently supports two standards only, need to add support for rest of the * modes, like SECAM, etc... */ -static struct tvp514x_std_info tvp514x_std_list[] = { +static const struct tvp514x_std_info tvp514x_std_list[] = { /* Standard: STD_NTSC_MJ */ [STD_NTSC_MJ] = { .width = NTSC_NUM_ACTIVE_PIXELS, -- GitLab From c2fc80961fc2059c05bf07c92decfffde2a0f9ef Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 06:37:14 -0300 Subject: [PATCH 394/842] V4L/DVB: tvp514x: there is only one supported format, so simplify the code Get rid of unnecessary code since this driver supports only one pixel format. Removing this code will make the transition to the mbus API easier as well. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Reviewed-by: Vaibhav Hiremath <hvaibhav@ti.com> Tested-by: Vaibhav Hiremath <hvaibhav@ti.com> Acked-by: Vaibhav Hiremath <hvaibhav@ti.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/tvp514x.c | 45 +++++++---------------------------- 1 file changed, 9 insertions(+), 36 deletions(-) diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index b802da713114..cb4284384133 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -89,8 +89,6 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable); * @ver: Chip version * @streaming: TVP5146/47 decoder streaming - enabled or disabled. * @pix: Current pixel format - * @num_fmts: Number of formats - * @fmt_list: Format list * @current_std: Current standard * @num_stds: Number of standards * @std_list: Standards list @@ -106,8 +104,6 @@ struct tvp514x_decoder { int streaming; struct v4l2_pix_format pix; - int num_fmts; - const struct v4l2_fmtdesc *fmt_list; enum tvp514x_std current_std; int num_stds; @@ -960,27 +956,18 @@ tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) static int tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt) { - struct tvp514x_decoder *decoder = to_decoder(sd); - int index; - - if (fmt == NULL) - return -EINVAL; - - index = fmt->index; - if ((index >= decoder->num_fmts) || (index < 0)) - /* Index out of bound */ + if (fmt == NULL || fmt->index) return -EINVAL; if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) /* only capture is supported */ return -EINVAL; - memcpy(fmt, &decoder->fmt_list[index], - sizeof(struct v4l2_fmtdesc)); - - v4l2_dbg(1, debug, sd, "Current FMT: index - %d (%s)", - decoder->fmt_list[index].index, - decoder->fmt_list[index].description); + /* only one format */ + fmt->flags = 0; + strlcpy(fmt->description, "8-bit UYVY 4:2:2 Format", + sizeof(fmt->description)); + fmt->pixelformat = V4L2_PIX_FMT_UYVY; return 0; } @@ -997,7 +984,6 @@ static int tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) { struct tvp514x_decoder *decoder = to_decoder(sd); - int ifmt; struct v4l2_pix_format *pix; enum tvp514x_std current_std; @@ -1013,28 +999,18 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) /* Calculate height and width based on current standard */ current_std = decoder->current_std; + pix->pixelformat = V4L2_PIX_FMT_UYVY; pix->width = decoder->std_list[current_std].width; pix->height = decoder->std_list[current_std].height; - - for (ifmt = 0; ifmt < decoder->num_fmts; ifmt++) { - if (pix->pixelformat == - decoder->fmt_list[ifmt].pixelformat) - break; - } - if (ifmt == decoder->num_fmts) - /* None of the format matched, select default */ - ifmt = 0; - pix->pixelformat = decoder->fmt_list[ifmt].pixelformat; - pix->field = V4L2_FIELD_INTERLACED; pix->bytesperline = pix->width * 2; pix->sizeimage = pix->bytesperline * pix->height; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->priv = 0; - v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d" + v4l2_dbg(1, debug, sd, "Try FMT: bytesperline - %d" "Width - %d, Height - %d", - decoder->fmt_list[ifmt].description, pix->bytesperline, + pix->bytesperline, pix->width, pix->height); return 0; } @@ -1254,9 +1230,6 @@ static const struct v4l2_subdev_ops tvp514x_ops = { static struct tvp514x_decoder tvp514x_dev = { .streaming = 0, - .fmt_list = tvp514x_fmt_list, - .num_fmts = ARRAY_SIZE(tvp514x_fmt_list), - .pix = { /* Default to NTSC 8-bit YUV 422 */ .width = NTSC_NUM_ACTIVE_PIXELS, -- GitLab From 3907b07294a9a87793ca9e0223c7bf66b6108ab0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 06:39:44 -0300 Subject: [PATCH 395/842] V4L/DVB: tvp514x: add missing newlines Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Reviewed-by: Vaibhav Hiremath <hvaibhav@ti.com> Tested-by: Vaibhav Hiremath <hvaibhav@ti.com> Acked-by: Vaibhav Hiremath <hvaibhav@ti.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/tvp514x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index cb4284384133..1b03d0eb20df 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -611,7 +611,7 @@ static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id) decoder->tvp514x_regs[REG_VIDEO_STD].val = decoder->std_list[i].video_std; - v4l2_dbg(1, debug, sd, "Standard set to: %s", + v4l2_dbg(1, debug, sd, "Standard set to: %s\n", decoder->std_list[i].standard.name); return 0; } @@ -783,7 +783,7 @@ tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl) return err; } - v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d", + v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d\n", qctrl->name, qctrl->minimum, qctrl->maximum, qctrl->default_value); @@ -840,7 +840,7 @@ tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return -EINVAL; } - v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d", + v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d\n", ctrl->id, ctrl->value); return 0; } @@ -940,7 +940,7 @@ tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return err; } - v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d", + v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n", ctrl->id, ctrl->value); return err; @@ -1009,7 +1009,7 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) pix->priv = 0; v4l2_dbg(1, debug, sd, "Try FMT: bytesperline - %d" - "Width - %d, Height - %d", + "Width - %d, Height - %d\n", pix->bytesperline, pix->width, pix->height); return 0; @@ -1071,7 +1071,7 @@ tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) f->fmt.pix = decoder->pix; v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d" - "Width - %d, Height - %d", + "Width - %d, Height - %d\n", decoder->pix.bytesperline, decoder->pix.width, decoder->pix.height); return 0; -- GitLab From f1a4435f3efa510760adf6acb87c62653de9a0ee Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 06:40:18 -0300 Subject: [PATCH 396/842] V4L/DVB: tvp514x: remove obsolete fmt_list Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Reviewed-by: Vaibhav Hiremath <hvaibhav@ti.com> Tested-by: Vaibhav Hiremath <hvaibhav@ti.com> Acked-by: Vaibhav Hiremath <hvaibhav@ti.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/tvp514x.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index 1b03d0eb20df..bb5df5176377 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -198,21 +198,6 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = { {TOK_TERM, 0, 0}, }; -/** - * List of image formats supported by TVP5146/47 decoder - * Currently we are using 8 bit mode only, but can be - * extended to 10/20 bit mode. - */ -static const struct v4l2_fmtdesc tvp514x_fmt_list[] = { - { - .index = 0, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .flags = 0, - .description = "8-bit UYVY 4:2:2 Format", - .pixelformat = V4L2_PIX_FMT_UYVY, - }, -}; - /** * Supported standards - * -- GitLab From 283d637bbd7301c9fb2236103b990b9d66099d78 Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Sun, 9 May 2010 06:44:16 -0300 Subject: [PATCH 397/842] V4L/DVB: tvp514x: simplify try/g/s_fmt handling Since there is only one possible format just have all three calls do the same. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Reviewed-by: Vaibhav Hiremath <hvaibhav@ti.com> Tested-by: Vaibhav Hiremath <hvaibhav@ti.com> Acked-by: Vaibhav Hiremath <hvaibhav@ti.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/tvp514x.c | 98 ++++------------------------------- 1 file changed, 9 insertions(+), 89 deletions(-) diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index bb5df5176377..71c73fa0d68c 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -88,7 +88,6 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable); * @pdata: Board specific * @ver: Chip version * @streaming: TVP5146/47 decoder streaming - enabled or disabled. - * @pix: Current pixel format * @current_std: Current standard * @num_stds: Number of standards * @std_list: Standards list @@ -103,8 +102,6 @@ struct tvp514x_decoder { int ver; int streaming; - struct v4l2_pix_format pix; - enum tvp514x_std current_std; int num_stds; const struct tvp514x_std_info *std_list; @@ -957,16 +954,15 @@ tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt) } /** - * tvp514x_try_fmt_cap() - V4L2 decoder interface handler for try_fmt + * tvp514x_fmt_cap() - V4L2 decoder interface handler for try/s/g_fmt * @sd: pointer to standard V4L2 sub-device structure * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure * - * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This - * ioctl is used to negotiate the image capture size and pixel format - * without actually making it take effect. + * Implement the VIDIOC_TRY/S/G_FMT ioctl for the CAPTURE buffer type. This + * ioctl is used to negotiate the image capture size and pixel format. */ static int -tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) +tvp514x_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) { struct tvp514x_decoder *decoder = to_decoder(sd); struct v4l2_pix_format *pix; @@ -976,8 +972,7 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) return -EINVAL; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return -EINVAL; pix = &f->fmt.pix; @@ -993,75 +988,13 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->priv = 0; - v4l2_dbg(1, debug, sd, "Try FMT: bytesperline - %d" + v4l2_dbg(1, debug, sd, "FMT: bytesperline - %d" "Width - %d, Height - %d\n", pix->bytesperline, pix->width, pix->height); return 0; } -/** - * tvp514x_s_fmt_cap() - V4L2 decoder interface handler for s_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure - * - * If the requested format is supported, configures the HW to use that - * format, returns error code if format not supported or HW can't be - * correctly configured. - */ -static int -tvp514x_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - struct v4l2_pix_format *pix; - int rval; - - if (f == NULL) - return -EINVAL; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - return -EINVAL; - - pix = &f->fmt.pix; - rval = tvp514x_try_fmt_cap(sd, f); - if (rval) - return rval; - - decoder->pix = *pix; - - return rval; -} - -/** - * tvp514x_g_fmt_cap() - V4L2 decoder interface handler for tvp514x_g_fmt_cap - * @sd: pointer to standard V4L2 sub-device structure - * @f: pointer to standard V4L2 v4l2_format structure - * - * Returns the decoder's current pixel format in the v4l2_format - * parameter. - */ -static int -tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - - if (f == NULL) - return -EINVAL; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - /* only capture is supported */ - return -EINVAL; - - f->fmt.pix = decoder->pix; - - v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d" - "Width - %d, Height - %d\n", - decoder->pix.bytesperline, - decoder->pix.width, decoder->pix.height); - return 0; -} - /** * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm * @sd: pointer to standard V4L2 sub-device structure @@ -1199,9 +1132,9 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_routing = tvp514x_s_routing, .querystd = tvp514x_querystd, .enum_fmt = tvp514x_enum_fmt_cap, - .g_fmt = tvp514x_g_fmt_cap, - .try_fmt = tvp514x_try_fmt_cap, - .s_fmt = tvp514x_s_fmt_cap, + .g_fmt = tvp514x_fmt_cap, + .try_fmt = tvp514x_fmt_cap, + .s_fmt = tvp514x_fmt_cap, .g_parm = tvp514x_g_parm, .s_parm = tvp514x_s_parm, .s_stream = tvp514x_s_stream, @@ -1214,19 +1147,6 @@ static const struct v4l2_subdev_ops tvp514x_ops = { static struct tvp514x_decoder tvp514x_dev = { .streaming = 0, - - .pix = { - /* Default to NTSC 8-bit YUV 422 */ - .width = NTSC_NUM_ACTIVE_PIXELS, - .height = NTSC_NUM_ACTIVE_LINES, - .pixelformat = V4L2_PIX_FMT_UYVY, - .field = V4L2_FIELD_INTERLACED, - .bytesperline = NTSC_NUM_ACTIVE_PIXELS * 2, - .sizeimage = - NTSC_NUM_ACTIVE_PIXELS * 2 * NTSC_NUM_ACTIVE_LINES, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - }, - .current_std = STD_NTSC_MJ, .std_list = tvp514x_std_list, .num_stds = ARRAY_SIZE(tvp514x_std_list), -- GitLab From 76952c7e598f68bf12adf307d6a9a0de3b33b985 Mon Sep 17 00:00:00 2001 From: Guy Martin <gmsoft@tuxicoman.be> Date: Fri, 7 May 2010 04:09:25 -0300 Subject: [PATCH 398/842] V4L/DVB: TT CT-3650 DVB-C support Add support for the DVB-C frontend of the TT CT-3650. DVB-T fe, CI and IR are not implemented. Signed-off-by: Guy Martin <gmsoft@tuxicoman.be> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + drivers/media/dvb/dvb-usb/ttusb2.c | 95 +++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 085c4e457e0e..b4afe6f8ed19 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -198,6 +198,7 @@ #define USB_PID_AVERMEDIA_A850 0x850a #define USB_PID_AVERMEDIA_A805 0xa805 #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 +#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 20ca9d9ee99b..a6de489a6a39 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -29,6 +29,8 @@ #include "tda826x.h" #include "tda10086.h" +#include "tda1002x.h" +#include "tda827x.h" #include "lnbp21.h" /* debug */ @@ -150,7 +152,17 @@ static struct tda10086_config tda10086_config = { .xtal_freq = TDA10086_XTAL_16M, }; -static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap) +static struct tda10023_config tda10023_config = { + .demod_address = 0x0c, + .invert = 0, + .xtal = 16000000, + .pll_m = 11, + .pll_p = 3, + .pll_n = 1, + .deltaf = 0xa511, +}; + +static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) { if (usb_set_interface(adap->dev->udev,0,3) < 0) err("set interface to alts=3 failed"); @@ -163,7 +175,27 @@ static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap) return 0; } -static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap) +static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 3) < 0) + err("set interface to alts=3 failed"); + if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) { + deb_info("TDA10023 attach failed\n"); + return -ENODEV; + } + return 0; +} + +static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) +{ + if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) { + printk(KERN_ERR "%s: No tda827x found!\n", __func__); + return -ENODEV; + } + return 0; +} + +static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) { if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { deb_info("TDA8263 attach failed\n"); @@ -180,6 +212,7 @@ static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap) /* DVB USB Driver stuff */ static struct dvb_usb_device_properties ttusb2_properties; static struct dvb_usb_device_properties ttusb2_properties_s2400; +static struct dvb_usb_device_properties ttusb2_properties_ct3650; static int ttusb2_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -187,6 +220,8 @@ static int ttusb2_probe(struct usb_interface *intf, if (0 == dvb_usb_device_init(intf, &ttusb2_properties, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650, THIS_MODULE, NULL, adapter_nr)) return 0; return -ENODEV; @@ -197,6 +232,8 @@ static struct usb_device_id ttusb2_table [] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2400) }, + { USB_DEVICE(USB_VID_TECHNOTREND, + USB_PID_TECHNOTREND_CONNECT_CT3650) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, ttusb2_table); @@ -214,8 +251,8 @@ static struct dvb_usb_device_properties ttusb2_properties = { { .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, - .frontend_attach = ttusb2_frontend_attach, - .tuner_attach = ttusb2_tuner_attach, + .frontend_attach = ttusb2_frontend_tda10086_attach, + .tuner_attach = ttusb2_tuner_tda826x_attach, /* parameter for the MPEG2-data transfer */ .stream = { @@ -266,8 +303,8 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = { { .streaming_ctrl = NULL, - .frontend_attach = ttusb2_frontend_attach, - .tuner_attach = ttusb2_tuner_attach, + .frontend_attach = ttusb2_frontend_tda10086_attach, + .tuner_attach = ttusb2_tuner_tda826x_attach, /* parameter for the MPEG2-data transfer */ .stream = { @@ -301,6 +338,52 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = { } }; +static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct ttusb2_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = NULL, + + .frontend_attach = ttusb2_frontend_tda10023_attach, + .tuner_attach = ttusb2_tuner_tda827x_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + }, + }, + + .power_ctrl = ttusb2_power_ctrl, + .identify_state = ttusb2_identify_state, + + .i2c_algo = &ttusb2_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Technotrend TT-connect CT-3650", + .warm_ids = { &ttusb2_table[3], NULL }, + }, + } +}; + static struct usb_driver ttusb2_driver = { .name = "dvb_usb_ttusb2", .probe = ttusb2_probe, -- GitLab From e65f8c4e3eef3a0946f8e8fba1fb6aabde734f50 Mon Sep 17 00:00:00 2001 From: Guy Martin <gmsoft@tuxicoman.be> Date: Fri, 7 May 2010 04:34:40 -0300 Subject: [PATCH 399/842] V4L/DVB: stv6110x: Fix kernel null pointer deref The following OOPS happened when plugging two TT s2-1600: [ 96.521023] saa7146: register extension 'budget dvb'. [ 96.521052] budget dvb 0000:05:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16 [ 96.521070] IRQ 16/: IRQF_DISABLED is not guaranteed on shared IRQs [ 96.521076] saa7146: found saa7146 @ mem ffffc90011182c00 (revision 1, irq 16) (0x13c2,0x101c). [ 96.521080] saa7146 (0): dma buffer size 192512 [ 96.521081] DVB: registering new adapter (TT-Budget S2-1600 PCI) [ 96.539929] adapter has MAC addr = 00:d0:5c:cc:b0:a2 [ 96.890149] stv6110x_attach: Attaching STV6110x [ 96.912516] DVB: registering adapter 0 frontend 0 (STV090x Multistandard)... [ 96.912600] budget dvb 0000:05:01.0: PCI INT A -> GSI 17 (level, low) -> IRQ 17 [ 96.912639] IRQ 17/: IRQF_DISABLED is not guaranteed on shared IRQs [ 96.912667] saa7146: found saa7146 @ mem ffffc90011314800 (revision 1, irq 17) (0x13c2,0x101c). [ 96.912673] saa7146 (1): dma buffer size 192512 [ 96.912676] DVB: registering new adapter (TT-Budget S2-1600 PCI) [ 96.930893] adapter has MAC addr = 00:d0:5c:cc:b0:a3 [ 97.233478] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 [ 97.233647] IP: [<ffffffffa029c450>] stv6110x_set_mode+0x70/0x80 [stv6110x] [ 97.233753] PGD 3c16f067 PUD 3c383067 PMD 0 [ 97.234147] CPU 0 [ 97.234246] Pid: 5200, comm: modprobe Not tainted 2.6.33.2 #1 P5QSE/P5Q SE [ 97.234317] RIP: 0010:[<ffffffffa029c450>] [<ffffffffa029c450>] stv6110x_set_mode+0x70/0x80 [stv6110x] [ 97.234456] RSP: 0018:ffff88003c125c98 EFLAGS: 00010246 [ 97.234461] RAX: ffffffffa029c460 RBX: ffff88003f84d800 RCX: ffff88003a19e140 [ 97.234461] RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000 [ 97.234461] RBP: ffff88003f84d828 R08: 0000000000000002 R09: 0000000000000004 [ 97.234461] R10: 0000000000000003 R11: 0000000000000010 R12: ffff88003f84d800 [ 97.234461] R13: ffff88003f84d828 R14: ffff88003f84d828 R15: 0000000000000001 [ 97.234461] FS: 00007f9f7253e6f0(0000) GS:ffff880001800000(0000) knlGS:0000000000000000 [ 97.234461] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 97.234461] CR2: 0000000000000010 CR3: 000000003c382000 CR4: 00000000000006b0 [ 97.234461] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 97.234461] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 97.234461] Process modprobe (pid: 5200, threadinfo ffff88003c124000, task ffff88003e893ac0) [ 97.234461] ffff88003f84d800 ffff88003f84d828 ffff88003f84d800 ffffffffa0292343 [ 97.234461] <0> ffff88003f84d828 ffff88003ef70ae0 ffffffffa0280800 ffffffffa02934d2 [ 97.234461] <0> ffffffffa0295260 0000000000000000 ffffffffa02948b0 ffff88003df79800 [ 97.234461] [<ffffffffa0292343>] ? stv090x_sleep+0x33/0x120 [stv090x] [ 97.234461] [<ffffffffa02934d2>] ? stv090x_attach+0x1e2/0x73c [stv090x] [ 97.234461] [<ffffffff81007cc5>] ? dma_generic_alloc_coherent+0xa5/0x160 [ 97.234461] [<ffffffffa026e1f5>] ? saa7146_init_one+0x7d5/0x910 [saa7146] [ 97.234461] [<ffffffff811b84b2>] ? local_pci_probe+0x12/0x20 [ 97.234461] [<ffffffff811b87d0>] ? pci_device_probe+0x110/0x120 [ 97.234461] [<ffffffff81221788>] ? driver_probe_device+0x98/0x1b0 [ 97.234461] [<ffffffff81221933>] ? __driver_attach+0x93/0xa0 [ 97.234461] [<ffffffff812218a0>] ? __driver_attach+0x0/0xa0 [ 97.234461] [<ffffffff81220f18>] ? bus_for_each_dev+0x58/0x80 [ 97.234461] [<ffffffff8122079d>] ? bus_add_driver+0x14d/0x280 [ 97.234461] [<ffffffffa0284000>] ? budget_init+0x0/0xc [budget] [ 97.234461] [<ffffffff81221c29>] ? driver_register+0x79/0x170 [ 97.234461] [<ffffffffa0284000>] ? budget_init+0x0/0xc [budget] [ 97.234461] [<ffffffff811b8a48>] ? __pci_register_driver+0x58/0xe0 [ 97.234461] [<ffffffffa0284000>] ? budget_init+0x0/0xc [budget] [ 97.234461] [<ffffffff810001d5>] ? do_one_initcall+0x35/0x190 [ 97.234461] [<ffffffff81063d37>] ? sys_init_module+0xe7/0x260 [ 97.234461] [<ffffffff8100256b>] ? system_call_fastpath+0x16/0x1b [ 97.234461] RIP [<ffffffffa029c450>] stv6110x_set_mode+0x70/0x80 [stv6110x] [ 97.234461] RSP <ffff88003c125c98> [ 97.240074] ---[ end trace b53ecbbbbef15e99 ]--- Prevents calling stv6110x_set_mode() if fe->tuner_priv is not defined, in order to avoid the above bug. Signed-off-by: Guy Martin <gmsoft@tuxicoman.be> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/frontends/stv6110x.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c index 42591ce1aaad..f36cab12bdc7 100644 --- a/drivers/media/dvb/frontends/stv6110x.c +++ b/drivers/media/dvb/frontends/stv6110x.c @@ -303,7 +303,10 @@ static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode) static int stv6110x_sleep(struct dvb_frontend *fe) { - return stv6110x_set_mode(fe, TUNER_SLEEP); + if (fe->tuner_priv) + return stv6110x_set_mode(fe, TUNER_SLEEP); + + return 0; } static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status) -- GitLab From 9e1d9e7bac5c2bafc3c0c51db88c15f3fbcec83f Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski <herton@mandriva.com.br> Date: Sat, 8 May 2010 02:23:37 -0300 Subject: [PATCH 400/842] V4L/DVB: saa7134: add support for Avermedia M733A This change adds support for Avermedia M733A. The original version for linux 2.6.31 was sent to me from Avermedia, original author is unknown. I ported it to current kernels, expanded and fixed key code handling for RM-K6 remote control, and added an additional pci id also supported. [mchehab@redhat.com: make checkpatch.pl happier] Signed-off-by: Herton Ronaldo Krzesinski <herton@mandriva.com.br> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- Documentation/video4linux/CARDLIST.saa7134 | 5 +- drivers/media/IR/keymaps/Makefile | 1 + .../IR/keymaps/rc-avermedia-m733a-rm-k6.c | 95 +++++++++++++++++++ drivers/media/video/saa7134/saa7134-cards.c | 55 +++++++++++ drivers/media/video/saa7134/saa7134-input.c | 7 ++ drivers/media/video/saa7134/saa7134.h | 1 + include/media/rc-map.h | 1 + 7 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 070f2576707e..1387a69ae3aa 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -176,5 +176,6 @@ 175 -> Leadtek Winfast DTV1000S [107d:6655] 176 -> Beholder BeholdTV 505 RDS [0000:5051] 177 -> Hawell HW-404M7 -179 -> Beholder BeholdTV H7 [5ace:7190] -180 -> Beholder BeholdTV A7 [5ace:7090] +178 -> Beholder BeholdTV H7 [5ace:7190] +179 -> Beholder BeholdTV A7 [5ace:7090] +180 -> Avermedia M733A [1461:4155,1461:4255] diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile index ec25258a955f..585f75c3f376 100644 --- a/drivers/media/IR/keymaps/Makefile +++ b/drivers/media/IR/keymaps/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-avermedia-cardbus.o \ rc-avermedia-dvbt.o \ rc-avermedia-m135a-rm-jx.o \ + rc-avermedia-m733a-rm-k6.o \ rc-avertv-303.o \ rc-behold.o \ rc-behold-columbus.o \ diff --git a/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c new file mode 100644 index 000000000000..cf8d45717cb3 --- /dev/null +++ b/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c @@ -0,0 +1,95 @@ +/* avermedia-m733a-rm-k6.h - Keytable for avermedia_m733a_rm_k6 Remote Controller + * + * Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <media/rc-map.h> + +/* + * Avermedia M733A with IR model RM-K6 + * This is the stock remote controller used with Positivo machines with M733A + * Herton Ronaldo Krzesinski <herton@mandriva.com.br> + */ + +static struct ir_scancode avermedia_m733a_rm_k6[] = { + { 0x0401, KEY_POWER2 }, + { 0x0406, KEY_MUTE }, + { 0x0408, KEY_MODE }, /* TV/FM */ + + { 0x0409, KEY_1 }, + { 0x040a, KEY_2 }, + { 0x040b, KEY_3 }, + { 0x040c, KEY_4 }, + { 0x040d, KEY_5 }, + { 0x040e, KEY_6 }, + { 0x040f, KEY_7 }, + { 0x0410, KEY_8 }, + { 0x0411, KEY_9 }, + { 0x044c, KEY_DOT }, /* '.' */ + { 0x0412, KEY_0 }, + { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ + + { 0x0413, KEY_AUDIO }, + { 0x0440, KEY_SCREEN }, /* Full Screen toggle */ + { 0x0441, KEY_HOME }, + { 0x0442, KEY_BACK }, + { 0x0447, KEY_UP }, + { 0x0448, KEY_DOWN }, + { 0x0449, KEY_LEFT }, + { 0x044a, KEY_RIGHT }, + { 0x044b, KEY_OK }, + { 0x0404, KEY_VOLUMEUP }, + { 0x0405, KEY_VOLUMEDOWN }, + { 0x0402, KEY_CHANNELUP }, + { 0x0403, KEY_CHANNELDOWN }, + + { 0x0443, KEY_RED }, + { 0x0444, KEY_GREEN }, + { 0x0445, KEY_YELLOW }, + { 0x0446, KEY_BLUE }, + + { 0x0414, KEY_TEXT }, + { 0x0415, KEY_EPG }, + { 0x041a, KEY_TV2 }, /* PIP */ + { 0x041b, KEY_MHP }, /* Snapshot */ + + { 0x0417, KEY_RECORD }, + { 0x0416, KEY_PLAYPAUSE }, + { 0x0418, KEY_STOP }, + { 0x0419, KEY_PAUSE }, + + { 0x041f, KEY_PREVIOUS }, + { 0x041c, KEY_REWIND }, + { 0x041d, KEY_FORWARD }, + { 0x041e, KEY_NEXT }, +}; + +static struct rc_keymap avermedia_m733a_rm_k6_map = { + .map = { + .scan = avermedia_m733a_rm_k6, + .size = ARRAY_SIZE(avermedia_m733a_rm_k6), + .ir_type = IR_TYPE_NEC, + .name = RC_MAP_AVERMEDIA_M733A_RM_K6, + } +}; + +static int __init init_rc_map_avermedia_m733a_rm_k6(void) +{ + return ir_register_map(&avermedia_m733a_rm_k6_map); +} + +static void __exit exit_rc_map_avermedia_m733a_rm_k6(void) +{ + ir_unregister_map(&avermedia_m733a_rm_k6_map); +} + +module_init(init_rc_map_avermedia_m733a_rm_k6) +module_exit(exit_rc_map_avermedia_m733a_rm_k6) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 72700d4e3941..07f6bb8ef9d9 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3897,6 +3897,40 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x01, }, }, + [SAA7134_BOARD_AVERMEDIA_M733A] = { + .name = "Avermedia PCI M733A", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tuner_config = 0, + .gpiomask = 0x020200000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x00200000, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x01, + }, + }, [SAA7134_BOARD_BEHOLD_401] = { /* Beholder Intl. Ltd. 2008 */ /*Dmitry Belimov <d.belimov@gmail.com> */ @@ -5820,6 +5854,18 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0xf11d, .driver_data = SAA7134_BOARD_AVERMEDIA_M135A, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x4155, + .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x4255, + .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, }, { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, @@ -6786,6 +6832,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev, switch (dev->board) { case SAA7134_BOARD_HAUPPAUGE_HVR1150: case SAA7134_BOARD_HAUPPAUGE_HVR1120: + case SAA7134_BOARD_AVERMEDIA_M733A: /* tda8290 + tda18271 */ ret = saa7134_tda8290_18271_callback(dev, command, arg); break; @@ -7087,6 +7134,14 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0000C000, 0x0000C000); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0000C000, 0x0000C000); break; + case SAA7134_BOARD_AVERMEDIA_M733A: + saa7134_set_gpio(dev, 1, 1); + msleep(10); + saa7134_set_gpio(dev, 1, 0); + msleep(10); + saa7134_set_gpio(dev, 1, 1); + dev->has_remote = SAA7134_REMOTE_GPIO; + break; } return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index e5565e2fd426..f9ed8048894d 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -663,6 +663,13 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keycode = 0xffff; raw_decode = 1; break; + case SAA7134_BOARD_AVERMEDIA_M733A: + ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6; + mask_keydown = 0x0040000; + mask_keyup = 0x0040000; + mask_keycode = 0xffff; + raw_decode = 1; + break; case SAA7134_BOARD_AVERMEDIA_777: case SAA7134_BOARD_AVERMEDIA_A16AR: ir_codes = RC_MAP_AVERMEDIA; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 3962534267be..756a1ca8833d 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -303,6 +303,7 @@ struct saa7134_format { #define SAA7134_BOARD_HAWELL_HW_404M7 177 #define SAA7134_BOARD_BEHOLD_H7 178 #define SAA7134_BOARD_BEHOLD_A7 179 +#define SAA7134_BOARD_AVERMEDIA_M733A 180 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 5833966a7100..6f1f9f76674e 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -56,6 +56,7 @@ void rc_map_init(void); #define RC_MAP_AVERMEDIA_CARDBUS "rc-avermedia-cardbus" #define RC_MAP_AVERMEDIA_DVBT "rc-avermedia-dvbt" #define RC_MAP_AVERMEDIA_M135A_RM_JX "rc-avermedia-m135a-rm-jx" +#define RC_MAP_AVERMEDIA_M733A_RM_K6 "rc-avermedia-m733a-rm-k6" #define RC_MAP_AVERMEDIA "rc-avermedia" #define RC_MAP_AVERTV_303 "rc-avertv-303" #define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus" -- GitLab From 0439db75c1fbb28a3b314ae354582e4f180daf52 Mon Sep 17 00:00:00 2001 From: Stefan Ringel <stefan.ringel@arcor.de> Date: Mon, 10 May 2010 13:22:51 -0300 Subject: [PATCH 401/842] V4L/DVB: tm6000: add extension module support add module init over tm6000 extension Signed-off-by: Stefan Ringel <stefan.ringel@arcor.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/tm6000-alsa.c | 25 +++++++- drivers/staging/tm6000/tm6000-cards.c | 7 ++ drivers/staging/tm6000/tm6000-core.c | 92 +++++++++++++++++++++++++++ drivers/staging/tm6000/tm6000.h | 23 ++++++- 4 files changed, 145 insertions(+), 2 deletions(-) diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c index bc89f9d28002..ce081cd44ad4 100644 --- a/drivers/staging/tm6000/tm6000-alsa.c +++ b/drivers/staging/tm6000/tm6000-alsa.c @@ -410,5 +410,28 @@ error: snd_card_free(card); return rc; } -EXPORT_SYMBOL_GPL(tm6000_audio_init); +static int tm6000_audio_fini(struct tm6000_core *dev) +{ + return 0; +} + +struct tm6000_ops audio_ops = { + .id = TM6000_AUDIO, + .name = "TM6000 Audio Extension", + .init = tm6000_audio_init, + .fini = tm6000_audio_fini, +}; + +static int __init tm6000_alsa_register(void) +{ + return tm6000_register_extension(&audio_ops); +} + +static void __exit tm6000_alsa_unregister(void) +{ + tm6000_unregister_extension(&audio_ops); +} + +module_init(tm6000_alsa_register); +module_exit(tm6000_alsa_unregister); diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 6143e20d139d..ab12291e0b42 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -692,6 +692,10 @@ static int tm6000_init_dev(struct tm6000_core *dev) if (rc < 0) goto err; + tm6000_add_into_devlist(dev); + + tm6000_init_extension(dev); + if (dev->caps.has_dvb) { dev->dvb = kzalloc(sizeof(*(dev->dvb)), GFP_KERNEL); if (!dev->dvb) { @@ -931,6 +935,9 @@ static void tm6000_usb_disconnect(struct usb_interface *interface) usb_put_dev(dev->udev); + tm6000_remove_from_devlist(dev); + tm6000_close_extension(dev); + mutex_unlock(&dev->lock); kfree(dev); } diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index bfbc53bd2912..1259ae550547 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -600,3 +600,95 @@ printk("Original value=%d\n",val); return val; } EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate); + +static LIST_HEAD(tm6000_devlist); +static DEFINE_MUTEX(tm6000_devlist_mutex); + +/* + * tm6000_realease_resource() + */ + +void tm6000_remove_from_devlist(struct tm6000_core *dev) +{ + mutex_lock(&tm6000_devlist_mutex); + list_del(&dev->devlist); + mutex_unlock(&tm6000_devlist_mutex); +}; + +void tm6000_add_into_devlist(struct tm6000_core *dev) +{ + mutex_lock(&tm6000_devlist_mutex); + list_add_tail(&dev->devlist, &tm6000_devlist); + mutex_unlock(&tm6000_devlist_mutex); +}; + +/* + * Extension interface + */ + +static LIST_HEAD(tm6000_extension_devlist); +static DEFINE_MUTEX(tm6000_extension_devlist_lock); + +int tm6000_register_extension(struct tm6000_ops *ops) +{ + struct tm6000_core *dev = NULL; + + mutex_lock(&tm6000_devlist_mutex); + mutex_lock(&tm6000_extension_devlist_lock); + list_add_tail(&ops->next, &tm6000_extension_devlist); + list_for_each_entry(dev, &tm6000_devlist, devlist) { + if (dev) + ops->init(dev); + } + printk(KERN_INFO "tm6000: Initialized (%s) extension\n", ops->name); + mutex_unlock(&tm6000_extension_devlist_lock); + mutex_unlock(&tm6000_devlist_mutex); + return 0; +} +EXPORT_SYMBOL(tm6000_register_extension); + +void tm6000_unregister_extension(struct tm6000_ops *ops) +{ + struct tm6000_core *dev = NULL; + + mutex_lock(&tm6000_devlist_mutex); + list_for_each_entry(dev, &tm6000_devlist, devlist) { + if (dev) + ops->fini(dev); + } + + mutex_lock(&tm6000_extension_devlist_lock); + printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name); + list_del(&ops->next); + mutex_unlock(&tm6000_extension_devlist_lock); + mutex_unlock(&tm6000_devlist_mutex); +} +EXPORT_SYMBOL(tm6000_unregister_extension); + +void tm6000_init_extension(struct tm6000_core *dev) +{ + struct tm6000_ops *ops = NULL; + + mutex_lock(&tm6000_extension_devlist_lock); + if (!list_empty(&tm6000_extension_devlist)) { + list_for_each_entry(ops, &tm6000_extension_devlist, next) { + if (ops->init) + ops->init(dev); + } + } + mutex_unlock(&tm6000_extension_devlist_lock); +} + +void tm6000_close_extension(struct tm6000_core *dev) +{ + struct tm6000_ops *ops = NULL; + + mutex_lock(&tm6000_extension_devlist_lock); + if (!list_empty(&tm6000_extension_devlist)) { + list_for_each_entry(ops, &tm6000_extension_devlist, next) { + if (ops->fini) + ops->fini(dev); + } + } + mutex_unlock(&tm6000_extension_devlist_lock); +} diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index 6812d6867d57..79ef72a3f431 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -168,6 +168,10 @@ struct tm6000_core { struct i2c_adapter i2c_adap; struct i2c_client i2c_client; + + /* extension */ + struct list_head devlist; + /* video for linux */ int users; @@ -203,6 +207,16 @@ struct tm6000_core { spinlock_t slock; }; +#define TM6000_AUDIO 0x10 + +struct tm6000_ops { + struct list_head next; + char *name; + int id; + int (*init)(struct tm6000_core *); + int (*fini)(struct tm6000_core *); +}; + struct tm6000_fh { struct tm6000_core *dev; @@ -246,6 +260,13 @@ int tm6000_v4l2_unregister(struct tm6000_core *dev); int tm6000_v4l2_exit(void); void tm6000_set_fourcc_format(struct tm6000_core *dev); +void tm6000_remove_from_devlist(struct tm6000_core *dev); +void tm6000_add_into_devlist(struct tm6000_core *dev); +int tm6000_register_extension(struct tm6000_ops *ops); +void tm6000_unregister_extension(struct tm6000_ops *ops); +void tm6000_init_extension(struct tm6000_core *dev); +void tm6000_close_extension(struct tm6000_core *dev); + /* In tm6000-stds.c */ void tm6000_get_std_res(struct tm6000_core *dev); int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm); @@ -275,7 +296,7 @@ unsigned int tm6000_v4l2_poll(struct file *file, int tm6000_queue_init(struct tm6000_core *dev); /* In tm6000-alsa.c */ -int tm6000_audio_init(struct tm6000_core *dev, int idx); +/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/ /* Debug stuff */ -- GitLab From b9eb39d8f419d76e1d59febe48a6791f1fbb68c4 Mon Sep 17 00:00:00 2001 From: Stefan Ringel <stefan.ringel@arcor.de> Date: Mon, 10 May 2010 13:22:50 -0300 Subject: [PATCH 402/842] V4L/DVB: tm6000: Remove an extra ; symbol Signed-off-by: Stefan Ringel <stefan.ringel@arcor.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/tm6000-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index ab12291e0b42..33b134b521be 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -563,7 +563,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev) switch (dev->tuner_type) { case TUNER_XC2028: - tun_setup.tuner_callback = tm6000_tuner_callback;; + tun_setup.tuner_callback = tm6000_tuner_callback; break; case TUNER_XC5000: tun_setup.tuner_callback = tm6000_xc5000_callback; -- GitLab From 2a15ac7ad625dc22885446016d730a451df1b7d4 Mon Sep 17 00:00:00 2001 From: Dmitri Belimov <d.belimov@gmail.com> Date: Tue, 18 May 2010 04:23:29 -0300 Subject: [PATCH 403/842] V4L/DVB: tm6000, reset I2C bus function Add new function for reset I2C bus. Rework some code for use this function. Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/tm6000-cards.c | 17 ++--------------- drivers/staging/tm6000/tm6000-core.c | 16 ++++++++++++++++ drivers/staging/tm6000/tm6000.h | 2 ++ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 33b134b521be..22fbd75a551d 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -363,13 +363,7 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg) tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x02, arg); msleep(10); - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - TM6000_GPIO_CLK, 0); - if (rc < 0) - return rc; - msleep(10); - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - TM6000_GPIO_CLK, 1); + rc = tm6000_i2c_reset(dev, 10); break; case XC2028_TUNER_RESET: /* Reset codes during load firmware */ @@ -423,14 +417,7 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg) break; case 2: - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - TM6000_GPIO_CLK, 0); - if (rc < 0) - return rc; - msleep(100); - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - TM6000_GPIO_CLK, 1); - msleep(100); + rc = tm6000_i2c_reset(dev, 100); break; } } diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 1259ae550547..65feb8cb421c 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -153,6 +153,22 @@ int tm6000_get_reg32 (struct tm6000_core *dev, u8 req, u16 value, u16 index) return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24; } +int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep) +{ + int rc; + + rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0); + if (rc < 0) + return rc; + + msleep(tsleep); + + rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1); + msleep(tsleep); + + return rc; +} + void tm6000_set_fourcc_format(struct tm6000_core *dev) { if (dev->dev_type == TM6010) { diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index 79ef72a3f431..7bbaf26dea14 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -246,6 +246,8 @@ int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index); int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index); int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index); int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index); +int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep); + int tm6000_init (struct tm6000_core *dev); int tm6000_init_analog_mode (struct tm6000_core *dev); -- GitLab From 0f9bdbc2da442a78990579cabc1554446ed784a7 Mon Sep 17 00:00:00 2001 From: Stefan Ringel <stefan.ringel@arcor.de> Date: Wed, 19 May 2010 13:58:24 -0300 Subject: [PATCH 404/842] V4L/DVB: tm6000: bugfix incorrect size Signed-off-by: Stefan Ringel <stefan.ringel@arcor.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/tm6000-video.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index f2b7fe4a3581..2adf3cc972d3 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -205,7 +205,11 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp, c = (header >> 24) & 0xff; /* split the header fields */ - size = (((header & 0x7e) << 1) -1) *4; + size = ((header & 0x7e) << 1); + + if (size > 0) + size -= 4; + block = (header >> 7) & 0xf; field = (header >> 11) & 0x1; line = (header >> 12) & 0x1ff; -- GitLab From 3569417e5a2c20764158961a2f6c514d26136e5f Mon Sep 17 00:00:00 2001 From: Stefan Ringel <stefan.ringel@arcor.de> Date: Wed, 19 May 2010 13:58:25 -0300 Subject: [PATCH 405/842] V4L/DVB: tm6000: add vbi message inside the type switch add case line for vbi message Signed-off-by: Stefan Ringel <stefan.ringel@arcor.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/tm6000-video.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index 2adf3cc972d3..02b88b550a47 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -311,10 +311,12 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp, case TM6000_URB_MSG_PTS: break; case TM6000_URB_MSG_AUDIO: -/* Need some code to process audio */ -printk ("%ld: cmd=%s, size=%d\n", jiffies, + /* Need some code to process audio */ + printk ("%ld: cmd=%s, size=%d\n", jiffies, tm6000_msg_type[cmd],size); break; + case TM6000_URB_MSG_VBI: + break; default: dprintk (dev, V4L2_DEBUG_ISOC, "cmd=%s, size=%d\n", tm6000_msg_type[cmd],size); -- GitLab From 4b6ed9fd0baf34da6912bebee46c36eda0411984 Mon Sep 17 00:00:00 2001 From: Stefan Ringel <stefan.ringel@arcor.de> Date: Wed, 19 May 2010 13:58:26 -0300 Subject: [PATCH 406/842] V4L/DVB: tm6000: bugfix video image bugfix: Avoid loosing frames, causing image delays on some of the image lines. [mchehab@redhat.com: Fix compilation breakage by merging with the patch fix] Signed-off-by: Stefan Ringel <stefan.ringel@arcor.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/tm6000-video.c | 88 ++++++++++++++------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index 02b88b550a47..8acfebdb5cda 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -339,14 +339,23 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp, return rc; } -static int copy_streams(u8 *data, u8 *out_p, unsigned long len, - struct urb *urb, struct tm6000_buffer **buf) +static int copy_streams(u8 *data, unsigned long len, + struct urb *urb) { struct tm6000_dmaqueue *dma_q = urb->context; struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq); u8 *ptr=data, *endp=data+len; unsigned long header=0; int rc=0; + struct tm6000_buffer *buf; + char *outp = NULL; + + get_next_buf(dma_q, &buf); + if (buf) + outp = videobuf_to_vmalloc(&buf->vb); + + if (!outp) + return 0; for (ptr=data; ptr<endp;) { if (!dev->isoc_ctl.cmd) { @@ -394,14 +403,14 @@ static int copy_streams(u8 *data, u8 *out_p, unsigned long len, } HEADER: /* Copy or continue last copy */ - rc=copy_packet(urb,header,&ptr,endp,out_p,buf); + rc=copy_packet(urb,header,&ptr,endp,outp,&buf); if (rc<0) { buf=NULL; printk(KERN_ERR "tm6000: buffer underrun at %ld\n", jiffies); return rc; } - if (!*buf) + if (!buf) return 0; } @@ -410,31 +419,40 @@ HEADER: /* * Identify the tm5600/6000 buffer header type and properly handles */ -static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len, - struct urb *urb, struct tm6000_buffer **buf) +static int copy_multiplexed(u8 *ptr, unsigned long len, + struct urb *urb) { struct tm6000_dmaqueue *dma_q = urb->context; struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq); unsigned int pos=dev->isoc_ctl.pos,cpysize; int rc=1; + struct tm6000_buffer *buf; + char *outp = NULL; + + get_next_buf(dma_q, &buf); + if (buf) + outp = videobuf_to_vmalloc(&buf->vb); + + if (!outp) + return 0; while (len>0) { - cpysize=min(len,(*buf)->vb.size-pos); -//printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos); - memcpy(&out_p[pos], ptr, cpysize); + cpysize=min(len,buf->vb.size-pos); + //printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos); + memcpy(&outp[pos], ptr, cpysize); pos+=cpysize; ptr+=cpysize; len-=cpysize; - if (pos >= (*buf)->vb.size) { + if (pos >= buf->vb.size) { pos=0; /* Announces that a new buffer were filled */ - buffer_filled (dev, dma_q, *buf); + buffer_filled (dev, dma_q, buf); dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n"); - get_next_buf (dma_q, buf); - if (!*buf) + get_next_buf (dma_q, &buf); + if (!buf) break; - out_p = videobuf_to_vmalloc(&((*buf)->vb)); - if (!out_p) + outp = videobuf_to_vmalloc(&(buf->vb)); + if (!outp) return rc; pos = 0; } @@ -493,52 +511,36 @@ static inline int tm6000_isoc_copy(struct urb *urb) struct tm6000_dmaqueue *dma_q = urb->context; struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq); struct tm6000_buffer *buf; - int i, len=0, rc=1; - int size; - char *outp = NULL, *p; - unsigned long copied; + int i, len=0, rc=1, status; + char *p; - get_next_buf(dma_q, &buf); - if (buf) - outp = videobuf_to_vmalloc(&buf->vb); - - if (!outp) - return 0; - - size = buf->vb.size; - - copied=0; - - if (urb->status<0) { - print_err_status (dev,-1,urb->status); + if (urb->status < 0) { + print_err_status (dev, -1, urb->status); return 0; } for (i = 0; i < urb->number_of_packets; i++) { - int status = urb->iso_frame_desc[i].status; + status = urb->iso_frame_desc[i].status; if (status<0) { print_err_status (dev,i,status); continue; } - len=urb->iso_frame_desc[i].actual_length; + len = urb->iso_frame_desc[i].actual_length; -// if (len>=TM6000_URB_MSG_LEN) { - p=urb->transfer_buffer + urb->iso_frame_desc[i].offset; + if (len > 0) { + p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; if (!urb->iso_frame_desc[i].status) { - if ((buf->fmt->fourcc)==V4L2_PIX_FMT_TM6000) { - rc=copy_multiplexed(p, outp, len, urb, &buf); + if ((dev->fourcc)==V4L2_PIX_FMT_TM6000) { + rc=copy_multiplexed(p, len, urb); if (rc<=0) return rc; } else { - copy_streams(p, outp, len, urb, &buf); + copy_streams(p, len, urb); } } - copied += len; - if (copied >= size || !buf) - break; -// } + } } return rc; } -- GitLab From 5a4b55e2c256d78fd86679ee00777c393c87c94a Mon Sep 17 00:00:00 2001 From: Stefan Ringel <stefan.ringel@arcor.de> Date: Wed, 19 May 2010 13:58:27 -0300 Subject: [PATCH 407/842] V4L/DVB: tm6000: bugfix stabilizing urb data Signed-off-by: Stefan Ringel <stefan.ringel@arcor.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/tm6000-video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index 8acfebdb5cda..56fa371e08c8 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -48,7 +48,7 @@ #define TM6000_MIN_BUF 4 #define TM6000_DEF_BUF 8 -#define TM6000_MAX_ISO_PACKETS 40 /* Max number of ISO packets */ +#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */ /* Declare static vars that will be used as parameters */ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ @@ -620,7 +620,7 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev) static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize) { struct tm6000_dmaqueue *dma_q = &dev->vidq; - int i, j, sb_size, pipe, size, max_packets, num_bufs = 5; + int i, j, sb_size, pipe, size, max_packets, num_bufs = 8; struct urb *urb; /* De-allocates all pending stuff */ -- GitLab From f36cc0342df21fc6820b53cdfba3e98ee5943f46 Mon Sep 17 00:00:00 2001 From: Stefan Ringel <stefan.ringel@arcor.de> Date: Sun, 23 May 2010 15:29:25 -0300 Subject: [PATCH 408/842] V4L/DVB: tm6000: Add control to the power led Turn power led off, if device is disconnected Signed-off-by: Stefan Ringel <stefan.ringel@arcor.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/tm6000-cards.c | 19 +++++++++++++++++++ drivers/staging/tm6000/tm6000-core.c | 13 +++++++++++++ 2 files changed, 32 insertions(+) diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 22fbd75a551d..cedd9044022f 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -912,6 +912,25 @@ static void tm6000_usb_disconnect(struct usb_interface *interface) } #endif + if (dev->gpio.power_led) { + switch (dev->model) { + case TM6010_BOARD_HAUPPAUGE_900H: + case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + case TM6010_BOARD_TWINHAN_TU501: + /* Power led off */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.power_led, 0x01); + msleep(15); + break; + case TM6010_BOARD_BEHOLD_WANDER: + case TM6010_BOARD_BEHOLD_VOYAGER: + /* Power led off */ + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.power_led, 0x00); + msleep(15); + break; + } + } tm6000_v4l2_unregister(dev); tm6000_i2c_unregister(dev); diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 65feb8cb421c..27f3f551b545 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -339,6 +339,12 @@ int tm6000_init_analog_mode (struct tm6000_core *dev) tm6000_set_standard (dev, &dev->norm); tm6000_set_audio_bitrate (dev,48000); + /* switch dvb led off */ + if (dev->gpio.dvb_led) { + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.dvb_led, 0x01); + } + return 0; } @@ -391,6 +397,13 @@ int tm6000_init_digital_mode (struct tm6000_core *dev) tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); msleep(100); } + + /* switch dvb led on */ + if (dev->gpio.dvb_led) { + tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, + dev->gpio.dvb_led, 0x00); + } + return 0; } -- GitLab From 71d67f739e0b02995c2eb650448f031b76720307 Mon Sep 17 00:00:00 2001 From: Stefan Ringel <stefan.ringel@arcor.de> Date: Sun, 23 May 2010 15:29:24 -0300 Subject: [PATCH 409/842] V4L/DVB: tm6000: Properly select the tuners Signed-off-by: Stefan Ringel <stefan.ringel@arcor.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig index 5fe759cc2ee9..3657e33e8817 100644 --- a/drivers/staging/tm6000/Kconfig +++ b/drivers/staging/tm6000/Kconfig @@ -2,7 +2,8 @@ config VIDEO_TM6000 tristate "TV Master TM5600/6000/6010 driver" depends on VIDEO_DEV && I2C && INPUT && USB && EXPERIMENTAL select VIDEO_TUNER - select TUNER_XC2028 + select MEDIA_TUNER_XC2028 + select MEDIA_TUNER_XC5000 select VIDEOBUF_VMALLOC help Support for TM5600/TM6000/TM6010 USB Device -- GitLab From dcf5d3aa081617a4a8aa56b7e24988d600148f50 Mon Sep 17 00:00:00 2001 From: Stefan Ringel <stefan.ringel@arcor.de> Date: Sun, 23 May 2010 15:29:26 -0300 Subject: [PATCH 410/842] V4L/DVB: tm6000: set variable dev_mode in function tm6000_start_stream set variable dev_mode in function tm6000_start_stream and check mode Signed-off-by: Stefan Ringel <stefan.ringel@arcor.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/tm6000-dvb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c index eafc89c22b6b..e6a802e9c48a 100644 --- a/drivers/staging/tm6000/tm6000-dvb.c +++ b/drivers/staging/tm6000/tm6000-dvb.c @@ -100,7 +100,10 @@ int tm6000_start_stream(struct tm6000_core *dev) printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__); - tm6000_init_digital_mode(dev); + if (dev->mode != TM6000_MODE_DIGITAL) { + tm6000_init_digital_mode(dev); + dev->mode = TM6000_MODE_DIGITAL; + } dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); if(dvb->bulk_urb == NULL) { -- GitLab From 7e2d9820c37525da2469147eec897488ec141bcf Mon Sep 17 00:00:00 2001 From: Stefan Ringel <stefan.ringel@arcor.de> Date: Sun, 23 May 2010 15:31:44 -0300 Subject: [PATCH 411/842] V4L/DVB: tm6000: add DVB support for tuner xc5000 [mchehab@redhat.com: Fix compilation breakage due to duplicate cfg config delaration without {}] Signed-off-by: Stefan Ringel <stefan.ringel@arcor.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/staging/tm6000/tm6000-dvb.c | 69 ++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c index e6a802e9c48a..261e66acbe46 100644 --- a/drivers/staging/tm6000/tm6000-dvb.c +++ b/drivers/staging/tm6000/tm6000-dvb.c @@ -28,6 +28,7 @@ #include <media/tuner.h> #include "tuner-xc2028.h" +#include "xc5000.h" static void inline print_err_status (struct tm6000_core *dev, int packet, int status) @@ -257,27 +258,55 @@ int tm6000_dvb_register(struct tm6000_core *dev) dvb->adapter.priv = dev; if (dvb->frontend) { - struct xc2028_config cfg = { - .i2c_adap = &dev->i2c_adap, - .i2c_addr = dev->tuner_addr, - }; - - dvb->frontend->callback = tm6000_tuner_callback; - ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (ret < 0) { - printk(KERN_ERR - "tm6000: couldn't register frontend\n"); - goto adapter_err; + switch (dev->tuner_type) { + case TUNER_XC2028: { + struct xc2028_config cfg = { + .i2c_adap = &dev->i2c_adap, + .i2c_addr = dev->tuner_addr, + }; + + dvb->frontend->callback = tm6000_tuner_callback; + ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); + if (ret < 0) { + printk(KERN_ERR + "tm6000: couldn't register frontend\n"); + goto adapter_err; + } + + if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) { + printk(KERN_ERR "tm6000: couldn't register " + "frontend (xc3028)\n"); + ret = -EINVAL; + goto frontend_err; + } + printk(KERN_INFO "tm6000: XC2028/3028 asked to be " + "attached to frontend!\n"); + break; + } + case TUNER_XC5000: { + struct xc5000_config cfg = { + .i2c_address = dev->tuner_addr, + }; + + dvb->frontend->callback = tm6000_xc5000_callback; + ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); + if (ret < 0) { + printk(KERN_ERR + "tm6000: couldn't register frontend\n"); + goto adapter_err; + } + + if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) { + printk(KERN_ERR "tm6000: couldn't register " + "frontend (xc5000)\n"); + ret = -EINVAL; + goto frontend_err; + } + printk(KERN_INFO "tm6000: XC5000 asked to be " + "attached to frontend!\n"); + break; + } } - - if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) { - printk(KERN_ERR "tm6000: couldn't register " - "frontend (xc3028)\n"); - ret = -EINVAL; - goto frontend_err; - } - printk(KERN_INFO "tm6000: XC2028/3028 asked to be " - "attached to frontend!\n"); } else { printk(KERN_ERR "tm6000: no frontend found\n"); } -- GitLab From 63fc31e8d0757574edb03ed73986be56e70a75c1 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski <herton@mandriva.com.br> Date: Mon, 10 May 2010 15:43:31 -0300 Subject: [PATCH 412/842] V4L/DVB: saa7134: add RM-K6 remote control support for Avermedia M135A This change adds support for one more remote control type for Avermedia M135A (model RM-K6), shipped with Positivo machines. Signed-off-by: Herton Ronaldo Krzesinski <herton@mandriva.com.br> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/IR/keymaps/Makefile | 2 +- .../IR/keymaps/rc-avermedia-m135a-rm-jx.c | 90 ----------- drivers/media/IR/keymaps/rc-avermedia-m135a.c | 147 ++++++++++++++++++ drivers/media/video/saa7134/saa7134-input.c | 2 +- include/media/rc-map.h | 2 +- 5 files changed, 150 insertions(+), 93 deletions(-) delete mode 100644 drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c create mode 100644 drivers/media/IR/keymaps/rc-avermedia-m135a.c diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile index 585f75c3f376..aea649fbcf5a 100644 --- a/drivers/media/IR/keymaps/Makefile +++ b/drivers/media/IR/keymaps/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-avermedia.o \ rc-avermedia-cardbus.o \ rc-avermedia-dvbt.o \ - rc-avermedia-m135a-rm-jx.o \ + rc-avermedia-m135a.o \ rc-avermedia-m733a-rm-k6.o \ rc-avertv-303.o \ rc-behold.o \ diff --git a/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c b/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c deleted file mode 100644 index 101e7ea85941..000000000000 --- a/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c +++ /dev/null @@ -1,90 +0,0 @@ -/* avermedia-m135a-rm-jx.h - Keytable for avermedia_m135a_rm_jx Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <media/rc-map.h> - -/* - * Avermedia M135A with IR model RM-JX - * The same codes exist on both Positivo (BR) and original IR - * Mauro Carvalho Chehab <mchehab@infradead.org> - */ - -static struct ir_scancode avermedia_m135a_rm_jx[] = { - { 0x0200, KEY_POWER2 }, - { 0x022e, KEY_DOT }, /* '.' */ - { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */ - - { 0x0205, KEY_1 }, - { 0x0206, KEY_2 }, - { 0x0207, KEY_3 }, - { 0x0209, KEY_4 }, - { 0x020a, KEY_5 }, - { 0x020b, KEY_6 }, - { 0x020d, KEY_7 }, - { 0x020e, KEY_8 }, - { 0x020f, KEY_9 }, - { 0x0211, KEY_0 }, - - { 0x0213, KEY_RIGHT }, /* -> or L */ - { 0x0212, KEY_LEFT }, /* <- or R */ - - { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */ - { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */ - - { 0x0303, KEY_CHANNELUP }, - { 0x0302, KEY_CHANNELDOWN }, - { 0x021f, KEY_VOLUMEUP }, - { 0x021e, KEY_VOLUMEDOWN }, - { 0x020c, KEY_ENTER }, /* Full Screen */ - - { 0x0214, KEY_MUTE }, - { 0x0208, KEY_AUDIO }, - - { 0x0203, KEY_TEXT }, /* Teletext */ - { 0x0204, KEY_EPG }, - { 0x022b, KEY_TV2 }, /* TV2 or PIP */ - - { 0x021d, KEY_RED }, - { 0x021c, KEY_YELLOW }, - { 0x0301, KEY_GREEN }, - { 0x0300, KEY_BLUE }, - - { 0x021a, KEY_PLAYPAUSE }, - { 0x0219, KEY_RECORD }, - { 0x0218, KEY_PLAY }, - { 0x021b, KEY_STOP }, -}; - -static struct rc_keymap avermedia_m135a_rm_jx_map = { - .map = { - .scan = avermedia_m135a_rm_jx, - .size = ARRAY_SIZE(avermedia_m135a_rm_jx), - .ir_type = IR_TYPE_NEC, - .name = RC_MAP_AVERMEDIA_M135A_RM_JX, - } -}; - -static int __init init_rc_map_avermedia_m135a_rm_jx(void) -{ - return ir_register_map(&avermedia_m135a_rm_jx_map); -} - -static void __exit exit_rc_map_avermedia_m135a_rm_jx(void) -{ - ir_unregister_map(&avermedia_m135a_rm_jx_map); -} - -module_init(init_rc_map_avermedia_m135a_rm_jx) -module_exit(exit_rc_map_avermedia_m135a_rm_jx) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); diff --git a/drivers/media/IR/keymaps/rc-avermedia-m135a.c b/drivers/media/IR/keymaps/rc-avermedia-m135a.c new file mode 100644 index 000000000000..e4471fb2ad1e --- /dev/null +++ b/drivers/media/IR/keymaps/rc-avermedia-m135a.c @@ -0,0 +1,147 @@ +/* avermedia-m135a.c - Keytable for Avermedia M135A Remote Controllers + * + * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com> + * Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <media/rc-map.h> + +/* + * Avermedia M135A with RM-JX and RM-K6 remote controls + * + * On Avermedia M135A with IR model RM-JX, the same codes exist on both + * Positivo (BR) and original IR, initial version and remote control codes + * added by Mauro Carvalho Chehab <mchehab@infradead.org> + * + * Positivo also ships Avermedia M135A with model RM-K6, extra control + * codes added by Herton Ronaldo Krzesinski <herton@mandriva.com.br> + */ + +static struct ir_scancode avermedia_m135a[] = { + /* RM-JX */ + { 0x0200, KEY_POWER2 }, + { 0x022e, KEY_DOT }, /* '.' */ + { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */ + + { 0x0205, KEY_1 }, + { 0x0206, KEY_2 }, + { 0x0207, KEY_3 }, + { 0x0209, KEY_4 }, + { 0x020a, KEY_5 }, + { 0x020b, KEY_6 }, + { 0x020d, KEY_7 }, + { 0x020e, KEY_8 }, + { 0x020f, KEY_9 }, + { 0x0211, KEY_0 }, + + { 0x0213, KEY_RIGHT }, /* -> or L */ + { 0x0212, KEY_LEFT }, /* <- or R */ + + { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */ + { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */ + + { 0x0303, KEY_CHANNELUP }, + { 0x0302, KEY_CHANNELDOWN }, + { 0x021f, KEY_VOLUMEUP }, + { 0x021e, KEY_VOLUMEDOWN }, + { 0x020c, KEY_ENTER }, /* Full Screen */ + + { 0x0214, KEY_MUTE }, + { 0x0208, KEY_AUDIO }, + + { 0x0203, KEY_TEXT }, /* Teletext */ + { 0x0204, KEY_EPG }, + { 0x022b, KEY_TV2 }, /* TV2 or PIP */ + + { 0x021d, KEY_RED }, + { 0x021c, KEY_YELLOW }, + { 0x0301, KEY_GREEN }, + { 0x0300, KEY_BLUE }, + + { 0x021a, KEY_PLAYPAUSE }, + { 0x0219, KEY_RECORD }, + { 0x0218, KEY_PLAY }, + { 0x021b, KEY_STOP }, + + /* RM-K6 */ + { 0x0401, KEY_POWER2 }, + { 0x0406, KEY_MUTE }, + { 0x0408, KEY_MODE }, /* TV/FM */ + + { 0x0409, KEY_1 }, + { 0x040a, KEY_2 }, + { 0x040b, KEY_3 }, + { 0x040c, KEY_4 }, + { 0x040d, KEY_5 }, + { 0x040e, KEY_6 }, + { 0x040f, KEY_7 }, + { 0x0410, KEY_8 }, + { 0x0411, KEY_9 }, + { 0x044c, KEY_DOT }, /* '.' */ + { 0x0412, KEY_0 }, + { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ + + { 0x0413, KEY_AUDIO }, + { 0x0440, KEY_SCREEN }, /* Full Screen toggle */ + { 0x0441, KEY_HOME }, + { 0x0442, KEY_BACK }, + { 0x0447, KEY_UP }, + { 0x0448, KEY_DOWN }, + { 0x0449, KEY_LEFT }, + { 0x044a, KEY_RIGHT }, + { 0x044b, KEY_OK }, + { 0x0404, KEY_VOLUMEUP }, + { 0x0405, KEY_VOLUMEDOWN }, + { 0x0402, KEY_CHANNELUP }, + { 0x0403, KEY_CHANNELDOWN }, + + { 0x0443, KEY_RED }, + { 0x0444, KEY_GREEN }, + { 0x0445, KEY_YELLOW }, + { 0x0446, KEY_BLUE }, + + { 0x0414, KEY_TEXT }, + { 0x0415, KEY_EPG }, + { 0x041a, KEY_TV2 }, /* PIP */ + { 0x041b, KEY_MHP }, /* Snapshot */ + + { 0x0417, KEY_RECORD }, + { 0x0416, KEY_PLAYPAUSE }, + { 0x0418, KEY_STOP }, + { 0x0419, KEY_PAUSE }, + + { 0x041f, KEY_PREVIOUS }, + { 0x041c, KEY_REWIND }, + { 0x041d, KEY_FORWARD }, + { 0x041e, KEY_NEXT }, +}; + +static struct rc_keymap avermedia_m135a_map = { + .map = { + .scan = avermedia_m135a, + .size = ARRAY_SIZE(avermedia_m135a), + .ir_type = IR_TYPE_NEC, + .name = RC_MAP_AVERMEDIA_M135A, + } +}; + +static int __init init_rc_map_avermedia_m135a(void) +{ + return ir_register_map(&avermedia_m135a_map); +} + +static void __exit exit_rc_map_avermedia_m135a(void) +{ + ir_unregister_map(&avermedia_m135a_map); +} + +module_init(init_rc_map_avermedia_m135a) +module_exit(exit_rc_map_avermedia_m135a) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index f9ed8048894d..b36960dd7319 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -657,7 +657,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); break; case SAA7134_BOARD_AVERMEDIA_M135A: - ir_codes = RC_MAP_AVERMEDIA_M135A_RM_JX; + ir_codes = RC_MAP_AVERMEDIA_M135A; mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */ mask_keyup = 0x0040000; mask_keycode = 0xffff; diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 6f1f9f76674e..c78e99a435b6 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -55,7 +55,7 @@ void rc_map_init(void); #define RC_MAP_AVERMEDIA_A16D "rc-avermedia-a16d" #define RC_MAP_AVERMEDIA_CARDBUS "rc-avermedia-cardbus" #define RC_MAP_AVERMEDIA_DVBT "rc-avermedia-dvbt" -#define RC_MAP_AVERMEDIA_M135A_RM_JX "rc-avermedia-m135a-rm-jx" +#define RC_MAP_AVERMEDIA_M135A "rc-avermedia-m135a" #define RC_MAP_AVERMEDIA_M733A_RM_K6 "rc-avermedia-m733a-rm-k6" #define RC_MAP_AVERMEDIA "rc-avermedia" #define RC_MAP_AVERTV_303 "rc-avertv-303" -- GitLab From a49ba1674b0cf507e62d97fbd91ce345a37b11a8 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava <prarit@redhat.com> Date: Wed, 12 May 2010 19:30:02 -0300 Subject: [PATCH 413/842] V4L/DVB: Add notification to cxusb_dualdig4_rev2_frontend_attach() error handling Add a notification to the dib7000p_i2c_enumeration() failure path in cxusb_dualdig4_rev2_frontend_attach(). Signed-off-by: Prarit Bhargava <prarit@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/dvb-usb/cxusb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 0eb490889162..11e9e85dac86 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -1026,8 +1026,10 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &cxusb_dualdig4_rev2_config) < 0) + &cxusb_dualdig4_rev2_config) < 0) { + printk(KERN_WARNING "Unable to enumerate dib7000p\n"); return -ENODEV; + } adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &cxusb_dualdig4_rev2_config); -- GitLab From 58aac2bff192970a1186c33fbea181efe9464dd2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap <randy.dunlap@oracle.com> Date: Fri, 14 May 2010 14:09:57 -0300 Subject: [PATCH 414/842] V4L/DVB: [-next] IR: fix ir-nec-decoder build, select BITREVERSE Fix ir-nec-decoder build: it uses bitrev library code, so select BITREVERSE in its Kconfig. ir-nec-decoder.c:(.text+0x1a2517): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2526): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2530): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2539): undefined reference to `byte_rev_table' Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/IR/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig index 195c6cf359f6..b45f3bc4a7b1 100644 --- a/drivers/media/IR/Kconfig +++ b/drivers/media/IR/Kconfig @@ -13,6 +13,7 @@ source "drivers/media/IR/keymaps/Kconfig" config IR_NEC_DECODER tristate "Enable IR raw decoder for the NEC protocol" depends on IR_CORE + select BITREVERSE default y ---help--- -- GitLab From 9947e98a76455cec4a64aef536d375fa37cbfc32 Mon Sep 17 00:00:00 2001 From: Ben Hutchings <ben@decadent.org.uk> Date: Sat, 15 May 2010 13:45:21 -0300 Subject: [PATCH 415/842] V4L/DVB: dw2102: Select tda10023 frontend, not tda10021 Update the Kconfig selections to match the code. Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/dvb-usb/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index e5f91f16ffa4..cfcbf4f15b2b 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -264,7 +264,7 @@ config DVB_USB_DW2102 select DVB_STB6000 if !DVB_FE_CUSTOMISE select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_SI21XX if !DVB_FE_CUSTOMISE - select DVB_TDA10021 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE select DVB_MT312 if !DVB_FE_CUSTOMISE select DVB_ZL10039 if !DVB_FE_CUSTOMISE select DVB_DS3000 if !DVB_FE_CUSTOMISE -- GitLab From d46b36e7f927772bb72524dc9f1e384e3cb4a975 Mon Sep 17 00:00:00 2001 From: Ben Hutchings <ben@decadent.org.uk> Date: Sat, 15 May 2010 13:45:37 -0300 Subject: [PATCH 416/842] V4L/DVB: budget: Select correct frontends Update the Kconfig selections to match the code. Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/ttpci/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index d8d4214fd65f..32a7ec65ec42 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -68,13 +68,14 @@ config DVB_BUDGET select DVB_VES1820 if !DVB_FE_CUSTOMISE select DVB_L64781 if !DVB_FE_CUSTOMISE select DVB_TDA8083 if !DVB_FE_CUSTOMISE - select DVB_TDA10021 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE select DVB_S5H1420 if !DVB_FE_CUSTOMISE select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_ISL6423 if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard MPEG2 decoder, and without -- GitLab From e245b0bd8253fc54dfe3b5e453af0c9841098f87 Mon Sep 17 00:00:00 2001 From: Ben Hutchings <ben@decadent.org.uk> Date: Sat, 15 May 2010 13:45:58 -0300 Subject: [PATCH 417/842] V4L/DVB: dib0700: Select dib0090 frontend Update the Kconfig selections to match the code. Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/dvb-usb/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index cfcbf4f15b2b..73a6e9dbbe9c 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -76,6 +76,7 @@ config DVB_USB_DIB0700 select DVB_S5H1411 if !DVB_FE_CUSTOMISE select DVB_LGDT3305 if !DVB_FE_CUSTOMISE select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE -- GitLab From 59fd08afe0f9ae3a3b793fc178a3c3677b1e716c Mon Sep 17 00:00:00 2001 From: Ben Hutchings <ben@decadent.org.uk> Date: Sat, 15 May 2010 13:46:16 -0300 Subject: [PATCH 418/842] V4L/DVB: m920x: Select simple tuner Update the Kconfig selections to match the code. Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/dvb-usb/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 73a6e9dbbe9c..553b48ac1919 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -135,6 +135,7 @@ config DVB_USB_M920X select DVB_TDA1004X if !DVB_FE_CUSTOMISE select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE help Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. Currently, only devices with a product id of -- GitLab From 2ef17c9fc8241e5b08c60ca82345c540bb001876 Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Thu, 13 May 2010 16:59:15 -0300 Subject: [PATCH 419/842] V4L/DVB: drivers/media: Use kzalloc Use kzalloc rather than the combination of kmalloc and memset. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // <smpl> @@ expression x,size,flags; statement S; @@ -x = kmalloc(size,flags); +x = kzalloc(size,flags); if (x == NULL) S -memset(x, 0, size); // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/frontends/ds3000.c | 5 +---- drivers/media/video/omap/omap_vout.c | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 78001e8bcdb7..fc61d9230db8 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -969,15 +969,12 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, dprintk("%s\n", __func__); /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct ds3000_state), GFP_KERNEL); + state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL); if (state == NULL) { printk(KERN_ERR "Unable to kmalloc\n"); goto error2; } - /* setup the state */ - memset(state, 0, sizeof(struct ds3000_state)); - state->config = config; state->i2c = i2c; state->prevUCBS2 = 0; diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 4c0ab499228b..e7db0554949a 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -2371,12 +2371,11 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) for (k = 0; k < pdev->num_resources; k++) { - vout = kmalloc(sizeof(struct omap_vout_device), GFP_KERNEL); + vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL); if (!vout) { dev_err(&pdev->dev, ": could not allocate memory\n"); return -ENOMEM; } - memset(vout, 0, sizeof(struct omap_vout_device)); vout->vid = k; vid_dev->vouts[k] = vout; -- GitLab From f137f9d0009067289a2fa6c4da9b82084cdd257e Mon Sep 17 00:00:00 2001 From: Hermann Gausterer <linux-media-maillinglist@mrq1.org> Date: Tue, 18 May 2010 04:26:17 -0300 Subject: [PATCH 420/842] V4L/DVB: Technotrend S2-3200 ships with a TT 1500 remote The Technotrend Budget S2-3200 ships with the Technotrend 1500 bundled remote which is already supported. Just add the right Subsystem Device ID. Signed-off-by: Hermann Gausterer <git-kernel-2010@mrq1.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/ttpci/budget-ci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 461714396331..13ac9e3ab121 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -215,6 +215,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) break; case 0x1010: case 0x1017: + case 0x1019: case 0x101a: /* for the Technotrend 1500 bundled remote */ ir_codes = RC_MAP_TT_1500; -- GitLab From 806b07c29b711aaf90c81d2a19711607769f8246 Mon Sep 17 00:00:00 2001 From: Jean Delvare <khali@linux-fr.org> Date: Wed, 26 May 2010 10:05:11 -0300 Subject: [PATCH 421/842] V4L/DVB: FusionHDTV: Use quick reads for I2C IR device probing IR support on FusionHDTV cards is broken since kernel 2.6.31. One side effect of the switch to the standard binding model for IR I2C devices was to let i2c-core do the probing instead of the ir-kbd-i2c driver. There is a slight difference between the two probe methods: i2c-core uses 0-byte writes, while the ir-kbd-i2c was using 0-byte reads. As some IR I2C devices only support reads, the new probe method fails to detect them. For now, revert to letting the driver do the probe, using 0-byte reads. In the future, i2c-core will be extended to let callers of i2c_new_probed_device() provide a custom probing function. Signed-off-by: Jean Delvare <khali@linux-fr.org> Tested-by: "Timothy D. Lenz" <tlenz@vorgon.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/cx23885/cx23885-i2c.c | 12 +++++++++++- drivers/media/video/cx88/cx88-i2c.c | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 4172cb387420..d4746e064516 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -365,7 +365,17 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - i2c_new_probed_device(&bus->i2c_adap, &info, addr_list); + /* + * We can't call i2c_new_probed_device() because it uses + * quick writes for probing and the IR receiver device only + * replies to reads. + */ + if (i2c_smbus_xfer(&bus->i2c_adap, addr_list[0], 0, + I2C_SMBUS_READ, 0, I2C_SMBUS_QUICK, + NULL) >= 0) { + info.addr = addr_list[0]; + i2c_new_device(&bus->i2c_adap, &info); + } } return bus->i2c_rc; diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index ee1ca39db06a..fb39f1184558 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -188,10 +188,24 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) 0x18, 0x6b, 0x71, I2C_CLIENT_END }; + const unsigned short *addrp; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - i2c_new_probed_device(&core->i2c_adap, &info, addr_list); + /* + * We can't call i2c_new_probed_device() because it uses + * quick writes for probing and at least some R receiver + * devices only reply to reads. + */ + for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) { + if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0, + I2C_SMBUS_READ, 0, + I2C_SMBUS_QUICK, NULL) >= 0) { + info.addr = *addrp; + i2c_new_device(&core->i2c_adap, &info); + break; + } + } } return core->i2c_rc; } -- GitLab From 1db2c22b2216718d4d9adb4a9450bb3dc70e56d2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap <randy.dunlap@oracle.com> Date: Thu, 20 May 2010 18:08:23 -0300 Subject: [PATCH 422/842] V4L/DVB: ak881x needs slab.h Add slab.h to fix ak881x build: drivers/media/video/ak881x.c:265:error: implicit declaration of function 'kzalloc' drivers/media/video/ak881x.c:265:warning: assignment makes pointer from integer without a cast drivers/media/video/ak881x.c:283:error: implicit declaration of function 'kfree' Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/ak881x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c index 3006a2c80f47..1573392f74bd 100644 --- a/drivers/media/video/ak881x.c +++ b/drivers/media/video/ak881x.c @@ -11,6 +11,7 @@ #include <linux/i2c.h> #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/slab.h> #include <linux/videodev2.h> #include <media/ak881x.h> -- GitLab From 7853d408b792f9015072f7c4649bd3a5d4f6ed02 Mon Sep 17 00:00:00 2001 From: Huang Weiyi <weiyi.huang@gmail.com> Date: Sat, 22 May 2010 14:12:06 -0300 Subject: [PATCH 423/842] V4L/DVB: ngene: remove unused #include <linux/version.h> Remove unused #include <linux/version.h>('s) in drivers/media/dvb/ngene/ngene-dvb.c drivers/media/dvb/ngene/ngene-i2c.c Signed-off-by: Huang Weiyi <weiyi.huang@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/ngene/ngene-dvb.c | 1 - drivers/media/dvb/ngene/ngene-i2c.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c index 61a932c1cfff..48f980b21d66 100644 --- a/drivers/media/dvb/ngene/ngene-dvb.c +++ b/drivers/media/dvb/ngene/ngene-dvb.c @@ -37,7 +37,6 @@ #include <linux/pci.h> #include <linux/smp_lock.h> #include <linux/timer.h> -#include <linux/version.h> #include <linux/byteorder/generic.h> #include <linux/firmware.h> #include <linux/vmalloc.h> diff --git a/drivers/media/dvb/ngene/ngene-i2c.c b/drivers/media/dvb/ngene/ngene-i2c.c index 2ef54ca6badd..477fe0aade86 100644 --- a/drivers/media/dvb/ngene/ngene-i2c.c +++ b/drivers/media/dvb/ngene/ngene-i2c.c @@ -39,7 +39,6 @@ #include <linux/pci_ids.h> #include <linux/smp_lock.h> #include <linux/timer.h> -#include <linux/version.h> #include <linux/byteorder/generic.h> #include <linux/firmware.h> #include <linux/vmalloc.h> -- GitLab From 517521e4651ac106fc2a4f7638c284f60de92bb8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Sat, 22 May 2010 16:53:27 -0300 Subject: [PATCH 424/842] V4L/DVB: em28xx: remove unneeded null checks The "dev" variable is used as a list cursor in a list_for_each_entry() loop and can never be null here so I removed the check. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/em28xx/em28xx-core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 331e1cac4272..44c63cbd6dda 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -1186,8 +1186,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) mutex_lock(&em28xx_devlist_mutex); list_add_tail(&ops->next, &em28xx_extension_devlist); list_for_each_entry(dev, &em28xx_devlist, devlist) { - if (dev) - ops->init(dev); + ops->init(dev); } printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); mutex_unlock(&em28xx_devlist_mutex); @@ -1201,10 +1200,8 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(dev, &em28xx_devlist, devlist) { - if (dev) - ops->fini(dev); + ops->fini(dev); } - printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); list_del(&ops->next); mutex_unlock(&em28xx_devlist_mutex); -- GitLab From f789bf4013e5e003e5d75ec0b8fa280aa66f401f Mon Sep 17 00:00:00 2001 From: Jarod Wilson <jarod@redhat.com> Date: Mon, 24 May 2010 12:00:31 -0300 Subject: [PATCH 425/842] V4L/DVB: IR/imon: clean up usage of bools There was a mix of 0/1 and false/true. Pick one convention and stick with it (I picked false/true). Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/IR/imon.c | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c index 5e2045670004..2bae9ba2e40c 100644 --- a/drivers/media/IR/imon.c +++ b/drivers/media/IR/imon.c @@ -385,7 +385,7 @@ static int display_open(struct inode *inode, struct file *file) err("%s: display port is already open", __func__); retval = -EBUSY; } else { - ictx->display_isopen = 1; + ictx->display_isopen = true; file->private_data = ictx; dev_dbg(ictx->dev, "display port opened\n"); } @@ -422,7 +422,7 @@ static int display_close(struct inode *inode, struct file *file) err("%s: display is not open", __func__); retval = -EIO; } else { - ictx->display_isopen = 0; + ictx->display_isopen = false; dev_dbg(ictx->dev, "display port closed\n"); if (!ictx->dev_present_intf0) { /* @@ -491,12 +491,12 @@ static int send_packet(struct imon_context *ictx) } init_completion(&ictx->tx.finished); - ictx->tx.busy = 1; + ictx->tx.busy = true; smp_rmb(); /* ensure later readers know we're busy */ retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL); if (retval) { - ictx->tx.busy = 0; + ictx->tx.busy = false; smp_rmb(); /* ensure later readers know we're not busy */ err("%s: error submitting urb(%d)", __func__, retval); } else { @@ -682,7 +682,7 @@ static ssize_t store_associate_remote(struct device *d, return -ENODEV; mutex_lock(&ictx->lock); - ictx->rf_isassociating = 1; + ictx->rf_isassociating = true; send_associate_24g(ictx); mutex_unlock(&ictx->lock); @@ -950,7 +950,7 @@ static void usb_tx_callback(struct urb *urb) ictx->tx.status = urb->status; /* notify waiters that write has finished */ - ictx->tx.busy = 0; + ictx->tx.busy = false; smp_rmb(); /* ensure later readers know we're not busy */ complete(&ictx->tx.finished); } @@ -1215,7 +1215,7 @@ static bool imon_mouse_event(struct imon_context *ictx, { char rel_x = 0x00, rel_y = 0x00; u8 right_shift = 1; - bool mouse_input = 1; + bool mouse_input = true; int dir = 0; /* newer iMON device PAD or mouse button */ @@ -1246,7 +1246,7 @@ static bool imon_mouse_event(struct imon_context *ictx, } else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) { dir = -1; } else - mouse_input = 0; + mouse_input = false; if (mouse_input) { dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); @@ -1450,7 +1450,7 @@ static void imon_incoming_packet(struct imon_context *ictx, unsigned char *buf = urb->transfer_buffer; struct device *dev = ictx->dev; u32 kc; - bool norelease = 0; + bool norelease = false; int i; u64 temp_key; u64 panel_key = 0; @@ -1517,7 +1517,7 @@ static void imon_incoming_packet(struct imon_context *ictx, !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) { len = 8; imon_pad_to_keys(ictx, buf); - norelease = 1; + norelease = true; } if (debug) { @@ -1580,7 +1580,7 @@ not_input_data: (buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */ dev_warn(dev, "%s: remote associated refid=%02X\n", __func__, buf[1]); - ictx->rf_isassociating = 0; + ictx->rf_isassociating = false; } } @@ -1790,9 +1790,9 @@ static bool imon_find_endpoints(struct imon_context *ictx, int ifnum = iface_desc->desc.bInterfaceNumber; int num_endpts = iface_desc->desc.bNumEndpoints; int i, ep_dir, ep_type; - bool ir_ep_found = 0; - bool display_ep_found = 0; - bool tx_control = 0; + bool ir_ep_found = false; + bool display_ep_found = false; + bool tx_control = false; /* * Scan the endpoint list and set: @@ -1808,13 +1808,13 @@ static bool imon_find_endpoints(struct imon_context *ictx, ep_type == USB_ENDPOINT_XFER_INT) { rx_endpoint = ep; - ir_ep_found = 1; + ir_ep_found = true; dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__); } else if (!display_ep_found && ep_dir == USB_DIR_OUT && ep_type == USB_ENDPOINT_XFER_INT) { tx_endpoint = ep; - display_ep_found = 1; + display_ep_found = true; dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__); } } @@ -1835,8 +1835,8 @@ static bool imon_find_endpoints(struct imon_context *ictx, * newer iMON devices that use control urb instead of interrupt */ if (!display_ep_found) { - tx_control = 1; - display_ep_found = 1; + tx_control = true; + display_ep_found = true; dev_dbg(ictx->dev, "%s: device uses control endpoint, not " "interface OUT endpoint\n", __func__); } @@ -1847,7 +1847,7 @@ static bool imon_find_endpoints(struct imon_context *ictx, * and without... :\ */ if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) { - display_ep_found = 0; + display_ep_found = false; dev_dbg(ictx->dev, "%s: device has no display\n", __func__); } @@ -1856,7 +1856,7 @@ static bool imon_find_endpoints(struct imon_context *ictx, * that refers to e.g. /dev/lcd0 (a character device LCD or VFD). */ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { - display_ep_found = 0; + display_ep_found = false; dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__); } @@ -1905,7 +1905,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) ictx->dev = dev; ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf)); - ictx->dev_present_intf0 = 1; + ictx->dev_present_intf0 = true; ictx->rx_urb_intf0 = rx_urb; ictx->tx_urb = tx_urb; @@ -1979,7 +1979,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, } ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); - ictx->dev_present_intf1 = 1; + ictx->dev_present_intf1 = true; ictx->rx_urb_intf1 = rx_urb; ret = -ENODEV; @@ -2297,7 +2297,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface) } if (ifnum == 0) { - ictx->dev_present_intf0 = 0; + ictx->dev_present_intf0 = false; usb_kill_urb(ictx->rx_urb_intf0); input_unregister_device(ictx->idev); if (ictx->display_supported) { @@ -2307,7 +2307,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface) usb_deregister_dev(interface, &imon_vfd_class); } } else { - ictx->dev_present_intf1 = 0; + ictx->dev_present_intf1 = false; usb_kill_urb(ictx->rx_urb_intf1); if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) input_unregister_device(ictx->touch); -- GitLab From bbe4690f6caef2b36c95dd50e59bc3f4e2eaa6ad Mon Sep 17 00:00:00 2001 From: Jarod Wilson <jarod@redhat.com> Date: Mon, 24 May 2010 12:02:05 -0300 Subject: [PATCH 426/842] V4L/DVB: IR/imon: add auto-config for 0xffdc rf device Add auto-config support for iMON 2.4G LT RF device, based on debug output from Giulio Amodeo in Red Hat bugzilla #572288. Also flips the switch on only setting up the rf associate sysfs attr only if we think we're looking at an RF device, vs. previously, setting up the attr for all 0xffdc devices, so its possible (but a bit unlikely) there's another iMON RF device we'll have to fix up. Nb: should be applied after "IR/imon: clean up usage of bools", or there will be a slight contextual mismatch. Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/IR/imon.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c index 2bae9ba2e40c..4bbd45f4284c 100644 --- a/drivers/media/IR/imon.c +++ b/drivers/media/IR/imon.c @@ -94,6 +94,7 @@ struct imon_context { bool display_supported; /* not all controllers do */ bool display_isopen; /* display port has been opened */ + bool rf_device; /* true if iMON 2.4G LT/DT RF device */ bool rf_isassociating; /* RF remote associating */ bool dev_present_intf0; /* USB device presence, interface 0 */ bool dev_present_intf1; /* USB device presence, interface 1 */ @@ -1465,7 +1466,7 @@ static void imon_incoming_packet(struct imon_context *ictx, idev = ictx->idev; /* filter out junk data on the older 0xffdc imon devices */ - if ((buf[0] == 0xff) && (buf[7] == 0xff)) + if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff)) return; /* Figure out what key was pressed */ @@ -1908,6 +1909,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) ictx->dev_present_intf0 = true; ictx->rx_urb_intf0 = rx_urb; ictx->tx_urb = tx_urb; + ictx->rf_device = false; ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); @@ -2047,6 +2049,12 @@ static void imon_get_ffdc_type(struct imon_context *ictx) dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR"); ictx->display_supported = false; break; + /* iMON 2.4G LT (usb stick), no display, iMON RF */ + case 0x4e: + dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF"); + ictx->display_supported = false; + ictx->rf_device = true; + break; /* iMON VFD, no IR (does have vol knob tho) */ case 0x35: dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR"); @@ -2197,15 +2205,6 @@ static int __devinit imon_probe(struct usb_interface *interface, goto fail; } - if (product == 0xffdc) { - /* RF products *also* use 0xffdc... sigh... */ - sysfs_err = sysfs_create_group(&interface->dev.kobj, - &imon_rf_attribute_group); - if (sysfs_err) - err("%s: Could not create RF sysfs entries(%d)", - __func__, sysfs_err); - } - } else { /* this is the secondary interface on the device */ ictx = imon_init_intf1(interface, first_if_ctx); @@ -2233,6 +2232,14 @@ static int __devinit imon_probe(struct usb_interface *interface, imon_set_display_type(ictx, interface); + if (product == 0xffdc && ictx->rf_device) { + sysfs_err = sysfs_create_group(&interface->dev.kobj, + &imon_rf_attribute_group); + if (sysfs_err) + err("%s: Could not create RF sysfs entries(%d)", + __func__, sysfs_err); + } + if (ictx->display_supported) imon_init_display(ictx, interface); } -- GitLab From f0e5481f2f5304ffebd43d97bd5118443fac8d23 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Tue, 25 May 2010 06:21:50 -0300 Subject: [PATCH 427/842] V4L/DVB: video/saa7134: remove duplicate break The original code had two break statements in a row. Signed-off-by: Dan Carpenter <error27@gmail.com> Acked-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/saa7134/saa7134-input.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index b36960dd7319..c1240d22028a 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -822,7 +822,6 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keyup = 0x020000; polling = 50; /* ms */ break; - break; } if (NULL == ir_codes) { printk("%s: Oops: IR config error [card=%d]\n", -- GitLab From 129c34d8fce443d1c43d32637abbab8433504497 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Wed, 26 May 2010 11:58:10 -0300 Subject: [PATCH 428/842] V4L/DVB: video/saa7134: change dprintk() to i2cdprintk() The problem is that dprintk() dereferences "dev" which is null here. The i2cdprintk() uses "ir" so that's OK. Also Jean Delvare pointed out a typo in the comment so we may as well fix that. Signed-off-by: Dan Carpenter <error27@gmail.com> Acked-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/saa7134/saa7134-input.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index c1240d22028a..0b336ca6d55b 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -141,8 +141,8 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - dprintk("get_key_flydvb_trio: " - "gir->c->adapter->algo_data is NULL!\n"); + i2cdprintk("get_key_flydvb_trio: " + "ir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -195,8 +195,8 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - dprintk("get_key_msi_tvanywhere_plus: " - "gir->c->adapter->algo_data is NULL!\n"); + i2cdprintk("get_key_msi_tvanywhere_plus: " + "ir->c->adapter->algo_data is NULL!\n"); return -EIO; } -- GitLab From 033608c1f33bcacba8d3a960240a7b2900b1d5ff Mon Sep 17 00:00:00 2001 From: Randy Dunlap <randy.dunlap@oracle.com> Date: Wed, 26 May 2010 14:08:51 -0300 Subject: [PATCH 429/842] V4L/DVB: media/IR: nec-decoder needs to select BITREV Fix ir-nec-decoder build: it uses bitrev library code, so select BITREVERSE in its Kconfig. ir-nec-decoder.c:(.text+0x1a2517): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2526): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2530): undefined reference to `byte_rev_table' ir-nec-decoder.c:(.text+0x1a2539): undefined reference to `byte_rev_table' Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/IR/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig index b45f3bc4a7b1..d22a8ec523fc 100644 --- a/drivers/media/IR/Kconfig +++ b/drivers/media/IR/Kconfig @@ -23,6 +23,7 @@ config IR_NEC_DECODER config IR_RC5_DECODER tristate "Enable IR raw decoder for the RC-5 protocol" depends on IR_CORE + select BITREVERSE default y ---help--- -- GitLab From 84b14f181a36eea6591779156ef356f8d198bbfd Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" <liplianin@me.by> Date: Wed, 26 May 2010 23:31:21 -0300 Subject: [PATCH 430/842] V4L/DVB: Bug fix: make IR work again for dm1105 It makes IR to work again for dm1105 and, possibly, others. Signed-off-by: Igor M. Liplianin <liplianin@me.by> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/IR/ir-keytable.c | 17 ++++++++++------- drivers/media/IR/ir-sysfs.c | 7 ++++--- drivers/media/dvb/dm1105/dm1105.c | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c index 9374a006f43d..94a8577e72eb 100644 --- a/drivers/media/IR/ir-keytable.c +++ b/drivers/media/IR/ir-keytable.c @@ -490,11 +490,12 @@ int __ir_input_register(struct input_dev *input_dev, if (rc < 0) goto out_table; - if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) { - rc = ir_raw_event_register(input_dev); - if (rc < 0) - goto out_event; - } + if (ir_dev->props) + if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) { + rc = ir_raw_event_register(input_dev); + if (rc < 0) + goto out_event; + } IR_dprintk(1, "Registered input device on %s for %s remote.\n", driver_name, rc_tab->name); @@ -530,8 +531,10 @@ void ir_input_unregister(struct input_dev *input_dev) IR_dprintk(1, "Freed keycode table\n"); del_timer_sync(&ir_dev->timer_keyup); - if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) - ir_raw_event_unregister(input_dev); + if (ir_dev->props) + if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) + ir_raw_event_unregister(input_dev); + rc_tab = &ir_dev->rc_tab; rc_tab->size = 0; kfree(rc_tab->scan); diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c index d7da63e16c92..2098dd1488e0 100644 --- a/drivers/media/IR/ir-sysfs.c +++ b/drivers/media/IR/ir-sysfs.c @@ -221,9 +221,10 @@ int ir_register_class(struct input_dev *input_dev) if (unlikely(devno < 0)) return devno; - if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) - ir_dev->dev.type = &rc_dev_type; - else + if (ir_dev->props) { + if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) + ir_dev->dev.type = &rc_dev_type; + } else ir_dev->dev.type = &ir_raw_dev_type; ir_dev->dev.class = &ir_input_class; diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index b762e561a6d5..bca07c0bcd01 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -594,7 +594,7 @@ static irqreturn_t dm1105_irq(int irq, void *dev_id) int __devinit dm1105_ir_init(struct dm1105_dev *dm1105) { struct input_dev *input_dev; - char *ir_codes = NULL; + char *ir_codes = RC_MAP_DM1105_NEC; int err = -ENOMEM; input_dev = input_allocate_device(); -- GitLab From 5c331fc8c19e181bffab46e9d18e1637cdc47170 Mon Sep 17 00:00:00 2001 From: Ang Way Chuang <wcang79@gmail.com> Date: Thu, 27 May 2010 02:02:09 -0300 Subject: [PATCH 431/842] V4L/DVB: dvb-core: Fix ULE decapsulation bug Fix ULE decapsulation bug when less than 4 bytes of ULE SNDU is packed into the remaining bytes of a MPEG2-TS frame ULE (Unidirectional Lightweight Encapsulation RFC 4326) decapsulation code has a bug that incorrectly treats ULE SNDU packed into the remaining 2 or 3 bytes of a MPEG2-TS frame as having invalid pointer field on the subsequent MPEG2-TS frame. Signed-off-by: Ang Way Chuang <wcang@nav6.org> Acked-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/dvb-core/dvb_net.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index f6dac2bb0ac6..6c3a8a06ccab 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -351,6 +351,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) const u8 *ts, *ts_end, *from_where = NULL; u8 ts_remain = 0, how_much = 0, new_ts = 1; struct ethhdr *ethh = NULL; + bool error = false; #ifdef ULE_DEBUG /* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */ @@ -460,10 +461,16 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { - dev_kfree_skb( priv->ule_skb ); + error = true; + dev_kfree_skb(priv->ule_skb); + } + + if (error || priv->ule_sndu_remain) { dev->stats.rx_errors++; dev->stats.rx_frame_errors++; + error = false; } + reset_ule(priv); priv->need_pusi = 1; continue; @@ -535,6 +542,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) from_where += 2; } + priv->ule_sndu_remain = priv->ule_sndu_len + 2; /* * State of current TS: * ts_remain (remaining bytes in the current TS cell) @@ -544,6 +552,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) */ switch (ts_remain) { case 1: + priv->ule_sndu_remain--; priv->ule_sndu_type = from_where[0] << 8; priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */ ts_remain -= 1; from_where += 1; @@ -557,6 +566,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) default: /* complete ULE header is present in current TS. */ /* Extract ULE type field. */ if (priv->ule_sndu_type_1) { + priv->ule_sndu_type_1 = 0; priv->ule_sndu_type |= from_where[0]; from_where += 1; /* points to payload start. */ ts_remain -= 1; -- GitLab From 4202066c6995200b2755a4501ea90f5d4e163e41 Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Thu, 27 May 2010 09:36:45 -0300 Subject: [PATCH 432/842] V4L/DVB: drivers/media: Eliminate a NULL pointer dereference In each case, the print involves dereferencing a value that is NULL or is near NULL. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @r exists@ expression E,E1; identifier f; statement S1,S2,S3; @@ if ((E == NULL && ...) || ...) { ... when != if (...) S1 else S2 when != E = E1 * E->f ... when any return ...; } else S3 // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/dvb/firewire/firedtv-1394.c | 2 +- drivers/media/video/hdpvr/hdpvr-video.c | 2 +- drivers/media/video/usbvision/usbvision-video.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c index 26333b4f4d3e..b34ca7afb0e6 100644 --- a/drivers/media/dvb/firewire/firedtv-1394.c +++ b/drivers/media/dvb/firewire/firedtv-1394.c @@ -58,7 +58,7 @@ static void rawiso_activity_cb(struct hpsb_iso *iso) num = hpsb_iso_n_ready(iso); if (!fdtv) { - dev_err(fdtv->device, "received at unknown iso channel\n"); + pr_err("received at unknown iso channel\n"); goto out; } diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c index 7cfccfd1b870..c338f3f62e77 100644 --- a/drivers/media/video/hdpvr/hdpvr-video.c +++ b/drivers/media/video/hdpvr/hdpvr-video.c @@ -366,7 +366,7 @@ static int hdpvr_open(struct file *file) dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file)); if (!dev) { - v4l2_err(&dev->v4l2_dev, "open failing with with ENODEV\n"); + pr_err("open failing with with ENODEV\n"); retval = -ENODEV; goto err; } diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 6248a639ba2d..c2690df33438 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1671,8 +1671,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) PDEBUG(DBG_PROBE, ""); if (usbvision == NULL) { - dev_err(&usbvision->dev->dev, - "%s: usb_get_intfdata() failed\n", __func__); + pr_err("%s: usb_get_intfdata() failed\n", __func__); return; } -- GitLab From 6afdeaf865b729287e02aafc61d8d013b89996ef Mon Sep 17 00:00:00 2001 From: Andy Walls <awalls@md.metrocast.net> Date: Sun, 23 May 2010 18:53:35 -0300 Subject: [PATCH 433/842] V4L/DVB: cx18, cx23885, v4l2 doc, MAINTAINERS: Update Andy Walls' email address A trivial change to update my email address from my dead awalls@radix.net address to my current awalls@md.metrocast.net address. Signed-off-by: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- Documentation/DocBook/v4l/v4l2.xml | 2 +- MAINTAINERS | 4 ++-- drivers/media/video/cx18/cx18-alsa-main.c | 2 +- drivers/media/video/cx18/cx18-alsa-mixer.c | 2 +- drivers/media/video/cx18/cx18-alsa-mixer.h | 2 +- drivers/media/video/cx18/cx18-alsa-pcm.c | 2 +- drivers/media/video/cx18/cx18-alsa-pcm.h | 2 +- drivers/media/video/cx18/cx18-alsa.h | 2 +- drivers/media/video/cx18/cx18-av-audio.c | 2 +- drivers/media/video/cx18/cx18-av-core.c | 2 +- drivers/media/video/cx18/cx18-av-core.h | 2 +- drivers/media/video/cx18/cx18-av-firmware.c | 2 +- drivers/media/video/cx18/cx18-cards.c | 2 +- drivers/media/video/cx18/cx18-cards.h | 2 +- drivers/media/video/cx18/cx18-driver.c | 2 +- drivers/media/video/cx18/cx18-driver.h | 2 +- drivers/media/video/cx18/cx18-dvb.c | 2 +- drivers/media/video/cx18/cx18-fileops.c | 2 +- drivers/media/video/cx18/cx18-firmware.c | 2 +- drivers/media/video/cx18/cx18-gpio.c | 2 +- drivers/media/video/cx18/cx18-gpio.h | 2 +- drivers/media/video/cx18/cx18-i2c.c | 2 +- drivers/media/video/cx18/cx18-io.c | 2 +- drivers/media/video/cx18/cx18-io.h | 4 ++-- drivers/media/video/cx18/cx18-ioctl.c | 2 +- drivers/media/video/cx18/cx18-ioctl.h | 2 +- drivers/media/video/cx18/cx18-irq.c | 2 +- drivers/media/video/cx18/cx18-irq.h | 2 +- drivers/media/video/cx18/cx18-mailbox.c | 2 +- drivers/media/video/cx18/cx18-mailbox.h | 2 +- drivers/media/video/cx18/cx18-queue.c | 2 +- drivers/media/video/cx18/cx18-queue.h | 2 +- drivers/media/video/cx18/cx18-scb.c | 2 +- drivers/media/video/cx18/cx18-scb.h | 2 +- drivers/media/video/cx18/cx18-streams.c | 2 +- drivers/media/video/cx18/cx18-streams.h | 2 +- drivers/media/video/cx23885/cx23885-input.c | 2 +- drivers/media/video/cx23885/cx23885-input.h | 2 +- drivers/media/video/cx23885/cx23885-ioctl.c | 2 +- drivers/media/video/cx23885/cx23885-ioctl.h | 2 +- drivers/media/video/cx23885/cx23885-ir.c | 2 +- drivers/media/video/cx23885/cx23885-ir.h | 2 +- drivers/media/video/cx23885/cx23888-ir.c | 2 +- drivers/media/video/cx23885/cx23888-ir.h | 2 +- 44 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml index 9737243377a3..7c3c098d5d08 100644 --- a/Documentation/DocBook/v4l/v4l2.xml +++ b/Documentation/DocBook/v4l/v4l2.xml @@ -58,7 +58,7 @@ MPEG stream embedded, sliced VBI data format in this specification. </contrib> <affiliation> <address> - <email>awalls@radix.net</email> + <email>awalls@md.metrocast.net</email> </address> </affiliation> </author> diff --git a/MAINTAINERS b/MAINTAINERS index 13608bd2e791..0200b63fb448 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1731,7 +1731,7 @@ S: Maintained F: sound/pci/cs5535audio/ CX18 VIDEO4LINUX DRIVER -M: Andy Walls <awalls@radix.net> +M: Andy Walls <awalls@md.metrocast.net> L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers) L: linux-media@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git @@ -3165,7 +3165,7 @@ F: Documentation/hwmon/it87 F: drivers/hwmon/it87.c IVTV VIDEO4LINUX DRIVER -M: Andy Walls <awalls@radix.net> +M: Andy Walls <awalls@md.metrocast.net> L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers) L: linux-media@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c index b5d7cbf4528a..d50d69da387b 100644 --- a/drivers/media/video/cx18/cx18-alsa-main.c +++ b/drivers/media/video/cx18/cx18-alsa-main.c @@ -1,7 +1,7 @@ /* * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> * * Portions of this work were sponsored by ONELAN Limited. diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.c b/drivers/media/video/cx18/cx18-alsa-mixer.c index ef21114309fe..341bddc00b77 100644 --- a/drivers/media/video/cx18/cx18-alsa-mixer.c +++ b/drivers/media/video/cx18/cx18-alsa-mixer.c @@ -2,7 +2,7 @@ * ALSA mixer controls for the * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.h b/drivers/media/video/cx18/cx18-alsa-mixer.h index 2d418db000fe..ec9238793f6f 100644 --- a/drivers/media/video/cx18/cx18-alsa-mixer.h +++ b/drivers/media/video/cx18/cx18-alsa-mixer.h @@ -2,7 +2,7 @@ * ALSA mixer controls for the * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c index 2bd312daeb1e..8f55692db36d 100644 --- a/drivers/media/video/cx18/cx18-alsa-pcm.c +++ b/drivers/media/video/cx18/cx18-alsa-pcm.c @@ -2,7 +2,7 @@ * ALSA PCM device for the * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> * * Portions of this work were sponsored by ONELAN Limited. diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.h b/drivers/media/video/cx18/cx18-alsa-pcm.h index 325662c647a0..d26e51f94577 100644 --- a/drivers/media/video/cx18/cx18-alsa-pcm.h +++ b/drivers/media/video/cx18/cx18-alsa-pcm.h @@ -2,7 +2,7 @@ * ALSA PCM device for the * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-alsa.h b/drivers/media/video/cx18/cx18-alsa.h index 88a1cde7540b..447da374c9e8 100644 --- a/drivers/media/video/cx18/cx18-alsa.h +++ b/drivers/media/video/cx18/cx18-alsa.h @@ -1,7 +1,7 @@ /* * ALSA interface to cx18 PCM capture streams * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c index 9e30983f2ff6..43d09a24b262 100644 --- a/drivers/media/video/cx18/cx18-av-audio.c +++ b/drivers/media/video/cx18/cx18-av-audio.c @@ -4,7 +4,7 @@ * Derived from cx25840-audio.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index 54371f6d6b5f..a41951cab276 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -4,7 +4,7 @@ * Derived from cx25840-core.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h index c106967bdcc3..1956991795e3 100644 --- a/drivers/media/video/cx18/cx18-av-core.h +++ b/drivers/media/video/cx18/cx18-av-core.h @@ -4,7 +4,7 @@ * Derived from cx25840-core.h * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c index b9e8cc5d264a..280aa4d22488 100644 --- a/drivers/media/video/cx18/cx18-av-firmware.c +++ b/drivers/media/video/cx18/cx18-av-firmware.c @@ -2,7 +2,7 @@ * cx18 ADEC firmware functions * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c index 74e122b5fc49..6b805afe5d20 100644 --- a/drivers/media/video/cx18/cx18-cards.c +++ b/drivers/media/video/cx18/cx18-cards.c @@ -4,7 +4,7 @@ * Derived from ivtv-cards.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h index 796e517300ac..3e750068f275 100644 --- a/drivers/media/video/cx18/cx18-cards.h +++ b/drivers/media/video/cx18/cx18-cards.h @@ -4,7 +4,7 @@ * Derived from ivtv-cards.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index c95a86ba33b0..df60f27337cf 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -4,7 +4,7 @@ * Derived from ivtv-driver.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index b9728e8eee40..9bc51a99376b 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -4,7 +4,7 @@ * Derived from ivtv-driver.h * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index 0ae2c2e1eab5..6d19f040d70f 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c @@ -2,7 +2,7 @@ * cx18 functions for DVB support * * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index e12a15020cda..9f23b90732f2 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -4,7 +4,7 @@ * Derived from ivtv-fileops.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c index 83cd559cc609..1b3fb502e6be 100644 --- a/drivers/media/video/cx18/cx18-firmware.c +++ b/drivers/media/video/cx18/cx18-firmware.c @@ -2,7 +2,7 @@ * cx18 firmware functions * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c index 86a204b5448e..5374aeb0cd22 100644 --- a/drivers/media/video/cx18/cx18-gpio.c +++ b/drivers/media/video/cx18/cx18-gpio.c @@ -4,7 +4,7 @@ * Derived from ivtv-gpio.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h index f9a5ca3566af..4aea2ef88e8d 100644 --- a/drivers/media/video/cx18/cx18-gpio.h +++ b/drivers/media/video/cx18/cx18-gpio.h @@ -4,7 +4,7 @@ * Derived from ivtv-gpio.h * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index cfa1f289b0f5..809f7d37129c 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -4,7 +4,7 @@ * Derived from ivtv-i2c.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c index ec5b3d7bcc6b..49b9dbd06248 100644 --- a/drivers/media/video/cx18/cx18-io.c +++ b/drivers/media/video/cx18/cx18-io.c @@ -2,7 +2,7 @@ * cx18 driver PCI memory mapped IO access routines * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h index 2635b3a8cc96..18974d886cf7 100644 --- a/drivers/media/video/cx18/cx18-io.h +++ b/drivers/media/video/cx18/cx18-io.h @@ -2,7 +2,7 @@ * cx18 driver PCI memory mapped IO access routines * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ /* * Readback and retry of MMIO access for reliability: * The concept was suggested by Steve Toth <stoth@linuxtv.org>. - * The implmentation is the fault of Andy Walls <awalls@radix.net>. + * The implmentation is the fault of Andy Walls <awalls@md.metrocast.net>. * * *write* functions are implied to retry the mmio unless suffixed with _noretry * *read* functions never retry the mmio (it never helps to do so) diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index b5b221c8a725..20eaf38ba959 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -4,7 +4,7 @@ * Derived from ivtv-ioctl.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h index e2ca0d152116..dcb2559ad520 100644 --- a/drivers/media/video/cx18/cx18-ioctl.h +++ b/drivers/media/video/cx18/cx18-ioctl.h @@ -4,7 +4,7 @@ * Derived from ivtv-ioctl.h * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c index af2f504eda2b..80edfe93a3d8 100644 --- a/drivers/media/video/cx18/cx18-irq.c +++ b/drivers/media/video/cx18/cx18-irq.c @@ -2,7 +2,7 @@ * cx18 interrupt handling * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h index 91f0b5278ef9..30e7eaf8cb55 100644 --- a/drivers/media/video/cx18/cx18-irq.h +++ b/drivers/media/video/cx18/cx18-irq.h @@ -2,7 +2,7 @@ * cx18 interrupt handling * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 6dcce297752f..956aa190ecca 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -2,7 +2,7 @@ * cx18 mailbox functions * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h index 33a3491c4537..077952fcbcca 100644 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ b/drivers/media/video/cx18/cx18-mailbox.h @@ -2,7 +2,7 @@ * cx18 mailbox functions * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index aefc8c8cf3c1..8884537bd62f 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c @@ -4,7 +4,7 @@ * Derived from ivtv-queue.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h index 88a6d34ad3bb..4201ddc16091 100644 --- a/drivers/media/video/cx18/cx18-queue.h +++ b/drivers/media/video/cx18/cx18-queue.h @@ -4,7 +4,7 @@ * Derived from ivtv-queue.h * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c index 34b4d03c55cd..85cc59637e54 100644 --- a/drivers/media/video/cx18/cx18-scb.c +++ b/drivers/media/video/cx18/cx18-scb.c @@ -2,7 +2,7 @@ * cx18 System Control Block initialization * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h index 368f23d08709..08877652e321 100644 --- a/drivers/media/video/cx18/cx18-scb.h +++ b/drivers/media/video/cx18/cx18-scb.h @@ -2,7 +2,7 @@ * cx18 System Control Block initialization * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index f5c91261b2db..9045f1ece0eb 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -4,7 +4,7 @@ * Derived from ivtv-streams.c * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h index 0bff0fa29763..77412bee5963 100644 --- a/drivers/media/video/cx18/cx18-streams.h +++ b/drivers/media/video/cx18/cx18-streams.h @@ -4,7 +4,7 @@ * Derived from ivtv-streams.h * * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@radix.net> + * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c index 8d306d8bb61c..5de6ba98f7a8 100644 --- a/drivers/media/video/cx23885/cx23885-input.c +++ b/drivers/media/video/cx23885/cx23885-input.c @@ -5,7 +5,7 @@ * * Most of this file is * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * * However, the cx23885_input_{init,fini} functions contained herein are * derived from Linux kernel files linux/media/video/.../...-input.c marked as: diff --git a/drivers/media/video/cx23885/cx23885-input.h b/drivers/media/video/cx23885/cx23885-input.h index 3572cb1ecfc2..75ef15d3f523 100644 --- a/drivers/media/video/cx23885/cx23885-input.h +++ b/drivers/media/video/cx23885/cx23885-input.h @@ -3,7 +3,7 @@ * * Infrared remote control input device * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx23885/cx23885-ioctl.c b/drivers/media/video/cx23885/cx23885-ioctl.c index dfb4627fb340..44812ca78899 100644 --- a/drivers/media/video/cx23885/cx23885-ioctl.c +++ b/drivers/media/video/cx23885/cx23885-ioctl.c @@ -3,7 +3,7 @@ * * Various common ioctl() support functions * - * Copyright (c) 2009 Andy Walls <awalls@radix.net> + * Copyright (c) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx23885/cx23885-ioctl.h b/drivers/media/video/cx23885/cx23885-ioctl.h index 80b0f4923c6a..315be0ca5a04 100644 --- a/drivers/media/video/cx23885/cx23885-ioctl.h +++ b/drivers/media/video/cx23885/cx23885-ioctl.h @@ -3,7 +3,7 @@ * * Various common ioctl() support functions * - * Copyright (c) 2009 Andy Walls <awalls@radix.net> + * Copyright (c) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c index 6ae982cc9856..9a677eb080af 100644 --- a/drivers/media/video/cx23885/cx23885-ir.c +++ b/drivers/media/video/cx23885/cx23885-ir.c @@ -3,7 +3,7 @@ * * Infrared device support routines - non-input, non-vl42_subdev routines * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx23885/cx23885-ir.h b/drivers/media/video/cx23885/cx23885-ir.h index 9b8a6d5d1ef6..0c9d8bda9e28 100644 --- a/drivers/media/video/cx23885/cx23885-ir.h +++ b/drivers/media/video/cx23885/cx23885-ir.h @@ -3,7 +3,7 @@ * * Infrared device support routines - non-input, non-vl42_subdev routines * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c index ad728d767d69..f63d378257a7 100644 --- a/drivers/media/video/cx23885/cx23888-ir.c +++ b/drivers/media/video/cx23885/cx23888-ir.c @@ -3,7 +3,7 @@ * * CX23888 Integrated Consumer Infrared Controller * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/video/cx23885/cx23888-ir.h b/drivers/media/video/cx23885/cx23888-ir.h index 3d446f9eb94b..d2de41caaf1d 100644 --- a/drivers/media/video/cx23885/cx23888-ir.h +++ b/drivers/media/video/cx23885/cx23888-ir.h @@ -3,7 +3,7 @@ * * CX23888 Integrated Consumer Infrared Controller * - * Copyright (C) 2009 Andy Walls <awalls@radix.net> + * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License -- GitLab From 064a2485aa45956cf1e8520e716839e9d7555b90 Mon Sep 17 00:00:00 2001 From: Ian Armstrong <ian@iarmst.demon.co.uk> Date: Sun, 23 May 2010 21:56:33 -0300 Subject: [PATCH 434/842] V4L/DVB: cx2341x: Report correct temporal setting for log-status [Andy Walls comment:] This patch from Ian removes the cx2341x module lying about the setting of the temporal filter for the log status ioctl(). Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk> Signed-off-by: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/cx2341x.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 022b480918cd..2bf44ef10fec 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -1113,7 +1113,6 @@ invalid: void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) { int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - int temporal = p->video_temporal_filter; /* Stream */ printk(KERN_INFO "%s: Stream: %s", @@ -1179,14 +1178,11 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), p->video_spatial_filter); - if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) - temporal = 0; - printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), - temporal); + p->video_temporal_filter); printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", prefix, -- GitLab From 5f39b9f660778c3b095fc380da178d58a040add5 Mon Sep 17 00:00:00 2001 From: Ian Armstrong <ian@iarmst.demon.co.uk> Date: Sun, 23 May 2010 22:10:30 -0300 Subject: [PATCH 435/842] V4L/DVB: ivtvfb : Module load / unload fixes Check firmware state when loading module & if firmware is not responding exit with an error. When module is unloaded, only disable the framebuffer & not all decoder output. Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk> Signed-off-by: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/ivtv/ivtvfb.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 49e1a283ed36..9ff3425891ed 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -1066,7 +1066,11 @@ static int ivtvfb_init_io(struct ivtv *itv) } mutex_unlock(&itv->serialize_lock); - ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); + if (ivtvfb_get_framebuffer(itv, &oi->video_rbase, + &oi->video_buffer_size) < 0) { + IVTVFB_ERR("Firmware failed to respond\n"); + return -EIO; + } /* The osd buffer size depends on the number of video buffers allocated on the PVR350 itself. For now we'll hardcode the smallest osd buffer @@ -1158,8 +1162,11 @@ static int ivtvfb_init_card(struct ivtv *itv) } /* Find & setup the OSD buffer */ - if ((rc = ivtvfb_init_io(itv))) + rc = ivtvfb_init_io(itv); + if (rc) { + ivtvfb_release_buffers(itv); return rc; + } /* Set the startup video mode information */ if ((rc = ivtvfb_init_vidmode(itv))) { @@ -1210,6 +1217,7 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p) { struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev); + struct osd_info *oi = itv->osd_info; if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) { @@ -1218,7 +1226,7 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p) return 0; } IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance); - ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); + ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info); ivtvfb_release_buffers(itv); itv->osd_video_pbase = 0; } -- GitLab From bd62307b20ff864c48541e46c3ee2bb9cc330f64 Mon Sep 17 00:00:00 2001 From: Ian Armstrong <ian@iarmst.demon.co.uk> Date: Sun, 23 May 2010 22:19:11 -0300 Subject: [PATCH 436/842] V4L/DVB: ivtv: Avoid accidental video standard change For yuv video output, pass fake values to avoid firmware trying to change video standard. Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk> Signed-off-by: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/ivtv/ivtv-streams.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index de4288cc1889..5441dc205966 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -618,12 +618,17 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) struct ivtv *itv = s->itv; struct cx2341x_mpeg_params *p = &itv->params; int datatype; + u16 width; + u16 height; if (s->vdev == NULL) return -EINVAL; IVTV_DEBUG_INFO("Setting some initial decoder settings\n"); + width = p->width; + height = p->height; + /* set audio mode to left/stereo for dual/stereo mode. */ ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); @@ -646,7 +651,14 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) 2 = yuv_from_host */ switch (s->type) { case IVTV_DEC_STREAM_TYPE_YUV: - datatype = itv->output_mode == OUT_PASSTHROUGH ? 1 : 2; + if (itv->output_mode == OUT_PASSTHROUGH) { + datatype = 1; + } else { + /* Fake size to avoid switching video standard */ + datatype = 2; + width = 720; + height = itv->is_out_50hz ? 576 : 480; + } IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype); break; case IVTV_DEC_STREAM_TYPE_MPG: @@ -655,7 +667,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) break; } if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype, - p->width, p->height, p->audio_properties)) { + width, height, p->audio_properties)) { IVTV_DEBUG_WARN("Couldn't initialize decoder source\n"); } return 0; -- GitLab From 666092c679f7d9eb9f5230087f960a487fda721c Mon Sep 17 00:00:00 2001 From: Ian Armstrong <ian@iarmst.demon.co.uk> Date: Sun, 23 May 2010 22:27:49 -0300 Subject: [PATCH 437/842] V4L/DVB: ivtv: Timing tweaks and code re-order to try and improve stability Added small delay on device open & close to allow hardware to settle. Move yuv register restore to before the decoder firmware call to stop playback. Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk> Signed-off-by: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> --- drivers/media/video/ivtv/ivtv-fileops.c | 11 +++++++---- drivers/media/video/ivtv/ivtv-streams.c | 7 +++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index abf410943cc9..3c2cc270ccd5 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -823,6 +823,12 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) IVTV_DEBUG_FILE("close() of %s\n", s->name); + if (id->type == IVTV_DEC_STREAM_TYPE_YUV && + test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) { + /* Restore registers we've changed & clean up any mess */ + ivtv_yuv_close(itv); + } + /* Stop decoding */ if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { IVTV_DEBUG_INFO("close stopping decode\n"); @@ -832,10 +838,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) } clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); - if (id->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) { - /* Restore registers we've changed & clean up any mess we've made */ - ivtv_yuv_close(itv); - } + if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames) itv->output_mode = OUT_NONE; diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 5441dc205966..9ecacab4b89b 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -670,6 +670,10 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) width, height, p->audio_properties)) { IVTV_DEBUG_WARN("Couldn't initialize decoder source\n"); } + + /* Decoder sometimes dies here, so wait a moment */ + ivtv_msleep_timeout(10, 0); + return 0; } @@ -709,6 +713,9 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) /* start playback */ ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0); + /* Let things settle before we actually start */ + ivtv_msleep_timeout(10, 0); + /* Clear the following Interrupt mask bits for decoding */ ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE); IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask); -- GitLab From f07ff97b012ff9485618faeadcc9b1e5f72ceefa Mon Sep 17 00:00:00 2001 From: Takashi Iwai <tiwai@suse.de> Date: Tue, 1 Jun 2010 07:42:03 +0200 Subject: [PATCH 438/842] usb/gadget: Replace the old USB audio FU definitions in f_audio.c The USB audio FU definitions were renewed by the commit 65f25da44b51f55e3a74301c25f29263be2bf1ba ALSA: usb-audio: unify constants from specification Signed-off-by: Takashi Iwai <tiwai@suse.de> --- drivers/usb/gadget/f_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index 43bf44514c41..b91115f84b13 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c @@ -101,7 +101,7 @@ static struct uac_feature_unit_descriptor_0 feature_unit_desc = { static struct usb_audio_control mute_control = { .list = LIST_HEAD_INIT(mute_control.list), .name = "Mute Control", - .type = UAC_MUTE_CONTROL, + .type = UAC_FU_MUTE, /* Todo: add real Mute control code */ .set = generic_set_cmd, .get = generic_get_cmd, @@ -110,7 +110,7 @@ static struct usb_audio_control mute_control = { static struct usb_audio_control volume_control = { .list = LIST_HEAD_INIT(volume_control.list), .name = "Volume Control", - .type = UAC_VOLUME_CONTROL, + .type = UAC_FU_VOLUME, /* Todo: add real Volume control code */ .set = generic_set_cmd, .get = generic_get_cmd, -- GitLab From 9f75c1b12c5ef392ddcea575b13560842c28b1b3 Mon Sep 17 00:00:00 2001 From: Daniel T Chen <crimsun@ubuntu.com> Date: Sun, 30 May 2010 13:08:41 -0400 Subject: [PATCH 439/842] ALSA: hda: Use LPIB for ASUS M2V BugLink: https://launchpad.net/bugs/587546 Symptom: On the reporter's ASUS M2V, using PulseAudio in Ubuntu 10.04 LTS results in the PA daemon crashing shortly after attempting playback of an audio file. Test case: Using Ubuntu 10.04 LTS (Linux 2.6.32.12), Linux 2.6.33, or Linux 2.6.34, attempt playback of an audio file while PulseAudio is active. Resolution: add SSID for this machine to the position_fix quirk table, explicitly specifying the LPIB method. Reported-and-Tested-By: D Tangman Cc: <stable@kernel.org> Signed-off-by: Daniel T Chen <crimsun@ubuntu.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/hda_intel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1640005e0cd9..e42ab999d0f2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2289,6 +2289,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), -- GitLab From b1faf5666438090a4dc4fceac8502edc7788b7e3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Mon, 31 May 2010 23:44:05 -0700 Subject: [PATCH 440/842] net: sock_queue_err_skb() dont mess with sk_forward_alloc Correct sk_forward_alloc handling for error_queue would need to use a backlog of frames that softirq handler could not deliver because socket is owned by user thread. Or extend backlog processing to be able to process normal and error packets. Another possibility is to not use mem charge for error queue, this is what I implemented in this patch. Note: this reverts commit 29030374 (net: fix sk_forward_alloc corruptions), since we dont need to lock socket anymore. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- include/net/sock.h | 15 +-------------- net/core/skbuff.c | 30 ++++++++++++++++++++++++++++-- net/ipv4/udp.c | 6 ++---- net/ipv6/udp.c | 6 ++---- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index ca241ea14875..731150d52799 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1524,20 +1524,7 @@ extern void sk_stop_timer(struct sock *sk, struct timer_list* timer); extern int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); -static inline int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) -{ - /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces - number of warnings when compiling with -W --ANK - */ - if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= - (unsigned)sk->sk_rcvbuf) - return -ENOMEM; - skb_set_owner_r(skb, sk); - skb_queue_tail(&sk->sk_error_queue, skb); - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk, skb->len); - return 0; -} +extern int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb); /* * Recover an error report and clear atomically diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4e7ac09c281a..9f07e749d7b1 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2965,6 +2965,34 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) } EXPORT_SYMBOL_GPL(skb_cow_data); +static void sock_rmem_free(struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + + atomic_sub(skb->truesize, &sk->sk_rmem_alloc); +} + +/* + * Note: We dont mem charge error packets (no sk_forward_alloc changes) + */ +int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) +{ + if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= + (unsigned)sk->sk_rcvbuf) + return -ENOMEM; + + skb_orphan(skb); + skb->sk = sk; + skb->destructor = sock_rmem_free; + atomic_add(skb->truesize, &sk->sk_rmem_alloc); + + skb_queue_tail(&sk->sk_error_queue, skb); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skb->len); + return 0; +} +EXPORT_SYMBOL(sock_queue_err_skb); + void skb_tstamp_tx(struct sk_buff *orig_skb, struct skb_shared_hwtstamps *hwtstamps) { @@ -2997,9 +3025,7 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, serr->ee.ee_errno = ENOMSG; serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; - bh_lock_sock(sk); err = sock_queue_err_skb(sk, skb); - bh_unlock_sock(sk); if (err) kfree_skb(skb); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 50678f9a2763..eec4ff456e33 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -633,11 +633,9 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) if (!inet->recverr) { if (!harderr || sk->sk_state != TCP_ESTABLISHED) goto out; - } else { - bh_lock_sock(sk); + } else ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *)(uh+1)); - bh_unlock_sock(sk); - } + sk->sk_err = err; sk->sk_error_report(sk); out: diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 3048f906c042..87be58673b55 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -466,11 +466,9 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (sk->sk_state != TCP_ESTABLISHED && !np->recverr) goto out; - if (np->recverr) { - bh_lock_sock(sk); + if (np->recverr) ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); - bh_unlock_sock(sk); - } + sk->sk_err = err; sk->sk_error_report(sk); out: -- GitLab From 288fcee8b7aa98796d96cd5b1b2e8005639328bf Mon Sep 17 00:00:00 2001 From: Joe Perches <joe@perches.com> Date: Mon, 31 May 2010 23:48:19 -0700 Subject: [PATCH 441/842] net/ipv4/tcp_input.c: fix compilation breakage when FASTRETRANS_DEBUG > 1 Commit: c720c7e8383aff1cb219bddf474ed89d850336e3 missed these. Signed-off-by: Joe Perches <joe@perches.com> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv4/tcp_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3e6dafcb1071..548d575e6cc6 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2639,7 +2639,7 @@ static void DBGUNDO(struct sock *sk, const char *msg) if (sk->sk_family == AF_INET) { printk(KERN_DEBUG "Undo %s %pI4/%u c%u l%u ss%u/%u p%u\n", msg, - &inet->daddr, ntohs(inet->dport), + &inet->inet_daddr, ntohs(inet->inet_dport), tp->snd_cwnd, tcp_left_out(tp), tp->snd_ssthresh, tp->prior_ssthresh, tp->packets_out); @@ -2649,7 +2649,7 @@ static void DBGUNDO(struct sock *sk, const char *msg) struct ipv6_pinfo *np = inet6_sk(sk); printk(KERN_DEBUG "Undo %s %pI6/%u c%u l%u ss%u/%u p%u\n", msg, - &np->daddr, ntohs(inet->dport), + &np->daddr, ntohs(inet->inet_dport), tp->snd_cwnd, tcp_left_out(tp), tp->snd_ssthresh, tp->prior_ssthresh, tp->packets_out); -- GitLab From 6bd17eb96ffc9c3b52927913d59da9ced5109c6a Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Mon, 31 May 2010 08:56:03 +0000 Subject: [PATCH 442/842] can: mpc5xxx_can.c: Fix build failure Fixes build error caused by the OF device_node pointer being moved into struct device. Signed-off-by: Anatolij Gustschin <agust@denx.de> Cc: Wolfgang Grandegger <wg@grandegger.com> Cc: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/can/mscan/mpc5xxx_can.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index 8af8442c694a..af753936e835 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -73,7 +73,7 @@ static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev, else *mscan_clksrc = MSCAN_CLKSRC_XTAL; - freq = mpc5xxx_get_bus_frequency(ofdev->node); + freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node); if (!freq) return 0; @@ -152,7 +152,7 @@ static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev, } /* Determine the MSCAN device index from the physical address */ - pval = of_get_property(ofdev->node, "reg", &plen); + pval = of_get_property(ofdev->dev.of_node, "reg", &plen); BUG_ON(!pval || plen < sizeof(*pval)); clockidx = (*pval & 0x80) ? 1 : 0; if (*pval & 0x2000) @@ -168,11 +168,11 @@ static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev, */ if (clock_name && !strcmp(clock_name, "ip")) { *mscan_clksrc = MSCAN_CLKSRC_IPS; - freq = mpc5xxx_get_bus_frequency(ofdev->node); + freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node); } else { *mscan_clksrc = MSCAN_CLKSRC_BUS; - pval = of_get_property(ofdev->node, + pval = of_get_property(ofdev->dev.of_node, "fsl,mscan-clock-divider", &plen); if (pval && plen == sizeof(*pval)) clockdiv = *pval; @@ -251,7 +251,7 @@ static int __devinit mpc5xxx_can_probe(struct of_device *ofdev, const struct of_device_id *id) { struct mpc5xxx_can_data *data = (struct mpc5xxx_can_data *)id->data; - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct net_device *dev; struct mscan_priv *priv; void __iomem *base; -- GitLab From 3ffd05159815d477f971a3259fc758f0c3c7e640 Mon Sep 17 00:00:00 2001 From: Sathya Perla <sathyap@serverengines.com> Date: Tue, 1 Jun 2010 00:19:33 -0700 Subject: [PATCH 443/842] be2net: convert hdr.timeout in be_cmd_loopback_test() to le32 The current code fails on ppc as hdr.timeout is not being converted to le32. Signed-off-by: Sathya Perla <sathyap@serverengines.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/benet/be_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 9e305d7fb4bd..b9ad799c719f 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1593,7 +1593,7 @@ int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req)); - req->hdr.timeout = 4; + req->hdr.timeout = cpu_to_le32(4); req->pattern = cpu_to_le64(pattern); req->src_port = cpu_to_le32(port_num); -- GitLab From aa989f5e46bb913e1a5966bb7d32eb2d00c1894e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" <mst@redhat.com> Date: Mon, 31 May 2010 01:10:01 +0000 Subject: [PATCH 444/842] virtio-net: pass gfp to add_buf virtio-net bounces buffer allocations off to a thread if it can't allocate buffers from the atomic pool. However, if posting buffers still requires atomic buffers, this is unlikely to succeed. Fix by passing in the proper gfp_t parameter. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/virtio_net.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 78eb3190b9b1..1edb7a61983c 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -340,7 +340,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp) skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len); - err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 2, skb); + err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 2, skb, gfp); if (err < 0) dev_kfree_skb(skb); @@ -385,8 +385,8 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp) /* chain first in list head */ first->private = (unsigned long)list; - err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2, - first); + err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2, + first, gfp); if (err < 0) give_pages(vi, first); @@ -404,7 +404,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp) sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE); - err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 1, page); + err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 1, page, gfp); if (err < 0) give_pages(vi, page); -- GitLab From 5ed83663f77ee7404022d046321f69545cd311b8 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov <dkirjanov@hera.kernel.org> Date: Mon, 31 May 2010 00:24:49 +0000 Subject: [PATCH 445/842] ksz884x: convert to netdev_tx_t Convert TX hook to netdev_tx_t type Signed-off-by: Denis Kirjanov <dkirjanov@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/ksz884x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index c80ca64277b2..4568b6f163eb 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -4854,7 +4854,7 @@ static inline void copy_old_skb(struct sk_buff *old, struct sk_buff *skb) * * Return 0 if successful; otherwise an error code indicating failure. */ -static int netdev_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev) { struct dev_priv *priv = netdev_priv(dev); struct dev_info *hw_priv = priv->adapter; -- GitLab From 96ed741e15896eea43f7203523db88bc8105c359 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov <dkirjanov@hera.kernel.org> Date: Mon, 31 May 2010 00:26:21 +0000 Subject: [PATCH 446/842] ksz884x: Add missing validate_addr hook Add missing validate_addr hook Signed-off-by: Denis Kirjanov <dkirjanov@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/ksz884x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 4568b6f163eb..7805bbf1d53a 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -6863,6 +6863,7 @@ static const struct net_device_ops netdev_ops = { .ndo_tx_timeout = netdev_tx_timeout, .ndo_change_mtu = netdev_change_mtu, .ndo_set_mac_address = netdev_set_mac_address, + .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = netdev_ioctl, .ndo_set_rx_mode = netdev_set_rx_mode, #ifdef CONFIG_NET_POLL_CONTROLLER -- GitLab From b42d9165e1e3d92e4e3318642463dbe592a12568 Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Tue, 1 Jun 2010 00:26:06 -0700 Subject: [PATCH 447/842] drivers/isdn/hardware/mISDN: Use GFP_ATOMIC when a lock is held The function inittiger is only called from nj_init_card, where a lock is held. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // <smpl> @gfp exists@ identifier fn; position p; @@ fn(...) { ... when != spin_unlock_irqrestore when any GFP_KERNEL@p ... when any } @locked@ identifier gfp.fn; @@ spin_lock_irqsave(...) ... when != spin_unlock_irqrestore fn(...) @depends on locked@ position gfp.p; @@ - GFP_KERNEL@p + GFP_ATOMIC // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/isdn/hardware/mISDN/netjet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index 0a3553df065f..54ae71a907f9 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -320,12 +320,12 @@ inittiger(struct tiger_hw *card) return -ENOMEM; } for (i = 0; i < 2; i++) { - card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_KERNEL); + card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_ATOMIC); if (!card->bc[i].hsbuf) { pr_info("%s: no B%d send buffer\n", card->name, i + 1); return -ENOMEM; } - card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_KERNEL); + card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_ATOMIC); if (!card->bc[i].hrbuf) { pr_info("%s: no B%d recv buffer\n", card->name, i + 1); return -ENOMEM; -- GitLab From e51fd5e22e12b39f49b1bb60b37b300b17378a43 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra <a.p.zijlstra@chello.nl> Date: Mon, 31 May 2010 12:37:30 +0200 Subject: [PATCH 448/842] sched: Fix wake_affine() vs RT tasks Mike reports that since e9e9250b (sched: Scale down cpu_power due to RT tasks), wake_affine() goes funny on RT tasks due to them still having a !0 weight and wake_affine() still subtracts that from the rq weight. Since nobody should be using se->weight for RT tasks, set the value to zero. Also, since we now use ->cpu_power to normalize rq weights to account for RT cpu usage, add that factor into the imbalance computation. Reported-by: Mike Galbraith <efault@gmx.de> Tested-by: Mike Galbraith <efault@gmx.de> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1275316109.27810.22969.camel@twins> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- kernel/sched.c | 24 ++++++------------------ kernel/sched_fair.c | 22 ++++++++++++++++------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index d48408142503..f8b8996228dd 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -544,6 +544,8 @@ struct rq { struct root_domain *rd; struct sched_domain *sd; + unsigned long cpu_power; + unsigned char idle_at_tick; /* For active balancing */ int post_schedule; @@ -1499,24 +1501,9 @@ static unsigned long target_load(int cpu, int type) return max(rq->cpu_load[type-1], total); } -static struct sched_group *group_of(int cpu) -{ - struct sched_domain *sd = rcu_dereference_sched(cpu_rq(cpu)->sd); - - if (!sd) - return NULL; - - return sd->groups; -} - static unsigned long power_of(int cpu) { - struct sched_group *group = group_of(cpu); - - if (!group) - return SCHED_LOAD_SCALE; - - return group->cpu_power; + return cpu_rq(cpu)->cpu_power; } static int task_hot(struct task_struct *p, u64 now, struct sched_domain *sd); @@ -1854,8 +1841,8 @@ static void dec_nr_running(struct rq *rq) static void set_load_weight(struct task_struct *p) { if (task_has_rt_policy(p)) { - p->se.load.weight = prio_to_weight[0] * 2; - p->se.load.inv_weight = prio_to_wmult[0] >> 1; + p->se.load.weight = 0; + p->se.load.inv_weight = WMULT_CONST; return; } @@ -7605,6 +7592,7 @@ void __init sched_init(void) #ifdef CONFIG_SMP rq->sd = NULL; rq->rd = NULL; + rq->cpu_power = SCHED_LOAD_SCALE; rq->post_schedule = 0; rq->active_balance = 0; rq->next_balance = jiffies; diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 217e4a9393e4..eed35eded602 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1225,7 +1225,6 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync) unsigned long this_load, load; int idx, this_cpu, prev_cpu; unsigned long tl_per_task; - unsigned int imbalance; struct task_group *tg; unsigned long weight; int balanced; @@ -1252,8 +1251,6 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync) tg = task_group(p); weight = p->se.load.weight; - imbalance = 100 + (sd->imbalance_pct - 100) / 2; - /* * In low-load situations, where prev_cpu is idle and this_cpu is idle * due to the sync cause above having dropped this_load to 0, we'll @@ -1263,9 +1260,21 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync) * Otherwise check if either cpus are near enough in load to allow this * task to be woken on this_cpu. */ - balanced = !this_load || - 100*(this_load + effective_load(tg, this_cpu, weight, weight)) <= - imbalance*(load + effective_load(tg, prev_cpu, 0, weight)); + if (this_load) { + unsigned long this_eff_load, prev_eff_load; + + this_eff_load = 100; + this_eff_load *= power_of(prev_cpu); + this_eff_load *= this_load + + effective_load(tg, this_cpu, weight, weight); + + prev_eff_load = 100 + (sd->imbalance_pct - 100) / 2; + prev_eff_load *= power_of(this_cpu); + prev_eff_load *= load + effective_load(tg, prev_cpu, 0, weight); + + balanced = this_eff_load <= prev_eff_load; + } else + balanced = true; /* * If the currently running task will sleep within @@ -2298,6 +2307,7 @@ static void update_cpu_power(struct sched_domain *sd, int cpu) if (!power) power = 1; + cpu_rq(cpu)->cpu_power = power; sdg->cpu_power = power; } -- GitLab From 02f726949f2be0967aa4871dd4e47d3967779b26 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra <a.p.zijlstra@chello.nl> Date: Mon, 31 May 2010 18:13:25 +0200 Subject: [PATCH 449/842] sched, trace: Fix sched_switch() prev_state argument For CONFIG_PREEMPT=y kernels the sched_switch(.prev_state) argument isn't useful because we can get preempted with current->state != TASK_RUNNING without actually getting removed from the runqueue. Cure this by treating all preempted tasks as runnable from the tracer's point of view. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cautiously-acked-by: Steven Rostedt <rostedt@goodmis.org> LKML-Reference: <1275322715.27810.23323.camel@twins> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- include/trace/events/sched.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 4f733ecea46e..b9e1dd6c6208 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -115,6 +115,23 @@ DEFINE_EVENT(sched_wakeup_template, sched_wakeup_new, TP_PROTO(struct task_struct *p, int success), TP_ARGS(p, success)); +#ifdef CREATE_TRACE_POINTS +static inline long __trace_sched_switch_state(struct task_struct *p) +{ + long state = p->state; + +#ifdef CONFIG_PREEMPT + /* + * For all intents and purposes a preempted task is a running task. + */ + if (task_thread_info(p)->preempt_count & PREEMPT_ACTIVE) + state = TASK_RUNNING; +#endif + + return state; +} +#endif + /* * Tracepoint for task switches, performed by the scheduler: */ @@ -139,7 +156,7 @@ TRACE_EVENT(sched_switch, memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN); __entry->prev_pid = prev->pid; __entry->prev_prio = prev->prio; - __entry->prev_state = prev->state; + __entry->prev_state = __trace_sched_switch_state(prev); memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN); __entry->next_pid = next->pid; __entry->next_prio = next->prio; -- GitLab From e82752d8b5a7e0a5e4d607fd8713549e2a4e2741 Mon Sep 17 00:00:00 2001 From: Joerg Roedel <joerg.roedel@amd.com> Date: Fri, 28 May 2010 14:26:48 +0200 Subject: [PATCH 450/842] x86/amd-iommu: Fix crash when request_mem_region fails When request_mem_region fails the error path tries to disable the IOMMUs. This accesses the mmio-region which was not allocated leading to a kernel crash. This patch fixes the issue. Cc: stable@kernel.org Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> --- arch/x86/kernel/amd_iommu_init.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 3bacb4d0844c..1405346c62b4 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -287,8 +287,12 @@ static u8 * __init iommu_map_mmio_space(u64 address) { u8 *ret; - if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu")) + if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu")) { + pr_err("AMD-Vi: Can not reserve memory region %llx for mmio\n", + address); + pr_err("AMD-Vi: This is a BIOS bug. Please contact your hardware vendor\n"); return NULL; + } ret = ioremap_nocache(address, MMIO_REGION_LENGTH); if (ret != NULL) @@ -1314,7 +1318,7 @@ static int __init amd_iommu_init(void) ret = amd_iommu_init_dma_ops(); if (ret) - goto free; + goto free_disable; amd_iommu_init_api(); @@ -1332,9 +1336,10 @@ static int __init amd_iommu_init(void) out: return ret; -free: +free_disable: disable_iommus(); +free: amd_iommu_uninit_devices(); free_pages((unsigned long)amd_iommu_pd_alloc_bitmap, -- GitLab From d7f0776975334070a93370ae048fda0c31a91c38 Mon Sep 17 00:00:00 2001 From: Joerg Roedel <joerg.roedel@amd.com> Date: Mon, 31 May 2010 15:05:20 +0200 Subject: [PATCH 451/842] x86/amd-iommu: Fall back to GART if initialization fails This patch implements a fallback to the GART IOMMU if this is possible and the AMD IOMMU initialization failed. Otherwise the fallback would be nommu which is very problematic on machines with more than 4GB of memory or swiotlb which hurts io-performance. Cc: stable@kernel.org Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> --- arch/x86/kernel/amd_iommu.c | 4 ---- arch/x86/kernel/amd_iommu_init.c | 9 +++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 8a9aaa8412c9..0d20286d78c6 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -2330,10 +2330,6 @@ int __init amd_iommu_init_dma_ops(void) iommu_detected = 1; swiotlb = 0; -#ifdef CONFIG_GART_IOMMU - gart_iommu_aperture_disabled = 1; - gart_iommu_aperture = 0; -#endif /* Make the driver finally visible to the drivers */ dma_ops = &amd_iommu_dma_ops; diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 1405346c62b4..3cc63e2b8dd4 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -1358,6 +1358,15 @@ free: free_unity_maps(); +#ifdef CONFIG_GART_IOMMU + /* + * We failed to initialize the AMD IOMMU - try fallback to GART + * if possible. + */ + gart_iommu_init(); + +#endif + goto out; } -- GitLab From 75d9ef1707cf3db264a549142a1f54a5380d63dc Mon Sep 17 00:00:00 2001 From: Konstantin Stepanyuk <kostyas@cqg.com> Date: Thu, 27 May 2010 02:10:11 +0400 Subject: [PATCH 452/842] perf hist: fix objdump output parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hist_entry__annotate() runs objdump with -S option so the output may contain lines of any format. If a line starts with a colon strtoull() returns 0 and calculated offset will be negative. This causes perf annotate segfaults. Make sure that strtoull() has parsed at least one digit. Cc: David S. Miller <davem@davemloft.net> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Konstantin Stepanyuk <konstantin.stepanyuk@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/hist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index cbf7eae2ce09..07f89b66b318 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -965,7 +965,7 @@ static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file, * Parse hexa addresses followed by ':' */ line_ip = strtoull(tmp, &tmp2, 16); - if (*tmp2 != ':') + if (*tmp2 != ':' || tmp == tmp2) line_ip = -1; } -- GitLab From f17625b318d9b151e7bd41e31223e9d89b2aaa77 Mon Sep 17 00:00:00 2001 From: Jens Axboe <jens.axboe@oracle.com> Date: Tue, 1 Jun 2010 11:05:22 +0200 Subject: [PATCH 453/842] Revert "writeback: ensure that WB_SYNC_NONE writeback with sb pinned is sync" This reverts commit 7c8a3554c683f512dbcee26faedb42e4c05f12fa. We are investigating a hang associated with the WB_SYNC_NONE changes, so revert them for now. Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- fs/fs-writeback.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 5c4161f1fd9a..6753912641b4 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -193,8 +193,7 @@ static void bdi_wait_on_work_clear(struct bdi_work *work) } static void bdi_alloc_queue_work(struct backing_dev_info *bdi, - struct wb_writeback_args *args, - int wait) + struct wb_writeback_args *args) { struct bdi_work *work; @@ -206,8 +205,6 @@ static void bdi_alloc_queue_work(struct backing_dev_info *bdi, if (work) { bdi_work_init(work, args); bdi_queue_work(bdi, work); - if (wait) - bdi_wait_on_work_clear(work); } else { struct bdi_writeback *wb = &bdi->wb; @@ -282,7 +279,7 @@ void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb, args.for_background = 1; } - bdi_alloc_queue_work(bdi, &args, sb_locked); + bdi_alloc_queue_work(bdi, &args); } /* @@ -912,7 +909,6 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait) while ((work = get_next_work_item(bdi, wb)) != NULL) { struct wb_writeback_args args = work->args; - int post_clear; /* * Override sync mode, in case we must wait for completion @@ -920,13 +916,11 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait) if (force_wait) work->args.sync_mode = args.sync_mode = WB_SYNC_ALL; - post_clear = WB_SYNC_ALL || args.sb_pinned; - /* * If this isn't a data integrity operation, just notify * that we have seen this work and we are now starting it. */ - if (!post_clear) + if (args.sync_mode == WB_SYNC_NONE) wb_clear_pending(wb, work); wrote += wb_writeback(wb, &args); @@ -935,7 +929,7 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait) * This is a data integrity writeback, so only do the * notification when we have completed the work. */ - if (post_clear) + if (args.sync_mode == WB_SYNC_ALL) wb_clear_pending(wb, work); } @@ -1011,7 +1005,7 @@ static void bdi_writeback_all(struct super_block *sb, long nr_pages) if (!bdi_has_dirty_io(bdi)) continue; - bdi_alloc_queue_work(bdi, &args, 0); + bdi_alloc_queue_work(bdi, &args); } rcu_read_unlock(); -- GitLab From 0e3c9a2284f5417f196e327c254d0b84c9ee8929 Mon Sep 17 00:00:00 2001 From: Jens Axboe <jaxboe@fusionio.com> Date: Tue, 1 Jun 2010 11:08:43 +0200 Subject: [PATCH 454/842] Revert "writeback: fix WB_SYNC_NONE writeback from umount" This reverts commit e913fc825dc685a444cb4c1d0f9d32f372f59861. We are investigating a hang associated with the WB_SYNC_NONE changes, so revert them for now. Conflicts: fs/fs-writeback.c mm/page-writeback.c Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- fs/fs-writeback.c | 48 +++++++++---------------------------- fs/sync.c | 2 +- include/linux/backing-dev.h | 2 +- include/linux/writeback.h | 10 -------- mm/page-writeback.c | 4 ++-- 5 files changed, 15 insertions(+), 51 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 6753912641b4..408a7877b79d 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -45,7 +45,6 @@ struct wb_writeback_args { unsigned int for_kupdate:1; unsigned int range_cyclic:1; unsigned int for_background:1; - unsigned int sb_pinned:1; }; /* @@ -231,11 +230,6 @@ static void bdi_sync_writeback(struct backing_dev_info *bdi, .sync_mode = WB_SYNC_ALL, .nr_pages = LONG_MAX, .range_cyclic = 0, - /* - * Setting sb_pinned is not necessary for WB_SYNC_ALL, but - * lets make it explicitly clear. - */ - .sb_pinned = 1, }; struct bdi_work work; @@ -251,23 +245,21 @@ static void bdi_sync_writeback(struct backing_dev_info *bdi, * @bdi: the backing device to write from * @sb: write inodes from this super_block * @nr_pages: the number of pages to write - * @sb_locked: caller already holds sb umount sem. * * Description: * This does WB_SYNC_NONE opportunistic writeback. The IO is only * started when this function returns, we make no guarentees on - * completion. Caller specifies whether sb umount sem is held already or not. + * completion. Caller need not hold sb s_umount semaphore. * */ void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb, - long nr_pages, int sb_locked) + long nr_pages) { struct wb_writeback_args args = { .sb = sb, .sync_mode = WB_SYNC_NONE, .nr_pages = nr_pages, .range_cyclic = 1, - .sb_pinned = sb_locked, }; /* @@ -592,7 +584,7 @@ static enum sb_pin_state pin_sb_for_writeback(struct writeback_control *wbc, /* * Caller must already hold the ref for this */ - if (wbc->sync_mode == WB_SYNC_ALL || wbc->sb_pinned) { + if (wbc->sync_mode == WB_SYNC_ALL) { WARN_ON(!rwsem_is_locked(&sb->s_umount)); return SB_NOT_PINNED; } @@ -766,7 +758,6 @@ static long wb_writeback(struct bdi_writeback *wb, .for_kupdate = args->for_kupdate, .for_background = args->for_background, .range_cyclic = args->range_cyclic, - .sb_pinned = args->sb_pinned, }; unsigned long oldest_jif; long wrote = 0; @@ -1214,18 +1205,6 @@ static void wait_sb_inodes(struct super_block *sb) iput(old_inode); } -static void __writeback_inodes_sb(struct super_block *sb, int sb_locked) -{ - unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); - unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); - long nr_to_write; - - nr_to_write = nr_dirty + nr_unstable + - (inodes_stat.nr_inodes - inodes_stat.nr_unused); - - bdi_start_writeback(sb->s_bdi, sb, nr_to_write, sb_locked); -} - /** * writeback_inodes_sb - writeback dirty inodes from given super_block * @sb: the superblock @@ -1237,21 +1216,16 @@ static void __writeback_inodes_sb(struct super_block *sb, int sb_locked) */ void writeback_inodes_sb(struct super_block *sb) { - __writeback_inodes_sb(sb, 0); -} -EXPORT_SYMBOL(writeback_inodes_sb); + unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); + unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); + long nr_to_write; -/** - * writeback_inodes_sb_locked - writeback dirty inodes from given super_block - * @sb: the superblock - * - * Like writeback_inodes_sb(), except the caller already holds the - * sb umount sem. - */ -void writeback_inodes_sb_locked(struct super_block *sb) -{ - __writeback_inodes_sb(sb, 1); + nr_to_write = nr_dirty + nr_unstable + + (inodes_stat.nr_inodes - inodes_stat.nr_unused); + + bdi_start_writeback(sb->s_bdi, sb, nr_to_write); } +EXPORT_SYMBOL(writeback_inodes_sb); /** * writeback_inodes_sb_if_idle - start writeback if none underway diff --git a/fs/sync.c b/fs/sync.c index e8cbd415e50a..5a537ccd2e85 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -42,7 +42,7 @@ static int __sync_filesystem(struct super_block *sb, int wait) if (wait) sync_inodes_sb(sb); else - writeback_inodes_sb_locked(sb); + writeback_inodes_sb(sb); if (sb->s_op->sync_fs) sb->s_op->sync_fs(sb, wait); diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index e6e0cb5437e6..aee5f6ce166e 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -106,7 +106,7 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev); void bdi_unregister(struct backing_dev_info *bdi); int bdi_setup_and_register(struct backing_dev_info *, char *, unsigned int); void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb, - long nr_pages, int sb_locked); + long nr_pages); int bdi_writeback_task(struct bdi_writeback *wb); int bdi_has_dirty_io(struct backing_dev_info *bdi); void bdi_arm_supers_timer(void); diff --git a/include/linux/writeback.h b/include/linux/writeback.h index cc97d6caf2b3..f64134653a8c 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -65,15 +65,6 @@ struct writeback_control { * so we use a single control to update them */ unsigned no_nrwrite_index_update:1; - - /* - * For WB_SYNC_ALL, the sb must always be pinned. For WB_SYNC_NONE, - * the writeback code will pin the sb for the caller. However, - * for eg umount, the caller does WB_SYNC_NONE but already has - * the sb pinned. If the below is set, caller already has the - * sb pinned. - */ - unsigned sb_pinned:1; }; /* @@ -82,7 +73,6 @@ struct writeback_control { struct bdi_writeback; int inode_wait(void *); void writeback_inodes_sb(struct super_block *); -void writeback_inodes_sb_locked(struct super_block *); int writeback_inodes_sb_if_idle(struct super_block *); void sync_inodes_sb(struct super_block *); void writeback_inodes_wbc(struct writeback_control *wbc); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index b289310e2c89..5fa63bdf52e4 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -597,7 +597,7 @@ static void balance_dirty_pages(struct address_space *mapping, (!laptop_mode && ((global_page_state(NR_FILE_DIRTY) + global_page_state(NR_UNSTABLE_NFS)) > background_thresh))) - bdi_start_writeback(bdi, NULL, 0, 0); + bdi_start_writeback(bdi, NULL, 0); } void set_page_dirty_balance(struct page *page, int page_mkwrite) @@ -707,7 +707,7 @@ void laptop_mode_timer_fn(unsigned long data) */ if (bdi_has_dirty_io(&q->backing_dev_info)) - bdi_start_writeback(&q->backing_dev_info, NULL, nr_pages, 0); + bdi_start_writeback(&q->backing_dev_info, NULL, nr_pages); } /* -- GitLab From b7c335713ea130d707c22d7f7c57a8eca75ded7e Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Wed, 26 May 2010 15:41:14 +0200 Subject: [PATCH 455/842] brd: support discard Support discard requests in brd by zeroing or deleting the underlying backing pages. This is simply to help with testing and documentation nature of brd code. Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Jens Axboe <jens.axboe@oracle.com> --- drivers/block/brd.c | 53 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 6081e81d5738..f1bf79d9bc0a 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -133,6 +133,28 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector) return page; } +static void brd_free_page(struct brd_device *brd, sector_t sector) +{ + struct page *page; + pgoff_t idx; + + spin_lock(&brd->brd_lock); + idx = sector >> PAGE_SECTORS_SHIFT; + page = radix_tree_delete(&brd->brd_pages, idx); + spin_unlock(&brd->brd_lock); + if (page) + __free_page(page); +} + +static void brd_zero_page(struct brd_device *brd, sector_t sector) +{ + struct page *page; + + page = brd_lookup_page(brd, sector); + if (page) + clear_highpage(page); +} + /* * Free all backing store pages and radix tree. This must only be called when * there are no other users of the device. @@ -189,6 +211,24 @@ static int copy_to_brd_setup(struct brd_device *brd, sector_t sector, size_t n) return 0; } +static void discard_from_brd(struct brd_device *brd, + sector_t sector, size_t n) +{ + while (n >= PAGE_SIZE) { + /* + * Don't want to actually discard pages here because + * re-allocating the pages can result in writeback + * deadlocks under heavy load. + */ + if (0) + brd_free_page(brd, sector); + else + brd_zero_page(brd, sector); + sector += PAGE_SIZE >> SECTOR_SHIFT; + n -= PAGE_SIZE; + } +} + /* * Copy n bytes from src to the brd starting at sector. Does not sleep. */ @@ -300,6 +340,12 @@ static int brd_make_request(struct request_queue *q, struct bio *bio) get_capacity(bdev->bd_disk)) goto out; + if (unlikely(bio_rw_flagged(bio, BIO_RW_DISCARD))) { + err = 0; + discard_from_brd(brd, sector, bio->bi_size); + goto out; + } + rw = bio_rw(bio); if (rw == READA) rw = READ; @@ -320,7 +366,7 @@ out: } #ifdef CONFIG_BLK_DEV_XIP -static int brd_direct_access (struct block_device *bdev, sector_t sector, +static int brd_direct_access(struct block_device *bdev, sector_t sector, void **kaddr, unsigned long *pfn) { struct brd_device *brd = bdev->bd_disk->private_data; @@ -437,6 +483,11 @@ static struct brd_device *brd_alloc(int i) blk_queue_max_hw_sectors(brd->brd_queue, 1024); blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY); + brd->brd_queue->limits.discard_granularity = PAGE_SIZE; + brd->brd_queue->limits.max_discard_sectors = UINT_MAX; + brd->brd_queue->limits.discard_zeroes_data = 1; + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue); + disk = brd->brd_disk = alloc_disk(1 << part_shift); if (!disk) goto out_free_queue; -- GitLab From 2c8d196759054b632788633b20e39167df36041d Mon Sep 17 00:00:00 2001 From: Philipp Reisner <philipp.reisner@linbit.com> Date: Tue, 25 May 2010 14:32:03 +0200 Subject: [PATCH 456/842] drbd: Revert "drbd: Create new current UUID as late as possible" The late-UUID writing is delayed until the next release. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- drivers/block/drbd/drbd_int.h | 9 +------- drivers/block/drbd/drbd_main.c | 34 ++++++------------------------ drivers/block/drbd/drbd_receiver.c | 11 ---------- 3 files changed, 7 insertions(+), 47 deletions(-) diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index e9654c8d5b62..c194348a46ed 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -943,8 +943,7 @@ struct drbd_conf { struct drbd_work resync_work, unplug_work, md_sync_work, - delay_probe_work, - uuid_work; + delay_probe_work; struct timer_list resync_timer; struct timer_list md_sync_timer; struct timer_list delay_probe_timer; @@ -1069,7 +1068,6 @@ struct drbd_conf { struct timeval dps_time; /* delay-probes-start-time */ unsigned int dp_volume_last; /* send_cnt of last delay probe */ int c_sync_rate; /* current resync rate after delay_probe magic */ - atomic_t new_c_uuid; }; static inline struct drbd_conf *minor_to_mdev(unsigned int minor) @@ -2219,8 +2217,6 @@ static inline int __inc_ap_bio_cond(struct drbd_conf *mdev) return 0; if (test_bit(BITMAP_IO, &mdev->flags)) return 0; - if (atomic_read(&mdev->new_c_uuid)) - return 0; return 1; } @@ -2241,9 +2237,6 @@ static inline void inc_ap_bio(struct drbd_conf *mdev, int count) * to avoid races with the reconnect code, * we need to atomic_inc within the spinlock. */ - if (atomic_read(&mdev->new_c_uuid) && atomic_add_unless(&mdev->new_c_uuid, -1, 1)) - drbd_queue_work_front(&mdev->data.work, &mdev->uuid_work); - spin_lock_irq(&mdev->req_lock); while (!__inc_ap_bio_cond(mdev)) { prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index be2d2da9cdba..1fcf2d1bcc39 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1215,18 +1215,17 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, ns.pdsk == D_OUTDATED)) { if (get_ldev(mdev)) { if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) && - mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE && - !atomic_read(&mdev->new_c_uuid)) - atomic_set(&mdev->new_c_uuid, 2); + mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) { + drbd_uuid_new_current(mdev); + drbd_send_uuids(mdev); + } put_ldev(mdev); } } if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) { - /* Diskless peer becomes primary or got connected do diskless, primary peer. */ - if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0 && - !atomic_read(&mdev->new_c_uuid)) - atomic_set(&mdev->new_c_uuid, 2); + if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0) + drbd_uuid_new_current(mdev); /* D_DISKLESS Peer becomes secondary */ if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) @@ -1350,24 +1349,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, drbd_md_sync(mdev); } -static int w_new_current_uuid(struct drbd_conf *mdev, struct drbd_work *w, int cancel) -{ - if (get_ldev(mdev)) { - if (mdev->ldev->md.uuid[UI_BITMAP] == 0) { - drbd_uuid_new_current(mdev); - if (get_net_conf(mdev)) { - drbd_send_uuids(mdev); - put_net_conf(mdev); - } - drbd_md_sync(mdev); - } - put_ldev(mdev); - } - atomic_dec(&mdev->new_c_uuid); - wake_up(&mdev->misc_wait); - - return 1; -} static int drbd_thread_setup(void *arg) { @@ -2708,7 +2689,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) atomic_set(&mdev->net_cnt, 0); atomic_set(&mdev->packet_seq, 0); atomic_set(&mdev->pp_in_use, 0); - atomic_set(&mdev->new_c_uuid, 0); mutex_init(&mdev->md_io_mutex); mutex_init(&mdev->data.mutex); @@ -2739,14 +2719,12 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) INIT_LIST_HEAD(&mdev->bm_io_work.w.list); INIT_LIST_HEAD(&mdev->delay_probes); INIT_LIST_HEAD(&mdev->delay_probe_work.list); - INIT_LIST_HEAD(&mdev->uuid_work.list); mdev->resync_work.cb = w_resync_inactive; mdev->unplug_work.cb = w_send_write_hint; mdev->md_sync_work.cb = w_md_sync; mdev->bm_io_work.w.cb = w_bitmap_io; mdev->delay_probe_work.cb = w_delay_probes; - mdev->uuid_work.cb = w_new_current_uuid; init_timer(&mdev->resync_timer); init_timer(&mdev->md_sync_timer); init_timer(&mdev->delay_probe_timer); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index bc9ab7fb2cc7..a56340dd5710 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1154,17 +1154,6 @@ int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, unsigned n_bios = 0; unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT; - if (atomic_read(&mdev->new_c_uuid)) { - if (atomic_add_unless(&mdev->new_c_uuid, -1, 1)) { - drbd_uuid_new_current(mdev); - drbd_md_sync(mdev); - - atomic_dec(&mdev->new_c_uuid); - wake_up(&mdev->misc_wait); - } - wait_event(mdev->misc_wait, !atomic_read(&mdev->new_c_uuid)); - } - /* In most cases, we will only need one bio. But in case the lower * level restrictions happen to be different at this offset on this * side than those of the sending peer, we may need to submit the -- GitLab From 344fa462e3246bd102059ccc3c59deef416676dd Mon Sep 17 00:00:00 2001 From: Lars Ellenberg <lars.ellenberg@linbit.com> Date: Tue, 25 May 2010 14:23:57 +0200 Subject: [PATCH 457/842] drbd: improve network latency, TCP_QUICKACK On Thu, Apr 29, 2010 at 04:00:50PM -0400, Eduard.Guzovsky@stratus.com wrote on drbd-dev@lists.linbit.com Subject: [Drbd-dev] DRBD small synchronous writes performance improvements > 1. TCP_QUICKACK option is set incorrectly. The goal was force TCP to > send and ACK as a "one time" event. Instead the code permanently sets > connection in the QUICKACK mode. He is right, we actually want to use an even val with TCP_QUICKACK. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- drivers/block/drbd/drbd_int.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index c194348a46ed..6d79a76ba597 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1540,7 +1540,7 @@ static inline void drbd_tcp_nodelay(struct socket *sock) static inline void drbd_tcp_quickack(struct socket *sock) { - int __user val = 1; + int __user val = 2; (void) drbd_setsockopt(sock, SOL_TCP, TCP_QUICKACK, (char __user *)&val, sizeof(val)); } -- GitLab From 5dbf1673383f2f1554f0634fdfc390d59dc2c7d6 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg <lars.ellenberg@linbit.com> Date: Tue, 25 May 2010 16:18:01 +0200 Subject: [PATCH 458/842] drbd: need to set socket bufsize early to take effect quoting tcp(7): On individual connections, the socket buffer size must be set prior to the listen(2) or connect(2) calls in order to have it take effect. This adds a wrapper to do so, and uses it appropriately. Improves performance in certain situations. Note that because we cannot easily determine which socket will be "meta" and wich "data" (bulk) socket, we adjust both sockets. Previously, DRBD only adjusted the bufsizes of the "data" socket. Thanks again to Eduard.Guzovsky@stratus.com. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- drivers/block/drbd/drbd_receiver.c | 33 +++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index a56340dd5710..f9a3e199e715 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -571,6 +571,25 @@ static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) return rv; } +/* quoting tcp(7): + * On individual connections, the socket buffer size must be set prior to the + * listen(2) or connect(2) calls in order to have it take effect. + * This is our wrapper to do so. + */ +static void drbd_setbufsize(struct socket *sock, unsigned int snd, + unsigned int rcv) +{ + /* open coded SO_SNDBUF, SO_RCVBUF */ + if (snd) { + sock->sk->sk_sndbuf = snd; + sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK; + } + if (rcv) { + sock->sk->sk_rcvbuf = rcv; + sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK; + } +} + static struct socket *drbd_try_connect(struct drbd_conf *mdev) { const char *what; @@ -592,6 +611,8 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev) sock->sk->sk_rcvtimeo = sock->sk->sk_sndtimeo = mdev->net_conf->try_connect_int*HZ; + drbd_setbufsize(sock, mdev->net_conf->sndbuf_size, + mdev->net_conf->rcvbuf_size); /* explicitly bind to the configured IP as source IP * for the outgoing connections. @@ -670,6 +691,8 @@ static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev) s_listen->sk->sk_reuse = 1; /* SO_REUSEADDR */ s_listen->sk->sk_rcvtimeo = timeo; s_listen->sk->sk_sndtimeo = timeo; + drbd_setbufsize(s_listen, mdev->net_conf->sndbuf_size, + mdev->net_conf->rcvbuf_size); what = "bind before listen"; err = s_listen->ops->bind(s_listen, @@ -856,16 +879,6 @@ retry: sock->sk->sk_priority = TC_PRIO_INTERACTIVE_BULK; msock->sk->sk_priority = TC_PRIO_INTERACTIVE; - if (mdev->net_conf->sndbuf_size) { - sock->sk->sk_sndbuf = mdev->net_conf->sndbuf_size; - sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK; - } - - if (mdev->net_conf->rcvbuf_size) { - sock->sk->sk_rcvbuf = mdev->net_conf->rcvbuf_size; - sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK; - } - /* NOT YET ... * sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10; * sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; -- GitLab From ba11ad9a3b9dd2dbb9c6686ea9d41a9a77d94327 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg <lars.ellenberg@linbit.com> Date: Tue, 25 May 2010 16:26:16 +0200 Subject: [PATCH 459/842] drbd: improve usage of MSG_MORE It seems to improve performance if we allow the "p_data" header in its own frame (no MSG_MORE), but sendpage all but the last page with MSG_MORE. This is also in preparation of a later zero copy receive implementation. Suggested by Eduard.Guzovsky@stratus.com on drbd-dev. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- drivers/block/drbd/drbd_main.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 1fcf2d1bcc39..c978557b4b80 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2272,9 +2272,9 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * * with page_count == 0 or PageSlab. */ static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page, - int offset, size_t size) + int offset, size_t size, unsigned msg_flags) { - int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, 0); + int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, msg_flags); kunmap(page); if (sent == size) mdev->send_cnt += size>>9; @@ -2282,7 +2282,7 @@ static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page, } static int _drbd_send_page(struct drbd_conf *mdev, struct page *page, - int offset, size_t size) + int offset, size_t size, unsigned msg_flags) { mm_segment_t oldfs = get_fs(); int sent, ok; @@ -2295,14 +2295,15 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page, * __page_cache_release a page that would actually still be referenced * by someone, leading to some obscure delayed Oops somewhere else. */ if (disable_sendpage || (page_count(page) < 1) || PageSlab(page)) - return _drbd_no_send_page(mdev, page, offset, size); + return _drbd_no_send_page(mdev, page, offset, size, msg_flags); + msg_flags |= MSG_NOSIGNAL; drbd_update_congested(mdev); set_fs(KERNEL_DS); do { sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page, offset, len, - MSG_NOSIGNAL); + msg_flags); if (sent == -EAGAIN) { if (we_should_drop_the_connection(mdev, mdev->data.socket)) @@ -2331,9 +2332,11 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio) { struct bio_vec *bvec; int i; + /* hint all but last page with MSG_MORE */ __bio_for_each_segment(bvec, bio, i, 0) { if (!_drbd_no_send_page(mdev, bvec->bv_page, - bvec->bv_offset, bvec->bv_len)) + bvec->bv_offset, bvec->bv_len, + i == bio->bi_vcnt -1 ? 0 : MSG_MORE)) return 0; } return 1; @@ -2343,12 +2346,13 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) { struct bio_vec *bvec; int i; + /* hint all but last page with MSG_MORE */ __bio_for_each_segment(bvec, bio, i, 0) { if (!_drbd_send_page(mdev, bvec->bv_page, - bvec->bv_offset, bvec->bv_len)) + bvec->bv_offset, bvec->bv_len, + i == bio->bi_vcnt -1 ? 0 : MSG_MORE)) return 0; } - return 1; } @@ -2356,9 +2360,11 @@ static int _drbd_send_zc_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e) { struct page *page = e->pages; unsigned len = e->size; + /* hint all but last page with MSG_MORE */ page_chain_for_each(page) { unsigned l = min_t(unsigned, len, PAGE_SIZE); - if (!_drbd_send_page(mdev, page, 0, l)) + if (!_drbd_send_page(mdev, page, 0, l, + page_chain_next(page) ? MSG_MORE : 0)) return 0; len -= l; } @@ -2438,11 +2444,11 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) p.dp_flags = cpu_to_be32(dp_flags); set_bit(UNPLUG_REMOTE, &mdev->flags); ok = (sizeof(p) == - drbd_send(mdev, mdev->data.socket, &p, sizeof(p), MSG_MORE)); + drbd_send(mdev, mdev->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0)); if (ok && dgs) { dgb = mdev->int_dig_out; drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, dgb); - ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE); + ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); } if (ok) { if (mdev->net_conf->wire_protocol == DRBD_PROT_A) @@ -2491,11 +2497,11 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, return 0; ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p, - sizeof(p), MSG_MORE); + sizeof(p), dgs ? MSG_MORE : 0); if (ok && dgs) { dgb = mdev->int_dig_out; drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb); - ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE); + ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); } if (ok) ok = _drbd_send_zc_ee(mdev, e); -- GitLab From 039e1fb65496636778e24c881a5e58ed7c39fbb3 Mon Sep 17 00:00:00 2001 From: Andrea Gelmini <andrea.gelmini@gelma.net> Date: Sun, 23 May 2010 21:48:13 +0200 Subject: [PATCH 460/842] drbd: removed duplicated #includes drbd/drbd_receiver.c: linux/mm.h is included more than once. Signed-off-by: Andrea Gelmini <andrea.gelmini@gelma.net> Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- drivers/block/drbd/drbd_receiver.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index f9a3e199e715..dff48701b84d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -42,7 +42,6 @@ #include <linux/unistd.h> #include <linux/vmalloc.h> #include <linux/random.h> -#include <linux/mm.h> #include <linux/string.h> #include <linux/scatterlist.h> #include "drbd_int.h" -- GitLab From 32fa7e91f923d8b2578c42016ff3a94efc9968a2 Mon Sep 17 00:00:00 2001 From: Philipp Reisner <philipp.reisner@linbit.com> Date: Wed, 26 May 2010 17:13:18 +0200 Subject: [PATCH 461/842] drbd: Removed the now empty w_io_error() function Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- drivers/block/drbd/drbd_int.h | 1 - drivers/block/drbd/drbd_req.c | 27 +-------------------------- drivers/block/drbd/drbd_worker.c | 14 -------------- 3 files changed, 1 insertion(+), 41 deletions(-) diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 6d79a76ba597..86605f6d0854 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1474,7 +1474,6 @@ extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int); extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int); extern int w_resync_inactive(struct drbd_conf *, struct drbd_work *, int); extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int); -extern int w_io_error(struct drbd_conf *, struct drbd_work *, int); extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int); extern int w_make_resync_request(struct drbd_conf *, struct drbd_work *, int); extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 3397f11d0ba9..e6c4d579eaba 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -102,32 +102,7 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const } } - /* if it was a local io error, we want to notify our - * peer about that, and see if we need to - * detach the disk and stuff. - * to avoid allocating some special work - * struct, reuse the request. */ - - /* THINK - * why do we do this not when we detect the error, - * but delay it until it is "done", i.e. possibly - * until the next barrier ack? */ - - if (rw == WRITE && - ((s & RQ_LOCAL_MASK) && !(s & RQ_LOCAL_OK))) { - if (!(req->w.list.next == LIST_POISON1 || - list_empty(&req->w.list))) { - /* DEBUG ASSERT only; if this triggers, we - * probably corrupt the worker list here */ - dev_err(DEV, "req->w.list.next = %p\n", req->w.list.next); - dev_err(DEV, "req->w.list.prev = %p\n", req->w.list.prev); - } - req->w.cb = w_io_error; - drbd_queue_work(&mdev->data.work, &req->w); - /* drbd_req_free() is done in w_io_error */ - } else { - drbd_req_free(req); - } + drbd_req_free(req); } static void queue_barrier(struct drbd_conf *mdev) diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 727ff6339754..a12b447bafbd 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -257,20 +257,6 @@ void drbd_endio_pri(struct bio *bio, int error) complete_master_bio(mdev, &m); } -int w_io_error(struct drbd_conf *mdev, struct drbd_work *w, int cancel) -{ - struct drbd_request *req = container_of(w, struct drbd_request, w); - - /* NOTE: mdev->ldev can be NULL by the time we get here! */ - /* D_ASSERT(mdev->ldev->dc.on_io_error != EP_PASS_ON); */ - - /* the only way this callback is scheduled is from _req_may_be_done, - * when it is done and had a local write error, see comments there */ - drbd_req_free(req); - - return TRUE; -} - int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { struct drbd_request *req = container_of(w, struct drbd_request, w); -- GitLab From d255e5ff5fc6cc6c60dd014d1261448a7bbc8134 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg <lars.ellenberg@linbit.com> Date: Thu, 27 May 2010 09:45:45 +0200 Subject: [PATCH 462/842] drbd: fix hang on local read errors while disconnected "canceled" w_read_retry_remote never completed, if they have been canceled after drbd_disconnect connection teardown cleanup has already run (or we are currently not connected anyways). Fixed by not queueing a remote retry if we already know it won't work (pdsk not uptodate), and cleanup ourselves on "cancel", in case we hit a race with drbd_disconnect. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- drivers/block/drbd/drbd_req.c | 22 +++++++++++++--------- drivers/block/drbd/drbd_req.h | 1 + drivers/block/drbd/drbd_worker.c | 6 ++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index e6c4d579eaba..8915644af722 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -452,20 +452,21 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, dev_alert(DEV, "Local READ failed sec=%llus size=%u\n", (unsigned long long)req->sector, req->size); - /* _req_mod(req,to_be_send); oops, recursion... */ D_ASSERT(!(req->rq_state & RQ_NET_MASK)); - req->rq_state |= RQ_NET_PENDING; - inc_ap_pending(mdev); __drbd_chk_io_error(mdev, FALSE); put_ldev(mdev); - /* NOTE: if we have no connection, - * or know the peer has no good data either, - * then we don't actually need to "queue_for_net_read", - * but we do so anyways, since the drbd_io_error() - * and the potential state change to "Diskless" - * needs to be done from process context */ + /* no point in retrying if there is no good remote data, + * or we have no connection. */ + if (mdev->state.pdsk != D_UP_TO_DATE) { + _req_may_be_done(req, m); + break; + } + + /* _req_mod(req,to_be_send); oops, recursion... */ + req->rq_state |= RQ_NET_PENDING; + inc_ap_pending(mdev); /* fall through: _req_mod(req,queue_for_net_read); */ case queue_for_net_read: @@ -575,6 +576,9 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, _req_may_be_done(req, m); break; + case read_retry_remote_canceled: + req->rq_state &= ~RQ_NET_QUEUED; + /* fall through, in case we raced with drbd_disconnect */ case connection_lost_while_pending: /* transfer log cleanup after connection loss */ /* assert something? */ diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 16119d7056cc..02d575d24518 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -91,6 +91,7 @@ enum drbd_req_event { send_failed, handed_over_to_network, connection_lost_while_pending, + read_retry_remote_canceled, recv_acked_by_peer, write_acked_by_peer, write_acked_by_peer_and_sis, /* and set_in_sync */ diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index a12b447bafbd..67371fcbc5aa 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -266,10 +266,8 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * to give the disk the chance to relocate that block */ spin_lock_irq(&mdev->req_lock); - if (cancel || - mdev->state.conn < C_CONNECTED || - mdev->state.pdsk <= D_INCONSISTENT) { - _req_mod(req, send_canceled); + if (cancel || mdev->state.pdsk != D_UP_TO_DATE) { + _req_mod(req, read_retry_remote_canceled); spin_unlock_irq(&mdev->req_lock); dev_alert(DEV, "WE ARE LOST. Local IO failure, no peer.\n"); return 1; -- GitLab From 7383506c87237dbd627f0b8b72b50117f25c5ca2 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg <lars.ellenberg@linbit.com> Date: Thu, 27 May 2010 11:51:56 +0200 Subject: [PATCH 463/842] drbd: use drbd specific ratelimit instead of global printk_ratelimit using the global printk_ratelimit() may mask other messages. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 86605f6d0854..485ed8c7d623 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1725,7 +1725,7 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach, switch (mdev->ldev->dc.on_io_error) { case EP_PASS_ON: if (!forcedetach) { - if (printk_ratelimit()) + if (__ratelimit(&drbd_ratelimit_state)) dev_err(DEV, "Local IO failed in %s." "Passing error on...\n", where); break; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index c978557b4b80..6b077f93acc6 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3783,7 +3783,7 @@ _drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) if (ret) { fault_count++; - if (printk_ratelimit()) + if (__ratelimit(&drbd_ratelimit_state)) dev_warn(DEV, "***Simulating %s failure\n", _drbd_fault_str(type)); } -- GitLab From 2a0ab2cd73c26835e635ed4e3868f983519048fb Mon Sep 17 00:00:00 2001 From: Philipp Reisner <philipp.reisner@linbit.com> Date: Wed, 26 May 2010 17:59:55 +0200 Subject: [PATCH 464/842] drbd: Reduce verbosity The "Local READ/WRITE failed" messages are too verbose. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- drivers/block/drbd/drbd_req.c | 5 ----- drivers/block/drbd/drbd_worker.c | 4 ---- 2 files changed, 9 deletions(-) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 8915644af722..654f1ef5cbb0 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -428,9 +428,6 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state &= ~RQ_LOCAL_PENDING; - dev_alert(DEV, "Local WRITE failed sec=%llus size=%u\n", - (unsigned long long)req->sector, req->size); - /* and now: check how to handle local io error. */ __drbd_chk_io_error(mdev, FALSE); _req_may_be_done(req, m); put_ldev(mdev); @@ -450,8 +447,6 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state &= ~RQ_LOCAL_PENDING; - dev_alert(DEV, "Local READ failed sec=%llus size=%u\n", - (unsigned long long)req->sector, req->size); D_ASSERT(!(req->rq_state & RQ_NET_MASK)); __drbd_chk_io_error(mdev, FALSE); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 67371fcbc5aa..b623ceee2a4a 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -224,9 +224,6 @@ void drbd_endio_pri(struct bio *bio, int error) enum drbd_req_event what; int uptodate = bio_flagged(bio, BIO_UPTODATE); - if (error) - dev_warn(DEV, "p %s: error=%d\n", - bio_data_dir(bio) == WRITE ? "write" : "read", error); if (!error && !uptodate) { dev_warn(DEV, "p %s: setting error to -EIO\n", bio_data_dir(bio) == WRITE ? "write" : "read"); @@ -269,7 +266,6 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) if (cancel || mdev->state.pdsk != D_UP_TO_DATE) { _req_mod(req, read_retry_remote_canceled); spin_unlock_irq(&mdev->req_lock); - dev_alert(DEV, "WE ARE LOST. Local IO failure, no peer.\n"); return 1; } spin_unlock_irq(&mdev->req_lock); -- GitLab From 099c5c310e9744bd0654881bb55c137051228e56 Mon Sep 17 00:00:00 2001 From: Philipp Reisner <philipp.reisner@linbit.com> Date: Thu, 27 May 2010 13:46:35 +0200 Subject: [PATCH 465/842] Preparing 8.3.8rc2 Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- include/linux/drbd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/drbd.h b/include/linux/drbd.h index 68530521ad00..30da4ae48972 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h @@ -53,7 +53,7 @@ extern const char *drbd_buildtag(void); -#define REL_VERSION "8.3.8rc1" +#define REL_VERSION "8.3.8rc2" #define API_VERSION 88 #define PRO_VERSION_MIN 86 #define PRO_VERSION_MAX 94 -- GitLab From c02514850d67be8db6b2b6658cbc23ac1fbf8bc7 Mon Sep 17 00:00:00 2001 From: Pierre Tardy <tardyp@gmail.com> Date: Mon, 31 May 2010 23:12:09 +0200 Subject: [PATCH 466/842] perf scripts python: Give field dict to unhandled callback trace_unhandled() callback does not allow to access event fields, this patch resolves the problem. It can also been used as a more pythonic and flexible way for script writters to demux event types This will for example greatly simplify pytimechart event demux. Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Tom Zanussi <tzanussi@gmail.com> Cc: Ingo Molnar <mingo@elte.hu>, Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <1275340329-2397-1-git-send-email-tardyp@gmail.com> Signed-off-by: Pierre Tardy <tardyp@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/scripts/python/check-perf-trace.py | 3 +- .../scripting-engines/trace-event-python.c | 50 +++++++++++++------ 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py index 964d934395ff..d9f7893e315c 100644 --- a/tools/perf/scripts/python/check-perf-trace.py +++ b/tools/perf/scripts/python/check-perf-trace.py @@ -51,8 +51,7 @@ def kmem__kmalloc(event_name, context, common_cpu, flag_str("kmem__kmalloc", "gfp_flags", gfp_flags)), -def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs, - common_pid, common_comm): +def trace_unhandled(event_name, context, event_fields_dict): try: unhandled[event_name] += 1 except TypeError: diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 81f39cab3aaa..33a632523743 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -208,7 +208,7 @@ static void python_process_event(int cpu, void *data, int size __unused, unsigned long long nsecs, char *comm) { - PyObject *handler, *retval, *context, *t, *obj; + PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; static char handler_name[256]; struct format_field *field; unsigned long long val; @@ -232,6 +232,14 @@ static void python_process_event(int cpu, void *data, sprintf(handler_name, "%s__%s", event->system, event->name); + handler = PyDict_GetItemString(main_dict, handler_name); + if (handler && !PyCallable_Check(handler)) + handler = NULL; + if (!handler) { + dict = PyDict_New(); + if (!dict) + Py_FatalError("couldn't create Python dict"); + } s = nsecs / NSECS_PER_SEC; ns = nsecs - s * NSECS_PER_SEC; @@ -242,12 +250,20 @@ static void python_process_event(int cpu, void *data, PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); PyTuple_SetItem(t, n++, PyCObject_FromVoidPtr(scripting_context, NULL)); - PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); - PyTuple_SetItem(t, n++, PyInt_FromLong(s)); - PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); - PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); - PyTuple_SetItem(t, n++, PyString_FromString(comm)); + if (handler) { + PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); + PyTuple_SetItem(t, n++, PyInt_FromLong(s)); + PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); + PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); + PyTuple_SetItem(t, n++, PyString_FromString(comm)); + } else { + PyDict_SetItemString(dict, "common_cpu", PyInt_FromLong(cpu)); + PyDict_SetItemString(dict, "common_s", PyInt_FromLong(s)); + PyDict_SetItemString(dict, "common_ns", PyInt_FromLong(ns)); + PyDict_SetItemString(dict, "common_pid", PyInt_FromLong(pid)); + PyDict_SetItemString(dict, "common_comm", PyString_FromString(comm)); + } for (field = event->format.fields; field; field = field->next) { if (field->flags & FIELD_IS_STRING) { int offset; @@ -272,27 +288,31 @@ static void python_process_event(int cpu, void *data, obj = PyLong_FromUnsignedLongLong(val); } } - PyTuple_SetItem(t, n++, obj); + if (handler) + PyTuple_SetItem(t, n++, obj); + else + PyDict_SetItemString(dict, field->name, obj); + } + if (!handler) + PyTuple_SetItem(t, n++, dict); if (_PyTuple_Resize(&t, n) == -1) Py_FatalError("error resizing Python tuple"); - handler = PyDict_GetItemString(main_dict, handler_name); - if (handler && PyCallable_Check(handler)) { + if (handler) { retval = PyObject_CallObject(handler, t); if (retval == NULL) handler_call_die(handler_name); } else { handler = PyDict_GetItemString(main_dict, "trace_unhandled"); if (handler && PyCallable_Check(handler)) { - if (_PyTuple_Resize(&t, N_COMMON_FIELDS) == -1) - Py_FatalError("error resizing Python tuple"); retval = PyObject_CallObject(handler, t); if (retval == NULL) handler_call_die("trace_unhandled"); } + Py_DECREF(dict); } Py_DECREF(t); @@ -548,12 +568,10 @@ static int python_generate_script(const char *outfile) } fprintf(ofp, "def trace_unhandled(event_name, context, " - "common_cpu, common_secs, common_nsecs,\n\t\t" - "common_pid, common_comm):\n"); + "event_fields_dict):\n"); - fprintf(ofp, "\t\tprint_header(event_name, common_cpu, " - "common_secs, common_nsecs,\n\t\tcommon_pid, " - "common_comm)\n\n"); + fprintf(ofp, "\t\tprint ' '.join(['%%s=%%s'%%(k,str(v))" + "for k,v in sorted(event_fields_dict.items())])\n\n"); fprintf(ofp, "def print_header(" "event_name, cpu, secs, nsecs, pid, comm):\n" -- GitLab From 713b686494a577b3c4f4f9f585a4705fc30d51c2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Tue, 1 Jun 2010 12:17:48 +0200 Subject: [PATCH 467/842] cciss: call BUG() earlier I moved the range check after the increment. The current code would write past the end of the array once before calling BUG(). Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- drivers/block/cciss_scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index e1d0e2cfec72..3381505c8a6c 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -188,11 +188,11 @@ scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd) sa = h->scsi_ctlr; stk = &sa->cmd_stack; + stk->top++; if (stk->top >= CMD_STACK_SIZE) { printk("cciss: scsi_cmd_free called too many times.\n"); BUG(); } - stk->top++; stk->elem[stk->top] = (struct cciss_scsi_cmd_stack_elem_t *) cmd; } -- GitLab From 28f4197e5d4707311febeec8a0eb97cb5fd93c97 Mon Sep 17 00:00:00 2001 From: Jens Axboe <jaxboe@fusionio.com> Date: Tue, 1 Jun 2010 12:23:18 +0200 Subject: [PATCH 468/842] block: disable preemption before using sched_clock() Commit 9195291e5f05e01d67f9a09c756b8aca8f009089 added calls to sched_clock() from preemptible code. sched_clock() is both the wrong interface AND cannot be called without preempt disabled. Apply a temporary fix to get rid of the warnings, a real patch is in the works. Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- include/linux/blkdev.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 8b7f5e0914ad..09a840264d6f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1211,14 +1211,23 @@ struct work_struct; int kblockd_schedule_work(struct request_queue *q, struct work_struct *work); #ifdef CONFIG_BLK_CGROUP +/* + * This should not be using sched_clock(). A real patch is in progress + * to fix this up, until that is in place we need to disable preemption + * around sched_clock() in this function and set_io_start_time_ns(). + */ static inline void set_start_time_ns(struct request *req) { + preempt_disable(); req->start_time_ns = sched_clock(); + preempt_enable(); } static inline void set_io_start_time_ns(struct request *req) { + preempt_disable(); req->io_start_time_ns = sched_clock(); + preempt_enable(); } static inline uint64_t rq_start_time_ns(struct request *req) -- GitLab From e30c7c3b306312c157d67eedd6a01920518b756c Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp> Date: Tue, 1 Jun 2010 14:10:47 +0100 Subject: [PATCH 469/842] binfmt_elf_fdpic: Fix clear_user() error handling clear_user() returns the number of bytes that could not be copied rather than an error code. So we should return -EFAULT rather than directly returning the results. Without this patch, positive values may be returned to elf_fdpic_map_file() and the following error handlings do not function as expected. 1. ret = elf_fdpic_map_file_constdisp_on_uclinux(params, file, mm); if (ret < 0) return ret; 2. ret = elf_fdpic_map_file_by_direct_mmap(params, file, mm); if (ret < 0) return ret; Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp> Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Mike Frysinger <vapier@gentoo.org> CC: Alexander Viro <viro@zeniv.linux.org.uk> CC: Andrew Morton <akpm@linux-foundation.org> CC: Daisuke HATAYAMA <d.hatayama@jp.fujitsu.com> CC: Paul Mundt <lethal@linux-sh.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- fs/binfmt_elf_fdpic.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 2c5f9a0e5d72..63039ed9576f 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -990,10 +990,9 @@ static int elf_fdpic_map_file_constdisp_on_uclinux( /* clear any space allocated but not loaded */ if (phdr->p_filesz < phdr->p_memsz) { - ret = clear_user((void *) (seg->addr + phdr->p_filesz), - phdr->p_memsz - phdr->p_filesz); - if (ret) - return ret; + if (clear_user((void *) (seg->addr + phdr->p_filesz), + phdr->p_memsz - phdr->p_filesz)) + return -EFAULT; } if (mm) { @@ -1027,7 +1026,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, struct elf32_fdpic_loadseg *seg; struct elf32_phdr *phdr; unsigned long load_addr, delta_vaddr; - int loop, dvset, ret; + int loop, dvset; load_addr = params->load_addr; delta_vaddr = 0; @@ -1127,9 +1126,8 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, * PT_LOAD */ if (prot & PROT_WRITE && disp > 0) { kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr, disp); - ret = clear_user((void __user *) maddr, disp); - if (ret) - return ret; + if (clear_user((void __user *) maddr, disp)) + return -EFAULT; maddr += disp; } @@ -1164,19 +1162,17 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, if (prot & PROT_WRITE && excess1 > 0) { kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr + phdr->p_filesz, excess1); - ret = clear_user((void __user *) maddr + phdr->p_filesz, - excess1); - if (ret) - return ret; + if (clear_user((void __user *) maddr + phdr->p_filesz, + excess1)) + return -EFAULT; } #else if (excess > 0) { kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr + phdr->p_filesz, excess); - ret = clear_user((void *) maddr + phdr->p_filesz, excess); - if (ret) - return ret; + if (clear_user((void *) maddr + phdr->p_filesz, excess)) + return -EFAULT; } #endif -- GitLab From 2e8949f09e3097c629f33323eaf280cf5c88c81a Mon Sep 17 00:00:00 2001 From: Alan Cox <alan@linux.intel.com> Date: Tue, 1 Jun 2010 12:51:00 +0100 Subject: [PATCH 470/842] intel_scu_ipc: Length fix Commands with data must set the length in the message. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/platform/x86/intel_scu_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 576c3ed92435..40658e3385b4 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -524,7 +524,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, for (i = 0; i < inlen; i++) ipc_data_writel(*in++, 4 * i); - ipc_command(cmd << 12 | sub); + ipc_command((cmd << 12) | sub | (inlen << 18)); err = busy_loop(); for (i = 0; i < outlen; i++) -- GitLab From e29df91e67428c1a651d18df6ec047fcb30282d3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Fri, 28 May 2010 12:33:15 +0200 Subject: [PATCH 471/842] SFI: do not return freed pointer We never actually use the return value of sfi_sysfs_install_table() but it still seems wrong to return a freed pointer. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Len Brown <len.brown@intel.com> --- drivers/sfi/sfi_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c index 005195958647..ceba593dc84f 100644 --- a/drivers/sfi/sfi_core.c +++ b/drivers/sfi/sfi_core.c @@ -441,8 +441,10 @@ struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa) ret = sysfs_create_bin_file(tables_kobj, &tbl_attr->attr); - if (ret) + if (ret) { kfree(tbl_attr); + tbl_attr = NULL; + } sfi_unmap_table(th); return tbl_attr; -- GitLab From 0a76a34ff0804f1f413807b2e2d12117c2b602ca Mon Sep 17 00:00:00 2001 From: Len Brown <len.brown@intel.com> Date: Tue, 1 Jun 2010 12:13:23 -0400 Subject: [PATCH 472/842] ACPI: update feature-removal.txt to reflect deleted acpi=ht option Per plan, acpi=ht was removed in 2.6.35-rc1. Signed-off-by: Len Brown <len.brown@intel.com> --- Documentation/feature-removal-schedule.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 672be0109d02..c268783bc4e7 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -578,15 +578,6 @@ Who: Avi Kivity <avi@redhat.com> ---------------------------- -What: "acpi=ht" boot option -When: 2.6.35 -Why: Useful in 2003, implementation is a hack. - Generally invoked by accident today. - Seen as doing more harm than good. -Who: Len Brown <len.brown@intel.com> - ----------------------------- - What: iwlwifi 50XX module parameters When: 2.6.40 Why: The "..50" modules parameters were used to configure 5000 series and -- GitLab From 5c113fbeed7a5a192d8431a768965f8a45c16475 Mon Sep 17 00:00:00 2001 From: Daniel J Blueman <daniel.blueman@gmail.com> Date: Tue, 1 Jun 2010 12:15:11 +0100 Subject: [PATCH 473/842] fix cpu_chain section mismatch... In commit e9fb7631ebcd ("cpu-hotplug: introduce cpu_notify(), __cpu_notify(), cpu_notify_nofail()") the new helper functions access cpu_chain. As a result, it shouldn't be marked __cpuinitdata (via section mismatch warning). Alternatively, the helper functions should be forced inline, or marked __ref or __cpuinit. In the meantime, this patch silences the warning the trivial way. Signed-off-by: Daniel J Blueman <daniel.blueman@gmail.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- kernel/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cpu.c b/kernel/cpu.c index 8b92539b4754..97d1b426a4ac 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -34,7 +34,7 @@ void cpu_maps_update_done(void) mutex_unlock(&cpu_add_remove_lock); } -static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain); +static RAW_NOTIFIER_HEAD(cpu_chain); /* If set, cpu_up and cpu_down will return -EBUSY and do nothing. * Should always be manipulated under cpu_add_remove_lock -- GitLab From 037776fcbe73236408f6c9ca97c782457efd6b53 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov <dkirjanov@hera.kernel.org> Date: Tue, 1 Jun 2010 17:15:39 +0100 Subject: [PATCH 474/842] AFS: Fix possible null pointer dereference in afs_alloc_server() Fix a possible null pointer dereference in afs_alloc_server(): the server pointer is NULL if there was an allocation failure, and under such a condition, we can't dereference it in the _leave() statement. Signed-off-by: Denis Kirjanov <dkirjanov@kernel.org> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- fs/afs/server.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/afs/server.c b/fs/afs/server.c index f49099516675..9fdc7fe3a7bc 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c @@ -91,9 +91,10 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell, memcpy(&server->addr, addr, sizeof(struct in_addr)); server->addr.s_addr = addr->s_addr; + _leave(" = %p{%d}", server, atomic_read(&server->usage)); + } else { + _leave(" = NULL [nomem]"); } - - _leave(" = %p{%d}", server, atomic_read(&server->usage)); return server; } -- GitLab From 0a6531ebea13b164825ba28e77dcbed3e9386884 Mon Sep 17 00:00:00 2001 From: Randy Dunlap <randy.dunlap@oracle.com> Date: Tue, 1 Jun 2010 09:55:07 -0700 Subject: [PATCH 475/842] Documentation/timers/hpet_example.c: only build on X86 We should only build hpet_example on x86[-64], where it is implemented. It can cause build errors on other architectures. Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Reported-by: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Arjan van de Ven <arjan@infradead.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- Documentation/timers/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/timers/Makefile b/Documentation/timers/Makefile index c85625f4ab25..73f75f8a87dc 100644 --- a/Documentation/timers/Makefile +++ b/Documentation/timers/Makefile @@ -2,7 +2,7 @@ obj- := dummy.o # List of programs to build -hostprogs-y := hpet_example +hostprogs-$(CONFIG_X86) := hpet_example # Tell kbuild to always build the programs always := $(hostprogs-y) -- GitLab From 06b43672a9e665cab18dc7b77d56d36884b90d45 Mon Sep 17 00:00:00 2001 From: Jeff Layton <jlayton@redhat.com> Date: Tue, 1 Jun 2010 10:54:45 -0400 Subject: [PATCH 476/842] cifs: fix page refcount leak Commit 315e995c63a15cb4d4efdbfd70fe2db191917f7a is causing OOM kills when stress-testing a CIFS filesystem. The VFS readpages operation takes a page reference. The older code just handed this reference off to the page cache, but the new code takes an extra one. The simplest fix is to put the new reference after add_to_page_cache_lru. Signed-off-by: Jeff Layton <jlayton@redhat.com> Acked-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Steve French <sfrench@us.ibm.com> --- fs/cifs/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index f1ff785b2292..75541af4b3db 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1952,6 +1952,7 @@ static void cifs_copy_cache_pages(struct address_space *mapping, bytes_read -= PAGE_CACHE_SIZE; continue; } + page_cache_release(page); target = kmap_atomic(page, KM_USER0); -- GitLab From 9bc354998f8aa8a83b0cd430e8fcf2cbc3be7367 Mon Sep 17 00:00:00 2001 From: Adam Jackson <ajax@redhat.com> Date: Fri, 28 May 2010 17:17:37 -0400 Subject: [PATCH 477/842] drm/i915: Honor sync polarity from VBT panel timing descriptors I'm actually kind of shocked that it works at all otherwise. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_bios.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 4c748d8f73d6..96f75d7f6633 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -95,6 +95,16 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, panel_fixed_mode->clock = dvo_timing->clock * 10; panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; + if (dvo_timing->hsync_positive) + panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC; + else + panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC; + + if (dvo_timing->vsync_positive) + panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC; + else + panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; + /* Some VBTs have bogus h/vtotal values */ if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; -- GitLab From e3a815fcd38043b8f1bb526123d8ab6ae01deb77 Mon Sep 17 00:00:00 2001 From: Zou Nan hai <nanhai.zou@intel.com> Date: Mon, 31 May 2010 13:58:47 +0800 Subject: [PATCH 478/842] drm/i915: add HAS_BSD check to i915_getparam This will let userland only try to use the new media decode functionality when the appropriate kernel is present. Signed-off-by: Zou Nan hai <nanhai.zou@intel.com> Signed-off-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ include/drm/i915_drm.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 6577798d3441..84ce95602f00 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -744,6 +744,9 @@ static int i915_getparam(struct drm_device *dev, void *data, /* depends on GEM */ value = dev_priv->has_gem; break; + case I915_PARAM_HAS_BSD: + value = HAS_BSD(dev); + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index e9168704cabe..7f0028e1010b 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -275,6 +275,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_OVERLAY 7 #define I915_PARAM_HAS_PAGEFLIPPING 8 #define I915_PARAM_HAS_EXECBUF2 9 +#define I915_PARAM_HAS_BSD 10 typedef struct drm_i915_getparam { int param; -- GitLab From 397f385bdba6cdf7752467a7ae81810340929e44 Mon Sep 17 00:00:00 2001 From: Bruno Randolf <br1@einfach.org> Date: Wed, 19 May 2010 10:30:49 +0900 Subject: [PATCH 479/842] ath5k: wake queues on reset We can wake all queues after a chip reset since everything should be set up and we are ready to transmit. If we don't do that we might end up starting up with stopped queues, not beeing able to transmit. (This started to happen after "ath5k: clean up queue manipulation" but since periodic calibration also stopped and started the queues this effect was hidden most of the time). This way we can also get rid of the superfluous ath5k_reset_wake() function. Signed-off-by: Bruno Randolf <br1@einfach.org> Acked-by: Nick Kossifidis <mickflemm@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/ath/ath5k/base.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index cc6d41dec332..2978359c4366 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -222,7 +222,6 @@ static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath5k_txq *txq); static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan); -static int ath5k_reset_wake(struct ath5k_softc *sc); static int ath5k_start(struct ieee80211_hw *hw); static void ath5k_stop(struct ieee80211_hw *hw); static int ath5k_add_interface(struct ieee80211_hw *hw, @@ -2770,7 +2769,7 @@ ath5k_tasklet_reset(unsigned long data) { struct ath5k_softc *sc = (void *)data; - ath5k_reset_wake(sc); + ath5k_reset(sc, sc->curchan); } /* @@ -2941,23 +2940,13 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) ath5k_beacon_config(sc); /* intrs are enabled by ath5k_beacon_config */ + ieee80211_wake_queues(sc->hw); + return 0; err: return ret; } -static int -ath5k_reset_wake(struct ath5k_softc *sc) -{ - int ret; - - ret = ath5k_reset(sc, sc->curchan); - if (!ret) - ieee80211_wake_queues(sc->hw); - - return ret; -} - static int ath5k_start(struct ieee80211_hw *hw) { return ath5k_init(hw->priv); -- GitLab From 8ae5977ff95c03fe6c36a5721c57dcb4bfe4f290 Mon Sep 17 00:00:00 2001 From: Johannes Berg <johannes@sipsolutions.net> Date: Sun, 30 May 2010 14:52:58 +0200 Subject: [PATCH 480/842] mac80211: fix blockack-req processing Daniel reported that the paged RX changes had broken blockack request frame processing due to using data that wasn't really part of the skb data. Fix this using skb_copy_bits() for the needed data. As a side effect, this adds a check on processing too short frames, which previously this code could do. Reported-by: Daniel Halperin <dhalperi@cs.washington.edu> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Daniel Halperin <dhalperi@cs.washington.edu> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- net/mac80211/rx.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6e2a7bcd8cb8..5e0b65406c44 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1818,17 +1818,26 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) return RX_CONTINUE; if (ieee80211_is_back_req(bar->frame_control)) { + struct { + __le16 control, start_seq_num; + } __packed bar_data; + if (!rx->sta) return RX_DROP_MONITOR; + + if (skb_copy_bits(skb, offsetof(struct ieee80211_bar, control), + &bar_data, sizeof(bar_data))) + return RX_DROP_MONITOR; + spin_lock(&rx->sta->lock); - tid = le16_to_cpu(bar->control) >> 12; + tid = le16_to_cpu(bar_data.control) >> 12; if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) { spin_unlock(&rx->sta->lock); return RX_DROP_MONITOR; } tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; - start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; + start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4; /* reset session timer */ if (tid_agg_rx->timeout) -- GitLab From 51a0d38de26226f2779912d92f155b93d539da9a Mon Sep 17 00:00:00 2001 From: Johannes Berg <johannes.berg@intel.com> Date: Mon, 31 May 2010 12:00:12 +0200 Subject: [PATCH 481/842] mac80211: fix dialog token allocator The dialog token allocator has apparently been broken since b83f4e15 ("mac80211: fix deadlock in sta->lock") because it got moved out under the spinlock. Fix it. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- net/mac80211/agg-tx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index c163d0a149f4..98258b7341e3 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -332,14 +332,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) IEEE80211_QUEUE_STOP_REASON_AGGREGATION); spin_unlock(&local->ampdu_lock); - spin_unlock_bh(&sta->lock); - /* send an addBA request */ + /* prepare tid data */ sta->ampdu_mlme.dialog_token_allocator++; sta->ampdu_mlme.tid_tx[tid]->dialog_token = sta->ampdu_mlme.dialog_token_allocator; sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; + spin_unlock_bh(&sta->lock); + + /* send AddBA request */ ieee80211_send_addba_request(sdata, pubsta->addr, tid, sta->ampdu_mlme.tid_tx[tid]->dialog_token, sta->ampdu_mlme.tid_tx[tid]->ssn, -- GitLab From b5c874f14c5f57cc8654e9184694196c466147bb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@redhat.com> Date: Tue, 1 Jun 2010 12:37:05 -0300 Subject: [PATCH 482/842] perf buildid-list: Fix --with-hits event processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we use plain 'perf buildid-list' we use only what is in the buildid table in the perf.data header. And those have absolute pathnames because at 'perf record' time we used __perf_session__process_events and that doesn't sets up the path shortening code in map__new() that happens if symbol_conf.full_paths is false, the default. On the other hand, when we use 'perf buildid-list --with-hits' we process all the events using perf_session__process_events, adding entries to the global DSO list _after_ removing the current directory from the DSO name, for presentation purposes. Because of that we end up having two entries in the DSO list when recording events for binaries using relative pathnames. Fix it minimally by setting symbol_conf.full_paths to true when marking the DSOs with hits in 'perf buildid-list --with-hits', as used by 'perf archive' Right fix longer term is to shorten the path only at presentation time. Will be done for 2.6.36. Reported-by: Stephane Eranian <eranian@google.com> Tested-by: Stephane Eranian <eranian@google.com> Cc: David S. Miller <davem@davemloft.net> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <20100601183837.GC4093@ghostprotocols.net> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/builtin-buildid-list.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 44a47e13bd67..99890728409e 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -43,8 +43,10 @@ static int __cmd_buildid_list(void) if (session == NULL) return -1; - if (with_hits) + if (with_hits) { + symbol_conf.full_paths = true; perf_session__process_events(session, &build_id__mark_dso_hit_ops); + } perf_session__fprintf_dsos_buildid(session, stdout, with_hits); -- GitLab From 08a66859e69264f3223560d06b88e80c1a6a6387 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Tue, 1 Jun 2010 20:58:22 +0100 Subject: [PATCH 483/842] FS-Cache: Remove unneeded null checks fscache_write_op() makes unnecessary checks of the page variable to see if it is NULL. It can't be NULL at those points as the kernel would already have crashed a little higher up where we examined page->index. Furthermore, unless radix_tree_gang_lookup_tag() can return 1 but no page, a NULL pointer crash should not be encountered there as we can only get there if r_t_g_l_t() returned 1. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- fs/fscache/page.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 47aefd376e54..723b889fd219 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -710,30 +710,26 @@ static void fscache_write_op(struct fscache_operation *_op) goto superseded; } - if (page) { - radix_tree_tag_set(&cookie->stores, page->index, - FSCACHE_COOKIE_STORING_TAG); - radix_tree_tag_clear(&cookie->stores, page->index, - FSCACHE_COOKIE_PENDING_TAG); - } + radix_tree_tag_set(&cookie->stores, page->index, + FSCACHE_COOKIE_STORING_TAG); + radix_tree_tag_clear(&cookie->stores, page->index, + FSCACHE_COOKIE_PENDING_TAG); spin_unlock(&cookie->stores_lock); spin_unlock(&object->lock); - if (page) { - fscache_set_op_state(&op->op, "Store"); - fscache_stat(&fscache_n_store_pages); - fscache_stat(&fscache_n_cop_write_page); - ret = object->cache->ops->write_page(op, page); - fscache_stat_d(&fscache_n_cop_write_page); - fscache_set_op_state(&op->op, "EndWrite"); - fscache_end_page_write(object, page); - if (ret < 0) { - fscache_set_op_state(&op->op, "Abort"); - fscache_abort_object(object); - } else { - fscache_enqueue_operation(&op->op); - } + fscache_set_op_state(&op->op, "Store"); + fscache_stat(&fscache_n_store_pages); + fscache_stat(&fscache_n_cop_write_page); + ret = object->cache->ops->write_page(op, page); + fscache_stat_d(&fscache_n_cop_write_page); + fscache_set_op_state(&op->op, "EndWrite"); + fscache_end_page_write(object, page); + if (ret < 0) { + fscache_set_op_state(&op->op, "Abort"); + fscache_abort_object(object); + } else { + fscache_enqueue_operation(&op->op); } _leave(""); -- GitLab From b160fdabe93a8a53094f90f02bf4dcb500782aab Mon Sep 17 00:00:00 2001 From: Christoph Hellwig <hch@lst.de> Date: Tue, 1 Jun 2010 21:59:18 +0200 Subject: [PATCH 484/842] nfsd: nfsd_setattr needs to call commit_metadata The conversion of write_inode_now calls to commit_metadata in commit f501912a35c02eadc55ca9396ece55fe36f785d0 missed out the call in nfsd_setattr. But without this conversion we can't guarantee that a SETATTR request has actually been commited to disk with XFS, which causes a regression from 2.6.32 (only for NFSv2, but anyway). Signed-off-by: Christoph Hellwig <hch@lst.de> Cc: stable@kernel.org Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> --- fs/nfsd/vfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 6dd5f1970e01..3440dd8a4fb3 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -443,8 +443,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, if (size_change) put_write_access(inode); if (!err) - if (EX_ISSYNC(fhp->fh_export)) - write_inode_now(inode, 1); + commit_metadata(fhp); out: return err; -- GitLab From 13a4214cd9ec14d7b77e98bd3ee51f60f868a6e5 Mon Sep 17 00:00:00 2001 From: Henry C Chang <henry_c_chang@tcloudcomputing.com> Date: Tue, 1 Jun 2010 11:31:08 -0700 Subject: [PATCH 485/842] ceph: fix d_subdirs ordering problem We misused list_move_tail() to order the dentry in d_subdirs. This will screw up the d_subdirs order. This bug can be reliably reproduced by: 1. mount ceph fs. 2. on ceph fs, git clone git://ceph.newdream.net/git/ceph.git 3. Run autogen.sh in ceph directory. (Note: Errors only occur at the first time you run autogen.sh.) Signed-off-by: Henry C Chang <henry_c_chang@tcloudcomputing.com> Signed-off-by: Sage Weil <sage@newdream.net> --- fs/ceph/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 226f5a50d362..ab47f46ca282 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -827,7 +827,7 @@ static void ceph_set_dentry_offset(struct dentry *dn) spin_lock(&dcache_lock); spin_lock(&dn->d_lock); - list_move_tail(&dir->d_subdirs, &dn->d_u.d_child); + list_move(&dn->d_u.d_child, &dir->d_subdirs); dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, dn->d_u.d_child.prev, dn->d_u.d_child.next); spin_unlock(&dn->d_lock); -- GitLab From 205475679a74fe40b63a1c7f41110fdb64daa8b9 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh <yehuda@hq.newdream.net> Date: Tue, 1 Jun 2010 10:37:40 -0700 Subject: [PATCH 486/842] ceph: fix memory leak in statfs Freeing the statfs request structure when required. Signed-off-by: Yehuda Sadeh <yehuda@hq.newdream.net> Signed-off-by: Sage Weil <sage@newdream.net> --- fs/ceph/mon_client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ceph/mon_client.c b/fs/ceph/mon_client.c index 21c62e9b7d1d..07a539906e67 100644 --- a/fs/ceph/mon_client.c +++ b/fs/ceph/mon_client.c @@ -400,6 +400,8 @@ static void release_generic_request(struct kref *kref) ceph_msg_put(req->reply); if (req->request) ceph_msg_put(req->request); + + kfree(req); } static void put_generic_request(struct ceph_mon_generic_request *req) -- GitLab From 558d3499bd059d4534b1f2b69dc1c562acc733fe Mon Sep 17 00:00:00 2001 From: Sage Weil <sage@newdream.net> Date: Tue, 1 Jun 2010 12:51:12 -0700 Subject: [PATCH 487/842] ceph: fix f_namelen reported by statfs We were setting f_namelen in kstatfs to PATH_MAX instead of NAME_MAX. That disagrees with ceph_lookup behavior (which checks against NAME_MAX), and also makes the pjd posix test suite spit out ugly errors because with can't clean up its temporary files. Signed-off-by: Sage Weil <sage@newdream.net> --- fs/ceph/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 4e0bee240b9d..8db88792b5ad 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -89,7 +89,7 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_files = le64_to_cpu(st.num_objects); buf->f_ffree = -1; - buf->f_namelen = PATH_MAX; + buf->f_namelen = NAME_MAX; buf->f_frsize = PAGE_CACHE_SIZE; /* leave fsid little-endian, regardless of host endianness */ -- GitLab From abb24f4846d1537d73605e8576de8359a98e5ced Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Wed, 2 Jun 2010 16:26:13 +0900 Subject: [PATCH 488/842] usb: gadget: m66592-udc pio to mmio accessor conversion. m66592-udc is erroneously using PIO routines on MMIO registers, which presently blows up for any platform that elects to either override or do away with PIO routines. This managed to work for the common cases since the PIO routines were simply wrapped to their MMIO counterparts. This switches over to using the MMIO routines directly, and enables us to kill off a lot of superfluous casting in the process. Acked-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- drivers/usb/gadget/m66592-udc.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index 8b960deed680..c3caf1ac73ce 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -537,35 +537,35 @@ struct m66592 { /*-------------------------------------------------------------------------*/ static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset) { - return inw((unsigned long)m66592->reg + offset); + return ioread16(m66592->reg + offset); } static inline void m66592_read_fifo(struct m66592 *m66592, unsigned long offset, void *buf, unsigned long len) { - unsigned long fifoaddr = (unsigned long)m66592->reg + offset; + void __iomem *fifoaddr = m66592->reg + offset; if (m66592->pdata->on_chip) { len = (len + 3) / 4; - insl(fifoaddr, buf, len); + ioread32_rep(fifoaddr, buf, len); } else { len = (len + 1) / 2; - insw(fifoaddr, buf, len); + ioread16_rep(fifoaddr, buf, len); } } static inline void m66592_write(struct m66592 *m66592, u16 val, unsigned long offset) { - outw(val, (unsigned long)m66592->reg + offset); + iowrite16(val, m66592->reg + offset); } static inline void m66592_write_fifo(struct m66592 *m66592, unsigned long offset, void *buf, unsigned long len) { - unsigned long fifoaddr = (unsigned long)m66592->reg + offset; + void __iomem *fifoaddr = m66592->reg + offset; if (m66592->pdata->on_chip) { unsigned long count; @@ -573,25 +573,25 @@ static inline void m66592_write_fifo(struct m66592 *m66592, int i; count = len / 4; - outsl(fifoaddr, buf, count); + iowrite32_rep(fifoaddr, buf, count); if (len & 0x00000003) { pb = buf + count * 4; for (i = 0; i < (len & 0x00000003); i++) { if (m66592_read(m66592, M66592_CFBCFG)) /* le */ - outb(pb[i], fifoaddr + (3 - i)); + iowrite8(pb[i], fifoaddr + (3 - i)); else - outb(pb[i], fifoaddr + i); + iowrite8(pb[i], fifoaddr + i); } } } else { unsigned long odd = len & 0x0001; len = len / 2; - outsw(fifoaddr, buf, len); + iowrite16_rep(fifoaddr, buf, len); if (odd) { unsigned char *p = buf + len*2; - outb(*p, fifoaddr); + iowrite8(*p, fifoaddr); } } } -- GitLab From e8b48669de54d390644c77cd26d5c9fccbc1e0a1 Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Wed, 2 Jun 2010 16:27:12 +0900 Subject: [PATCH 489/842] usb: gadget: r8a66597-udc pio to mmio accessor conversion. r8a66597-udc is erroneously using PIO routines on MMIO registers, which presently blows up for any platform that elects to either override or do away with PIO routines. This managed to work for the common cases since the PIO routines were simply wrapped to their MMIO counterparts. This switches over to using the MMIO routines directly, and enables us to kill off a lot of superfluous casting in the process. Acked-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- drivers/usb/gadget/r8a66597-udc.c | 4 ++-- drivers/usb/gadget/r8a66597-udc.h | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 888d8f166c0b..70a817842755 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1500,7 +1500,7 @@ static int __exit r8a66597_remove(struct platform_device *pdev) struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev); del_timer_sync(&r8a66597->timer); - iounmap((void *)r8a66597->reg); + iounmap(r8a66597->reg); free_irq(platform_get_irq(pdev, 0), r8a66597); r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); #ifdef CONFIG_HAVE_CLK @@ -1578,7 +1578,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) init_timer(&r8a66597->timer); r8a66597->timer.function = r8a66597_timer; r8a66597->timer.data = (unsigned long)r8a66597; - r8a66597->reg = (unsigned long)reg; + r8a66597->reg = reg; #ifdef CONFIG_HAVE_CLK if (r8a66597->pdata->on_chip) { diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index 9a537aa07968..f763b5190afa 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -91,7 +91,7 @@ struct r8a66597_ep { struct r8a66597 { spinlock_t lock; - unsigned long reg; + void __iomem *reg; #ifdef CONFIG_HAVE_CLK struct clk *clk; @@ -127,7 +127,7 @@ struct r8a66597 { static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset) { - return inw(r8a66597->reg + offset); + return ioread16(r8a66597->reg + offset); } static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, @@ -135,7 +135,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, unsigned char *buf, int len) { - unsigned long fifoaddr = r8a66597->reg + offset; + void __iomem *fifoaddr = r8a66597->reg + offset; unsigned int data; int i; @@ -144,7 +144,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, /* aligned buf case */ if (len >= 4 && !((unsigned long)buf & 0x03)) { - insl(fifoaddr, buf, len / 4); + ioread32_rep(fifoaddr, buf, len / 4); buf += len & ~0x03; len &= 0x03; } @@ -152,7 +152,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, /* unaligned buf case */ for (i = 0; i < len; i++) { if (!(i & 0x03)) - data = inl(fifoaddr); + data = ioread32(fifoaddr); buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; } @@ -161,7 +161,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, /* aligned buf case */ if (len >= 2 && !((unsigned long)buf & 0x01)) { - insw(fifoaddr, buf, len / 2); + ioread16_rep(fifoaddr, buf, len / 2); buf += len & ~0x01; len &= 0x01; } @@ -169,7 +169,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, /* unaligned buf case */ for (i = 0; i < len; i++) { if (!(i & 0x01)) - data = inw(fifoaddr); + data = ioread16(fifoaddr); buf[i] = (data >> ((i & 0x01) * 8)) & 0xff; } @@ -179,7 +179,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, unsigned long offset) { - outw(val, r8a66597->reg + offset); + iowrite16(val, r8a66597->reg + offset); } static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, @@ -187,21 +187,21 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, unsigned char *buf, int len) { - unsigned long fifoaddr = r8a66597->reg + offset; + void __iomem *fifoaddr = r8a66597->reg + offset; int adj = 0; int i; if (r8a66597->pdata->on_chip) { /* 32-bit access only if buf is 32-bit aligned */ if (len >= 4 && !((unsigned long)buf & 0x03)) { - outsl(fifoaddr, buf, len / 4); + iowrite32_rep(fifoaddr, buf, len / 4); buf += len & ~0x03; len &= 0x03; } } else { /* 16-bit access only if buf is 16-bit aligned */ if (len >= 2 && !((unsigned long)buf & 0x01)) { - outsw(fifoaddr, buf, len / 2); + iowrite16_rep(fifoaddr, buf, len / 2); buf += len & ~0x01; len &= 0x01; } @@ -216,7 +216,7 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, } for (i = 0; i < len; i++) - outb(buf[i], fifoaddr + adj - (i & adj)); + iowrite8(buf[i], fifoaddr + adj - (i & adj)); } static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, -- GitLab From 1c98347e613bf17ea2f18c9766ce0ab77f65a96d Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Wed, 2 Jun 2010 16:27:54 +0900 Subject: [PATCH 490/842] usb: r8a66597-hcd pio to mmio accessor conversion. r8a66597-hcd is erroneously using PIO routines on MMIO registers, which presently blows up for any platform that elects to either override or do away with PIO routines. This managed to work for the common cases since the PIO routines were simply wrapped to their MMIO counterparts. This switches over to using the MMIO routines directly, and enables us to kill off a lot of superfluous casting in the process. Acked-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- drivers/usb/host/r8a66597-hcd.c | 4 ++-- drivers/usb/host/r8a66597.h | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 6db57ab6079d..1a2bb4ce638f 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2404,7 +2404,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev) del_timer_sync(&r8a66597->rh_timer); usb_remove_hcd(hcd); - iounmap((void *)r8a66597->reg); + iounmap(r8a66597->reg); #ifdef CONFIG_HAVE_CLK if (r8a66597->pdata->on_chip) clk_put(r8a66597->clk); @@ -2496,7 +2496,7 @@ static int __devinit r8a66597_probe(struct platform_device *pdev) init_timer(&r8a66597->rh_timer); r8a66597->rh_timer.function = r8a66597_timer; r8a66597->rh_timer.data = (unsigned long)r8a66597; - r8a66597->reg = (unsigned long)reg; + r8a66597->reg = reg; /* make sure no interrupts are pending */ ret = r8a66597_clock_enable(r8a66597); diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index 228e3fb23854..95d0f5adfdcf 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -112,7 +112,7 @@ struct r8a66597_root_hub { struct r8a66597 { spinlock_t lock; - unsigned long reg; + void __iomem *reg; #ifdef CONFIG_HAVE_CLK struct clk *clk; #endif @@ -170,67 +170,67 @@ static inline struct urb *r8a66597_get_urb(struct r8a66597 *r8a66597, static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset) { - return inw(r8a66597->reg + offset); + return ioread16(r8a66597->reg + offset); } static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, unsigned long offset, u16 *buf, int len) { - unsigned long fifoaddr = r8a66597->reg + offset; + void __iomem *fifoaddr = r8a66597->reg + offset; unsigned long count; if (r8a66597->pdata->on_chip) { count = len / 4; - insl(fifoaddr, buf, count); + ioread32_rep(fifoaddr, buf, count); if (len & 0x00000003) { - unsigned long tmp = inl(fifoaddr); + unsigned long tmp = ioread32(fifoaddr); memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03); } } else { len = (len + 1) / 2; - insw(fifoaddr, buf, len); + ioread16_rep(fifoaddr, buf, len); } } static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, unsigned long offset) { - outw(val, r8a66597->reg + offset); + iowrite16(val, r8a66597->reg + offset); } static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, unsigned long offset, u16 *buf, int len) { - unsigned long fifoaddr = r8a66597->reg + offset; + void __iomem *fifoaddr = r8a66597->reg + offset; unsigned long count; unsigned char *pb; int i; if (r8a66597->pdata->on_chip) { count = len / 4; - outsl(fifoaddr, buf, count); + iowrite32_rep(fifoaddr, buf, count); if (len & 0x00000003) { pb = (unsigned char *)buf + count * 4; for (i = 0; i < (len & 0x00000003); i++) { if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND) - outb(pb[i], fifoaddr + i); + iowrite8(pb[i], fifoaddr + i); else - outb(pb[i], fifoaddr + 3 - i); + iowrite8(pb[i], fifoaddr + 3 - i); } } } else { int odd = len & 0x0001; len = len / 2; - outsw(fifoaddr, buf, len); + ioread16_rep(fifoaddr, buf, len); if (unlikely(odd)) { buf = &buf[len]; - outb((unsigned char)*buf, fifoaddr); + iowrite8((unsigned char)*buf, fifoaddr); } } } -- GitLab From 86e4dd5add77ab809f5427391dfabb8f78cbcb58 Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Tue, 25 May 2010 20:06:13 +0900 Subject: [PATCH 491/842] sh: support for platforms without PIO. This extends some of the existing special casing for HAS_IOPORT platforms and gets it to the point where platforms can begin to conditionally select it. The major changes here are that the PIO routines themselves go away completely, including all of the machvec port mapping wrappers. With this in place it's possible for any non-machvec abusing platform to disable PIO completely. At present this is left as an opt-in until the abusers are the odd ones out instead of the majority. Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/Kconfig | 5 ++++- arch/sh/include/asm/io.h | 8 ++++++++ arch/sh/include/asm/machvec.h | 9 +++++---- arch/sh/kernel/Makefile | 3 ++- arch/sh/kernel/io.c | 22 ---------------------- arch/sh/kernel/io_generic.c | 20 ++++++++++++++++++++ arch/sh/kernel/io_trapped.c | 4 ++++ arch/sh/kernel/machvec.c | 17 +++++++++++------ 8 files changed, 54 insertions(+), 34 deletions(-) diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 0e318c905eea..1eef24d04bbf 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -9,7 +9,7 @@ config SUPERH def_bool y select EMBEDDED select HAVE_CLK - select HAVE_IDE + select HAVE_IDE if HAS_IOPORT select HAVE_LMB select HAVE_OPROFILE select HAVE_GENERIC_DMA_COHERENT @@ -174,6 +174,9 @@ config ARCH_HAS_DEFAULT_IDLE config ARCH_HAS_CPU_IDLE_WAIT def_bool y +config NO_IOPORT + bool + config IO_TRAPPED bool diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index f689554e17c1..b237d525d592 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -39,6 +39,8 @@ #include <asm/io_generic.h> #include <asm/io_trapped.h> +#ifdef CONFIG_HAS_IOPORT + #define inb(p) sh_mv.mv_inb((p)) #define inw(p) sh_mv.mv_inw((p)) #define inl(p) sh_mv.mv_inl((p)) @@ -60,6 +62,8 @@ #define outsw(p,b,c) sh_mv.mv_outsw((p), (b), (c)) #define outsl(p,b,c) sh_mv.mv_outsl((p), (b), (c)) +#endif + #define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile u8 __force *)(a) = (v)) #define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile u16 __force *)(a) = (v)) #define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile u32 __force *)(a) = (v)) @@ -240,6 +244,8 @@ __BUILD_MEMORY_STRING(q, u64) #define IO_SPACE_LIMIT 0xffffffff +#ifdef CONFIG_HAS_IOPORT + /* * This function provides a method for the generic case where a * board-specific ioport_map simply needs to return the port + some @@ -255,6 +261,8 @@ static inline void __set_io_port_base(unsigned long pbase) #define __ioport_map(p, n) sh_mv.mv_ioport_map((p), (n)) +#endif + /* We really want to try and get these to memcpy etc */ void memcpy_fromio(void *, const volatile void __iomem *, unsigned long); void memcpy_toio(volatile void __iomem *, const void *, unsigned long); diff --git a/arch/sh/include/asm/machvec.h b/arch/sh/include/asm/machvec.h index bc0218cb72e1..a0b0cf79cf8a 100644 --- a/arch/sh/include/asm/machvec.h +++ b/arch/sh/include/asm/machvec.h @@ -19,6 +19,10 @@ struct sh_machine_vector { const char *mv_name; int mv_nr_irqs; + int (*mv_irq_demux)(int irq); + void (*mv_init_irq)(void); + +#ifdef CONFIG_HAS_IOPORT u8 (*mv_inb)(unsigned long); u16 (*mv_inw)(unsigned long); u32 (*mv_inl)(unsigned long); @@ -40,12 +44,9 @@ struct sh_machine_vector { void (*mv_outsw)(unsigned long, const void *src, unsigned long count); void (*mv_outsl)(unsigned long, const void *src, unsigned long count); - int (*mv_irq_demux)(int irq); - - void (*mv_init_irq)(void); - void __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size); void (*mv_ioport_unmap)(void __iomem *); +#endif int (*mv_clk_init)(void); int (*mv_mode_pins)(void); diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 650b92f00ee5..e25f3c69525d 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -12,7 +12,7 @@ endif CFLAGS_REMOVE_return_address.o = -pg obj-y := clkdev.o debugtraps.o dma-nommu.o dumpstack.o \ - idle.o io.o io_generic.o irq.o \ + idle.o io.o irq.o \ irq_$(BITS).o machvec.o nmi_debug.o process.o \ process_$(BITS).o ptrace_$(BITS).o \ reboot.o return_address.o \ @@ -39,6 +39,7 @@ obj-$(CONFIG_DUMP_CODE) += disassemble.o obj-$(CONFIG_HIBERNATION) += swsusp.o obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o +obj-$(CONFIG_HAS_IOPORT) += io_generic.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c index 4770c241c679..5c51b794ba2a 100644 --- a/arch/sh/kernel/io.c +++ b/arch/sh/kernel/io.c @@ -112,25 +112,3 @@ void memset_io(volatile void __iomem *dst, int c, unsigned long count) } } EXPORT_SYMBOL(memset_io); - -#ifndef CONFIG_GENERIC_IOMAP - -void __iomem *ioport_map(unsigned long port, unsigned int nr) -{ - void __iomem *ret; - - ret = __ioport_map_trapped(port, nr); - if (ret) - return ret; - - return __ioport_map(port, nr); -} -EXPORT_SYMBOL(ioport_map); - -void ioport_unmap(void __iomem *addr) -{ - sh_mv.mv_ioport_unmap(addr); -} -EXPORT_SYMBOL(ioport_unmap); - -#endif /* CONFIG_GENERIC_IOMAP */ diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c index e1e1dbd19557..447d78f666f9 100644 --- a/arch/sh/kernel/io_generic.c +++ b/arch/sh/kernel/io_generic.c @@ -158,3 +158,23 @@ void __iomem *generic_ioport_map(unsigned long addr, unsigned int size) void generic_ioport_unmap(void __iomem *addr) { } + +#ifndef CONFIG_GENERIC_IOMAP +void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + void __iomem *ret; + + ret = __ioport_map_trapped(port, nr); + if (ret) + return ret; + + return __ioport_map(port, nr); +} +EXPORT_SYMBOL(ioport_map); + +void ioport_unmap(void __iomem *addr) +{ + sh_mv.mv_ioport_unmap(addr); +} +EXPORT_SYMBOL(ioport_unmap); +#endif /* CONFIG_GENERIC_IOMAP */ diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c index 4a8bb4eeb8ad..2947d2bd1291 100644 --- a/arch/sh/kernel/io_trapped.c +++ b/arch/sh/kernel/io_trapped.c @@ -91,10 +91,14 @@ int register_trapped_io(struct trapped_io *tiop) tiop->magic = IO_TRAPPED_MAGIC; INIT_LIST_HEAD(&tiop->list); spin_lock_irq(&trapped_lock); +#ifdef CONFIG_HAS_IOPORT if (flags & IORESOURCE_IO) list_add(&tiop->list, &trapped_io); +#endif +#ifdef CONFIG_HAS_IOMEM if (flags & IORESOURCE_MEM) list_add(&tiop->list, &trapped_mem); +#endif spin_unlock_irq(&trapped_lock); return 0; diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c index 85cfaf916fdc..9f9bb63616ad 100644 --- a/arch/sh/kernel/machvec.c +++ b/arch/sh/kernel/machvec.c @@ -118,6 +118,14 @@ void __init sh_mv_setup(void) sh_mv.mv_##elem = generic_##elem; \ } while (0) +#ifdef CONFIG_HAS_IOPORT + +#ifdef P2SEG + __set_io_port_base(P2SEG); +#else + __set_io_port_base(0); +#endif + mv_set(inb); mv_set(inw); mv_set(inl); mv_set(outb); mv_set(outw); mv_set(outl); @@ -129,16 +137,13 @@ void __init sh_mv_setup(void) mv_set(ioport_map); mv_set(ioport_unmap); + +#endif + mv_set(irq_demux); mv_set(mode_pins); mv_set(mem_init); if (!sh_mv.mv_nr_irqs) sh_mv.mv_nr_irqs = NR_IRQS; - -#ifdef P2SEG - __set_io_port_base(P2SEG); -#else - __set_io_port_base(0); -#endif } -- GitLab From 242239715c8394da16b1dd0d6f3254f99cac10d2 Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Tue, 25 May 2010 20:10:24 +0900 Subject: [PATCH 492/842] sh: mach-sdk7786: conditionally disable PIO support. SDK7786 only supports PIO via the PCI I/O space, so we disable PIO completely for the non-PCI case. Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/boards/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index 938e87d51482..fd6ddeb7d2c3 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig @@ -154,6 +154,7 @@ config SH_SDK7786 bool "SDK7786" depends on CPU_SUBTYPE_SH7786 select SYS_SUPPORTS_PCI + select NO_IOPORT if !PCI help Select SDK7786 if configuring for a Renesas Technology Europe SH7786-65nm board. -- GitLab From 861160bfd097de7dbf3195bbef210e4f787327ab Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Wed, 26 May 2010 15:58:45 +0900 Subject: [PATCH 493/842] sh: PIO disabling for x3proto and urquell. urquell only provides PIO in the PCI case, while the x3proto board never had a working PCIe controller, so it can simply disable it outright. Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/boards/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index fd6ddeb7d2c3..07b35ca2f644 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig @@ -191,6 +191,7 @@ config SH_URQUELL depends on CPU_SUBTYPE_SH7786 select ARCH_REQUIRE_GPIOLIB select SYS_SUPPORTS_PCI + select NO_IOPORT if !PCI config SH_MIGOR bool "Migo-R" @@ -287,6 +288,7 @@ config SH_LBOX_RE2 config SH_X3PROTO bool "SH-X3 Prototype board" depends on CPU_SUBTYPE_SHX3 + select NO_IOPORT if !PCI config SH_MAGIC_PANEL_R2 bool "Magic Panel R2" -- GitLab From 4adc8b71cc142f9a7b44b13b99aab38ba897c56f Mon Sep 17 00:00:00 2001 From: Borislav Petkov <borislav.petkov@amd.com> Date: Tue, 1 Jun 2010 21:04:55 +0200 Subject: [PATCH 494/842] x86, smpboot: Fix cores per node printing on boot Percpu initialization happens now after booting the cores on the machine and this causes them all to be displayed as belonging to node 0: Jun 8 05:57:21 kepek kernel: [ 0.106999] Booting Node 0, Processors #1 #2 #3 #4 #5 #6 #7 #8 #9 #10 #11 #12 #13 #14 #15 #16 #17 #18 #19 #20 #21 #22 #23 Ok. Use early_cpu_to_node() to get the correct node of each core instead. Signed-off-by: Borislav Petkov <borislav.petkov@amd.com> Cc: Mike Travis <travis@sgi.com> LKML-Reference: <20100601190455.GA14237@aftab> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- arch/x86/kernel/smpboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 37462f1ddba5..c4f33b2e77d6 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -686,7 +686,7 @@ static void __cpuinit do_fork_idle(struct work_struct *work) static void __cpuinit announce_cpu(int cpu, int apicid) { static int current_node = -1; - int node = cpu_to_node(cpu); + int node = early_cpu_to_node(cpu); if (system_state == SYSTEM_BOOTING) { if (node != current_node) { -- GitLab From 45fdf00dea92a480a8023c94d1a1aa887dcd3f69 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine <alexandre.bounine@idt.com> Date: Fri, 28 May 2010 13:56:17 -0400 Subject: [PATCH 495/842] of/powerpc: fix 85xx RapidIO device node pointer Fixes bug introduced by commit 61c7a080a5a061c976988fd4b844dfb468dda255 (of: Always use 'struct device.of_node' to get device node pointer) Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- arch/powerpc/sysdev/fsl_rio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index cd37e49e7034..30e1626b2e85 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c @@ -1426,7 +1426,7 @@ int fsl_rio_setup(struct of_device *dev) port->iores.flags = IORESOURCE_MEM; port->iores.name = "rio_io_win"; - priv->pwirq = irq_of_parse_and_map(dev->node, 0); + priv->pwirq = irq_of_parse_and_map(dev->dev.of_node, 0); priv->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2); priv->txirq = irq_of_parse_and_map(dev->dev.of_node, 3); priv->rxirq = irq_of_parse_and_map(dev->dev.of_node, 4); -- GitLab From 83aea945c21c646184a494a32ad5524248b60226 Mon Sep 17 00:00:00 2001 From: Andreas Schwab <schwab@linux-m68k.org> Date: Tue, 1 Jun 2010 05:58:40 +0000 Subject: [PATCH 496/842] powerpc/macio: Don't dereference pointer before null check Signed-off-by: Andreas Schwab <schwab@linux-m68k.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> --- drivers/macintosh/macio_asic.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 97147804a49c..40390ac01309 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -492,8 +492,8 @@ static void macio_pci_add_devices(struct macio_chip *chip) } /* Add media bay devices if any */ - pnode = mbdev->ofdev.dev.of_node; - if (mbdev) + if (mbdev) { + pnode = mbdev->ofdev.dev.of_node; for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) { if (macio_skip_device(np)) continue; @@ -502,10 +502,11 @@ static void macio_pci_add_devices(struct macio_chip *chip) mbdev, root_res) == NULL) of_node_put(np); } + } /* Add serial ports if any */ - pnode = sdev->ofdev.dev.of_node; if (sdev) { + pnode = sdev->ofdev.dev.of_node; for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) { if (macio_skip_device(np)) continue; -- GitLab From db97bc7f9997fef41b24c91f61c2f776d32d7ce3 Mon Sep 17 00:00:00 2001 From: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Date: Thu, 27 May 2010 19:19:20 +0000 Subject: [PATCH 497/842] powerpc/kprobes: Remove resume_execution() in kprobes emulate_step() in kprobe_handler() would've already determined if the probed instruction can be emulated. We single-step in hardware only if the instruction couldn't be emulated. resume_execution() therefore is superfluous -- all we need is to fix up the instruction pointer after single-stepping. Thanks to Paul Mackerras for catching this. Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> --- arch/powerpc/kernel/kprobes.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index c533525ca56a..bc47352deb1f 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -378,17 +378,6 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, * single-stepped a copy of the instruction. The address of this * copy is p->ainsn.insn. */ -static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) -{ - int ret; - unsigned int insn = *p->ainsn.insn; - - regs->nip = (unsigned long)p->addr; - ret = emulate_step(regs, insn); - if (ret == 0) - regs->nip = (unsigned long)p->addr + 4; -} - static int __kprobes post_kprobe_handler(struct pt_regs *regs) { struct kprobe *cur = kprobe_running(); @@ -406,7 +395,8 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) cur->post_handler(cur, regs, 0); } - resume_execution(cur, regs); + /* Adjust nip to after the single-stepped instruction */ + regs->nip = (unsigned long)cur->addr + 4; regs->msr |= kcb->kprobe_saved_msr; /*Restore back the original saved kprobes variables and continue. */ -- GitLab From 257d569821165a76fb4c91d74909c2e61fe41e46 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov <dkirjanov@hera.kernel.org> Date: Thu, 27 May 2010 04:19:52 +0000 Subject: [PATCH 498/842] powerpc/cell: Fix integer constant warning Fix smatch warning: warning: constant 0x800000000 is so big it is long Signed-off-by: Denis Kirjanov <dkirjanov@kernel.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> --- arch/powerpc/platforms/cell/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 22667a09d40e..4326b737d913 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -1066,7 +1066,7 @@ static int __init cell_iommu_fixed_mapping_init(void) fbase = _ALIGN_UP(fbase, 1 << IO_SEGMENT_SHIFT); fsize = lmb_phys_mem_size(); - if ((fbase + fsize) <= 0x800000000) + if ((fbase + fsize) <= 0x800000000ul) hbase = 0; /* use the device tree window */ else { /* If we're over 32 GB we need to cheat. We can't map all of -- GitLab From 92e197095e0aa59273decbeaa4b63de58e342355 Mon Sep 17 00:00:00 2001 From: Olof Johansson <olof@lixom.net> Date: Sat, 22 May 2010 05:17:38 +0000 Subject: [PATCH 499/842] powerpc/pasemi: Update MAINTAINERS file PWRficient platform work is definitely in maintenance mode these days, update MAINTAINERS file to reflect reality. Website is long gone as well. Signed-off-by: Olof Johansson <olof@lixom.net> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 2652ebc5ab40..a73dd8030afa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3503,9 +3503,8 @@ F: arch/powerpc/platforms/83xx/ LINUX FOR POWERPC PA SEMI PWRFICIENT M: Olof Johansson <olof@lixom.net> -W: http://www.pasemi.com/ L: linuxppc-dev@ozlabs.org -S: Supported +S: Maintained F: arch/powerpc/platforms/pasemi/ F: drivers/*/*pasemi* F: drivers/*/*/*pasemi* -- GitLab From 79905ad50bcf025deb81382413719ed600734941 Mon Sep 17 00:00:00 2001 From: Paul Mackerras <paulus@samba.org> Date: Tue, 1 Jun 2010 19:33:08 +0000 Subject: [PATCH 500/842] agp/uninorth: Fix oops caused by flushing too much This fixes a sporadic oops at boot on G5 Power Macs. The table_end variable has the address of the last byte of the table. Adding on PAGE_SIZE means we flush too much, and if the page after the table is not mapped for any reason, the kernel will oops. Instead we add on 1 because flush_dcache_range() interprets its second argument as the first byte past the range to be flushed. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> --- drivers/char/agp/uninorth-agp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 95db71360d24..f845a8f718b3 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -415,7 +415,7 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge) bridge->gatt_table_real = (u32 *) table; /* Need to clear out any dirty data still sitting in caches */ flush_dcache_range((unsigned long)table, - (unsigned long)(table_end + PAGE_SIZE)); + (unsigned long)table_end + 1); bridge->gatt_table = vmap(pages, (1 << page_order), 0, PAGE_KERNEL_NCG); if (bridge->gatt_table == NULL) -- GitLab From c2cdf6aba0dfcfb54be646ab630c1bccd180e890 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: Wed, 2 Jun 2010 17:09:18 +1000 Subject: [PATCH 501/842] powerpc/macio: Fix probing of macio devices by using the right of match table Grant patches added an of mach table to struct device_driver. However, while he changed the macio device code to use that, he left the match table pointer in struct macio_driver and didn't update drivers to use the "new" one, thus breaking the probing. This completes the change by moving all drivers to setup the "new" one, removing all traces of the old one, and while at it (since it changes the exact same locations), I also remove two other duplicates from struct driver which are the name and owner fields. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> --- arch/powerpc/include/asm/macio.h | 4 ---- drivers/ata/pata_macio.c | 10 +++++----- drivers/block/swim3.c | 6 ++++-- drivers/ide/pmac.c | 7 +++++-- drivers/macintosh/macio_asic.c | 1 - drivers/macintosh/mediabay.c | 6 ++++-- drivers/macintosh/rack-meter.c | 8 +++++--- drivers/net/bmac.c | 7 +++++-- drivers/net/mace.c | 7 +++++-- drivers/net/wireless/orinoco/airport.c | 7 +++++-- drivers/scsi/mac53c94.c | 7 +++++-- drivers/scsi/mesh.c | 7 +++++-- drivers/serial/pmac_zilog.c | 7 +++++-- sound/aoa/soundbus/i2sbus/core.c | 8 +++++--- 14 files changed, 58 insertions(+), 34 deletions(-) diff --git a/arch/powerpc/include/asm/macio.h b/arch/powerpc/include/asm/macio.h index 19a661b4cb98..675e159b5ef4 100644 --- a/arch/powerpc/include/asm/macio.h +++ b/arch/powerpc/include/asm/macio.h @@ -123,10 +123,6 @@ static inline struct pci_dev *macio_get_pci_dev(struct macio_dev *mdev) */ struct macio_driver { - char *name; - struct of_device_id *match_table; - struct module *owner; - int (*probe)(struct macio_dev* dev, const struct of_device_id *match); int (*remove)(struct macio_dev* dev); diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c index 76640ac76888..75b49d01780b 100644 --- a/drivers/ata/pata_macio.c +++ b/drivers/ata/pata_macio.c @@ -1355,8 +1355,11 @@ static struct of_device_id pata_macio_match[] = static struct macio_driver pata_macio_driver = { - .name = "pata-macio", - .match_table = pata_macio_match, + .driver = { + .name = "pata-macio", + .owner = THIS_MODULE, + .of_match_table = pata_macio_match, + }, .probe = pata_macio_attach, .remove = pata_macio_detach, #ifdef CONFIG_PM @@ -1366,9 +1369,6 @@ static struct macio_driver pata_macio_driver = #ifdef CONFIG_PMAC_MEDIABAY .mediabay_event = pata_macio_mb_event, #endif - .driver = { - .owner = THIS_MODULE, - }, }; static const struct pci_device_id pata_macio_pci_match[] = { diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 52f2d11bc7b9..ed6fb91123ab 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -1159,8 +1159,10 @@ static struct of_device_id swim3_match[] = static struct macio_driver swim3_driver = { - .name = "swim3", - .match_table = swim3_match, + .driver = { + .name = "swim3", + .of_match_table = swim3_match, + }, .probe = swim3_attach, #if 0 .suspend = swim3_suspend, diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c index 183fa38760d8..ebcf8e470a97 100644 --- a/drivers/ide/pmac.c +++ b/drivers/ide/pmac.c @@ -1400,8 +1400,11 @@ static struct of_device_id pmac_ide_macio_match[] = static struct macio_driver pmac_ide_macio_driver = { - .name = "ide-pmac", - .match_table = pmac_ide_macio_match, + .driver = { + .name = "ide-pmac", + .owner = THIS_MODULE, + .of_match_table = pmac_ide_macio_match, + }, .probe = pmac_ide_macio_attach, .suspend = pmac_ide_macio_suspend, .resume = pmac_ide_macio_resume, diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 40390ac01309..b6e7ddc09d76 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -526,7 +526,6 @@ static void macio_pci_add_devices(struct macio_chip *chip) int macio_register_driver(struct macio_driver *drv) { /* initialize common driver fields */ - drv->driver.name = drv->name; drv->driver.bus = &macio_bus_type; /* register with core */ diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 288acce76b74..2fd435bc542e 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -728,8 +728,10 @@ static struct of_device_id media_bay_match[] = static struct macio_driver media_bay_driver = { - .name = "media-bay", - .match_table = media_bay_match, + .driver = { + .name = "media-bay", + .of_match_table = media_bay_match, + }, .probe = media_bay_attach, .suspend = media_bay_suspend, .resume = media_bay_resume diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index 12946c5f583f..53cce3a5da23 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -584,9 +584,11 @@ static struct of_device_id rackmeter_match[] = { }; static struct macio_driver rackmeter_driver = { - .name = "rackmeter", - .owner = THIS_MODULE, - .match_table = rackmeter_match, + .driver = { + .name = "rackmeter", + .owner = THIS_MODULE, + .of_match_table = rackmeter_match, + }, .probe = rackmeter_probe, .remove = __devexit_p(rackmeter_remove), .shutdown = rackmeter_shutdown, diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 39250b2ca886..959add2410bf 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1654,8 +1654,11 @@ MODULE_DEVICE_TABLE (of, bmac_match); static struct macio_driver bmac_driver = { - .name = "bmac", - .match_table = bmac_match, + .driver = { + .name = "bmac", + .owner = THIS_MODULE, + .of_match_table = bmac_match, + }, .probe = bmac_probe, .remove = bmac_remove, #ifdef CONFIG_PM diff --git a/drivers/net/mace.c b/drivers/net/mace.c index b6855a6476f8..1c5221f79d6f 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -997,8 +997,11 @@ MODULE_DEVICE_TABLE (of, mace_match); static struct macio_driver mace_driver = { - .name = "mace", - .match_table = mace_match, + .driver = { + .name = "mace", + .owner = THIS_MODULE, + .of_match_table = mace_match, + }, .probe = mace_probe, .remove = mace_remove, }; diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c index 9bcee10c9308..4a0a0e5265c9 100644 --- a/drivers/net/wireless/orinoco/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -239,8 +239,11 @@ static struct of_device_id airport_match[] = MODULE_DEVICE_TABLE(of, airport_match); static struct macio_driver airport_driver = { - .name = DRIVER_NAME, - .match_table = airport_match, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = airport_match, + }, .probe = airport_attach, .remove = airport_detach, .suspend = airport_suspend, diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 18735b39b3d3..3ddb4dc62d5d 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -542,8 +542,11 @@ MODULE_DEVICE_TABLE (of, mac53c94_match); static struct macio_driver mac53c94_driver = { - .name = "mac53c94", - .match_table = mac53c94_match, + .driver = { + .name = "mac53c94", + .owner = THIS_MODULE, + .of_match_table = mac53c94_match, + }, .probe = mac53c94_probe, .remove = mac53c94_remove, }; diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index a1c97e88068a..1f784fde2510 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -2036,8 +2036,11 @@ MODULE_DEVICE_TABLE (of, mesh_match); static struct macio_driver mesh_driver = { - .name = "mesh", - .match_table = mesh_match, + .driver = { + .name = "mesh", + .owner = THIS_MODULE, + .of_match_table = mesh_match, + }, .probe = mesh_probe, .remove = mesh_remove, .shutdown = mesh_shutdown, diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index cabbdc7ba583..5b9cde79e4ea 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -2005,8 +2005,11 @@ static struct of_device_id pmz_match[] = MODULE_DEVICE_TABLE (of, pmz_match); static struct macio_driver pmz_driver = { - .name = "pmac_zilog", - .match_table = pmz_match, + .driver = { + .name = "pmac_zilog", + .owner = THIS_MODULE, + .of_match_table = pmz_match, + }, .probe = pmz_attach, .remove = pmz_detach, .suspend = pmz_suspend, diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 678933721735..3ff8cc5f487a 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -437,9 +437,11 @@ static int i2sbus_shutdown(struct macio_dev* dev) } static struct macio_driver i2sbus_drv = { - .name = "soundbus-i2s", - .owner = THIS_MODULE, - .match_table = i2sbus_match, + .driver = { + .name = "soundbus-i2s", + .owner = THIS_MODULE, + .of_match_table = i2sbus_match, + }, .probe = i2sbus_probe, .remove = i2sbus_remove, #ifdef CONFIG_PM -- GitLab From 66f49121ffa41a19c59965b31b046d8368fec3c7 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Mon, 31 May 2010 21:45:48 +0000 Subject: [PATCH 502/842] clocksource: sh_tmu: compute mult and shift before registration Since commit 98962465ed9e6ea99c38e0af63fe1dcb5a79dc25 ("nohz: Prevent clocksource wrapping during idle"), the CPU of an R2D board never goes to idle. This commit assumes that mult and shift are assigned before the clocksource is registered. As a consequence the safe maximum sleep time is negative and the CPU never goes into idle. This patch fixes the problem by moving mult and shift initialization from sh_tmu_clocksource_enable() to sh_tmu_register_clocksource(). Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> Cc: stable@kernel.org Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- drivers/clocksource/sh_tmu.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 8e44e14ec4c2..de715901b82a 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -199,16 +199,8 @@ static cycle_t sh_tmu_clocksource_read(struct clocksource *cs) static int sh_tmu_clocksource_enable(struct clocksource *cs) { struct sh_tmu_priv *p = cs_to_sh_tmu(cs); - int ret; - - ret = sh_tmu_enable(p); - if (ret) - return ret; - /* TODO: calculate good shift from rate and counter bit width */ - cs->shift = 10; - cs->mult = clocksource_hz2mult(p->rate, cs->shift); - return 0; + return sh_tmu_enable(p); } static void sh_tmu_clocksource_disable(struct clocksource *cs) @@ -228,6 +220,16 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, cs->disable = sh_tmu_clocksource_disable; cs->mask = CLOCKSOURCE_MASK(32); cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; + + /* clk_get_rate() needs an enabled clock */ + clk_enable(p->clk); + /* channel will be configured at parent clock / 4 */ + p->rate = clk_get_rate(p->clk) / 4; + clk_disable(p->clk); + /* TODO: calculate good shift from rate and counter bit width */ + cs->shift = 10; + cs->mult = clocksource_hz2mult(p->rate, cs->shift); + dev_info(&p->pdev->dev, "used as clock source\n"); clocksource_register(cs); return 0; -- GitLab From f4d7c3565c1692c54d9152b52090fe73f0029e37 Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Wed, 2 Jun 2010 17:10:44 +0900 Subject: [PATCH 503/842] clocksource: sh_cmt: compute mult and shift before registration Based on the sh_tmu change in 66f49121ffa41a19c59965b31b046d8368fec3c7 ("clocksource: sh_tmu: compute mult and shift before registration"). The same issues impact the sh_cmt driver, so we take the same approach here. Cc: stable@kernel.org Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- drivers/clocksource/sh_cmt.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index f6677cb19789..f3d3898898ed 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -412,18 +412,10 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs) static int sh_cmt_clocksource_enable(struct clocksource *cs) { struct sh_cmt_priv *p = cs_to_sh_cmt(cs); - int ret; p->total_cycles = 0; - ret = sh_cmt_start(p, FLAG_CLOCKSOURCE); - if (ret) - return ret; - - /* TODO: calculate good shift from rate and counter bit width */ - cs->shift = 0; - cs->mult = clocksource_hz2mult(p->rate, cs->shift); - return 0; + return sh_cmt_start(p, FLAG_CLOCKSOURCE); } static void sh_cmt_clocksource_disable(struct clocksource *cs) @@ -450,8 +442,20 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p, cs->resume = sh_cmt_clocksource_resume; cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; + + /* clk_get_rate() needs an enabled clock */ + clk_enable(p->clk); + p->rate = clk_get_rate(p->clk) / (p->width == 16) ? 512 : 8; + clk_disable(p->clk); + + /* TODO: calculate good shift from rate and counter bit width */ + cs->shift = 10; + cs->mult = clocksource_hz2mult(p->rate, cs->shift); + dev_info(&p->pdev->dev, "used as clock source\n"); + clocksource_register(cs); + return 0; } -- GitLab From f4cdd757bef262a16188fa89141cc243a9cfc81b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Date: Wed, 2 Jun 2010 00:27:26 +0000 Subject: [PATCH 504/842] sh: make sure static declaration on mach-ap325rxa Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/boards/mach-ap325rxa/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 57e37e284208..3a170bd3f3d0 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -328,7 +328,7 @@ static struct soc_camera_platform_info camera_info = { .set_capture = camera_set_capture, }; -struct soc_camera_link camera_link = { +static struct soc_camera_link camera_link = { .bus_id = 0, .add_device = ap325rxa_camera_add, .del_device = ap325rxa_camera_del, -- GitLab From 3ce0933437763f692c669d07d1b7b016b9e2fa41 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Date: Wed, 2 Jun 2010 00:27:31 +0000 Subject: [PATCH 505/842] sh: make sure static declaration on mach-ecovec24 Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/boards/mach-ecovec24/setup.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 778eb7cb9873..be1d114d3a43 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -140,7 +140,7 @@ static struct resource sh_eth_resources[] = { }, }; -struct sh_eth_plat_data sh_eth_plat = { +static struct sh_eth_plat_data sh_eth_plat = { .phy = 0x1f, /* SMSC LAN8700 */ .edmac_endian = EDMAC_LITTLE_ENDIAN, .ether_link_active_low = 1 @@ -160,7 +160,7 @@ static struct platform_device sh_eth_device = { }; /* USB0 host */ -void usb0_port_power(int port, int power) +static void usb0_port_power(int port, int power) { gpio_set_value(GPIO_PTB4, power); } @@ -196,7 +196,7 @@ static struct platform_device usb0_host_device = { }; /* USB1 host/function */ -void usb1_port_power(int port, int power) +static void usb1_port_power(int port, int power) { gpio_set_value(GPIO_PTB5, power); } @@ -422,7 +422,7 @@ static int ts_init(void) return 0; } -struct tsc2007_platform_data tsc2007_info = { +static struct tsc2007_platform_data tsc2007_info = { .model = 2007, .x_plate_ohms = 180, .get_pendown_state = ts_get_pendown_state, @@ -723,7 +723,7 @@ static struct clk fsimckb_clk = { .rate = 0, /* unknown */ }; -struct sh_fsi_platform_info fsi_info = { +static struct sh_fsi_platform_info fsi_info = { .portb_flags = SH_FSI_BRS_INV | SH_FSI_OUT_SLAVE_MODE | SH_FSI_IN_SLAVE_MODE | @@ -780,7 +780,7 @@ static struct platform_device irda_device = { #include <media/ak881x.h> #include <media/sh_vou.h> -struct ak881x_pdata ak881x_pdata = { +static struct ak881x_pdata ak881x_pdata = { .flags = AK881X_IF_MODE_SLAVE, }; @@ -789,7 +789,7 @@ static struct i2c_board_info ak8813 = { .platform_data = &ak881x_pdata, }; -struct sh_vou_pdata sh_vou_pdata = { +static struct sh_vou_pdata sh_vou_pdata = { .bus_fmt = SH_VOU_BUS_8BIT, .flags = SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW, .board_info = &ak8813, @@ -853,7 +853,7 @@ static struct resource sh_mmcif_resources[] = { }, }; -struct sh_mmcif_plat_data sh_mmcif_plat = { +static struct sh_mmcif_plat_data sh_mmcif_plat = { .set_pwr = mmcif_set_pwr, .down_pwr = mmcif_down_pwr, .sup_pclk = 0, /* SH7724: Max Pclk/2 */ -- GitLab From 30e0cc1ae0ca961de2764f584021c90d774d1063 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Date: Wed, 2 Jun 2010 00:27:46 +0000 Subject: [PATCH 506/842] sh: make sure static declaration on mach-migor Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/boards/mach-migor/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 87185de20446..662debe4ead2 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -181,7 +181,7 @@ static int migor_nand_flash_ready(struct mtd_info *mtd) return gpio_get_value(GPIO_PTA1); /* NAND_RBn */ } -struct platform_nand_data migor_nand_flash_data = { +static struct platform_nand_data migor_nand_flash_data = { .chip = { .nr_chips = 1, .partitions = migor_nand_flash_partitions, -- GitLab From 560526f1617acca62b645c81fb43923954d4ddc5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Date: Wed, 2 Jun 2010 00:27:38 +0000 Subject: [PATCH 507/842] sh: make sure static declaration on ms7724se Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- arch/sh/boards/mach-se/7724/setup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index f9b82546c2df..552ebd9ba82b 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -283,7 +283,7 @@ static struct clk fsimcka_clk = { }; /* change J20, J21, J22 pin to 1-2 connection to use slave mode */ -struct sh_fsi_platform_info fsi_info = { +static struct sh_fsi_platform_info fsi_info = { .porta_flags = SH_FSI_BRS_INV | SH_FSI_OUT_SLAVE_MODE | SH_FSI_IN_SLAVE_MODE | @@ -371,7 +371,7 @@ static struct resource sh_eth_resources[] = { }, }; -struct sh_eth_plat_data sh_eth_plat = { +static struct sh_eth_plat_data sh_eth_plat = { .phy = 0x1f, /* SMSC LAN8187 */ .edmac_endian = EDMAC_LITTLE_ENDIAN, }; @@ -535,7 +535,7 @@ static struct platform_device irda_device = { #include <media/ak881x.h> #include <media/sh_vou.h> -struct ak881x_pdata ak881x_pdata = { +static struct ak881x_pdata ak881x_pdata = { .flags = AK881X_IF_MODE_SLAVE, }; @@ -545,7 +545,7 @@ static struct i2c_board_info ak8813 = { .platform_data = &ak881x_pdata, }; -struct sh_vou_pdata sh_vou_pdata = { +static struct sh_vou_pdata sh_vou_pdata = { .bus_fmt = SH_VOU_BUS_8BIT, .flags = SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW, .board_info = &ak8813, -- GitLab From ac422f9443191e050c16fe99baeb5c3d74934589 Mon Sep 17 00:00:00 2001 From: Paul Mundt <lethal@linux-sh.org> Date: Wed, 2 Jun 2010 18:10:00 +0900 Subject: [PATCH 508/842] sh: Make intc messages consistent via pr_fmt. Wrapping pr_fmt to the KBUILD_MODNAME prefix seems to be the trendy thing to do these days, so just do that instead of manually tidying up the stragglers. Signed-off-by: Paul Mundt <lethal@linux-sh.org> --- drivers/sh/intc.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index c585574b9aed..e91a23e5ffd8 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c @@ -16,6 +16,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/init.h> #include <linux/irq.h> #include <linux/module.h> @@ -855,8 +857,8 @@ static void __init intc_register_irq(struct intc_desc *desc, primary = 1; if (!data[0] && !data[1]) - pr_warning("intc: missing unique irq mask for " - "irq %d (vect 0x%04x)\n", irq, irq2evt(irq)); + pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n", + irq, irq2evt(irq)); data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1); data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1); @@ -952,7 +954,7 @@ int __init register_intc_controller(struct intc_desc *desc) struct intc_desc_int *d; struct resource *res; - pr_info("intc: Registered controller '%s' with %u IRQs\n", + pr_info("Registered controller '%s' with %u IRQs\n", desc->name, hw->nr_vectors); d = kzalloc(sizeof(*d), GFP_NOWAIT); @@ -1148,7 +1150,7 @@ int register_intc_userimask(unsigned long addr) if (unlikely(!uimask)) return -ENOMEM; - pr_info("intc: userimask support registered for levels 0 -> %d\n", + pr_info("userimask support registered for levels 0 -> %d\n", default_prio_level - 1); return 0; @@ -1286,7 +1288,7 @@ static int __init register_intc_sysdevs(void) } if (error) - pr_err("intc: sysdev registration error\n"); + pr_err("sysdev registration error\n"); return error; } -- GitLab From fafeeb6c80e3842c6dc19d05de09a23f23eef0d8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Tue, 1 Jun 2010 10:04:49 +0000 Subject: [PATCH 509/842] xfrm: force a dst reference in __xfrm_route_forward() Packets going through __xfrm_route_forward() have a not refcounted dst entry, since we enabled a noref forwarding path. xfrm_lookup() might incorrectly release this dst entry. It's a bit late to make invasive changes in xfrm_lookup(), so lets force a refcount in this path. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/xfrm/xfrm_policy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d965a2bad8d3..4bf27d901333 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2153,6 +2153,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) return 0; } + skb_dst_force(skb); dst = skb_dst(skb); res = xfrm_lookup(net, &dst, &fl, NULL, 0) == 0; -- GitLab From f048fa9c8686119c3858a463cab6121dced7c0bf Mon Sep 17 00:00:00 2001 From: Michael Chan <mchan@broadcom.com> Date: Tue, 1 Jun 2010 15:05:36 +0000 Subject: [PATCH 510/842] bnx2: Fix hang during rmmod bnx2. The regression is caused by: commit 4327ba435a56ada13eedf3eb332e583c7a0586a9 bnx2: Fix netpoll crash. If ->open() and ->close() are called multiple times, the same napi structs will be added to dev->napi_list multiple times, corrupting the dev->napi_list. This causes free_netdev() to hang during rmmod. We fix this by calling netif_napi_del() during ->close(). Also, bnx2_init_napi() must not be in the __devinit section since it is called by ->open(). Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: Benjamin Li <benli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/bnx2.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 188e356c30a3..949d7a9dcf92 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -247,6 +247,7 @@ static const struct flash_spec flash_5709 = { MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); static void bnx2_init_napi(struct bnx2 *bp); +static void bnx2_del_napi(struct bnx2 *bp); static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr) { @@ -6270,6 +6271,7 @@ open_err: bnx2_free_skbs(bp); bnx2_free_irq(bp); bnx2_free_mem(bp); + bnx2_del_napi(bp); return rc; } @@ -6537,6 +6539,7 @@ bnx2_close(struct net_device *dev) bnx2_free_irq(bp); bnx2_free_skbs(bp); bnx2_free_mem(bp); + bnx2_del_napi(bp); bp->link_up = 0; netif_carrier_off(bp->dev); bnx2_set_power_state(bp, PCI_D3hot); @@ -8227,7 +8230,16 @@ bnx2_bus_string(struct bnx2 *bp, char *str) return str; } -static void __devinit +static void +bnx2_del_napi(struct bnx2 *bp) +{ + int i; + + for (i = 0; i < bp->irq_nvecs; i++) + netif_napi_del(&bp->bnx2_napi[i].napi); +} + +static void bnx2_init_napi(struct bnx2 *bp) { int i; -- GitLab From 08f382ebb8a9efb898840aa74cf55148c7a98af6 Mon Sep 17 00:00:00 2001 From: Scott Feldman <scofeldm@cisco.com> Date: Tue, 1 Jun 2010 08:59:33 +0000 Subject: [PATCH 511/842] enic: bug fix: make the set/get netlink VF_PORT support symmetrical To make get/set netlink VF_PORT truly symmetrical, we need to keep track of what items are set and only return those items on get. Previously, the driver wasn't differentiating between a set of attr with a NULL string, for example, and not setting the attr at all. We only want to return the NULL string if the attr was actually set with a NULL string. Otherwise, don't return the attr. Signed-off-by: Scott Feldman <scofeldm@cisco.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/enic/enic.h | 7 ++ drivers/net/enic/enic_main.c | 200 +++++++++++++++++------------------ 2 files changed, 104 insertions(+), 103 deletions(-) diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 85f2a2e7030a..45e86d1e5b1b 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -74,7 +74,14 @@ struct enic_msix_entry { void *devid; }; +#define ENIC_SET_APPLIED (1 << 0) +#define ENIC_SET_REQUEST (1 << 1) +#define ENIC_SET_NAME (1 << 2) +#define ENIC_SET_INSTANCE (1 << 3) +#define ENIC_SET_HOST (1 << 4) + struct enic_port_profile { + u32 set; u8 request; char name[PORT_PROFILE_MAX]; u8 instance_uuid[PORT_UUID_MAX]; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 6586b5c7e4b6..bc7d6b96de3d 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1029,8 +1029,7 @@ static int enic_dev_init_done(struct enic *enic, int *done, int *error) return err; } -static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac, - char *name, u8 *instance_uuid, u8 *host_uuid) +static int enic_set_port_profile(struct enic *enic, u8 *mac) { struct vic_provinfo *vp; u8 oui[3] = VIC_PROVINFO_CISCO_OUI; @@ -1040,97 +1039,112 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac, "%02X%02X-%02X%02X%02X%02X%0X%02X"; int err; - if (!name) - return -EINVAL; + err = enic_vnic_dev_deinit(enic); + if (err) + return err; - if (!is_valid_ether_addr(mac)) - return -EADDRNOTAVAIL; + switch (enic->pp.request) { - vp = vic_provinfo_alloc(GFP_KERNEL, oui, VIC_PROVINFO_LINUX_TYPE); - if (!vp) - return -ENOMEM; + case PORT_REQUEST_ASSOCIATE: - vic_provinfo_add_tlv(vp, - VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR, - strlen(name) + 1, name); - - vic_provinfo_add_tlv(vp, - VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR, - ETH_ALEN, mac); - - if (instance_uuid) { - uuid = instance_uuid; - sprintf(uuid_str, uuid_fmt, - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]); - vic_provinfo_add_tlv(vp, - VIC_LINUX_PROV_TLV_CLIENT_UUID_STR, - sizeof(uuid_str), uuid_str); - } + if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) + return -EINVAL; - if (host_uuid) { - uuid = host_uuid; - sprintf(uuid_str, uuid_fmt, - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]); - vic_provinfo_add_tlv(vp, - VIC_LINUX_PROV_TLV_HOST_UUID_STR, - sizeof(uuid_str), uuid_str); - } + if (!is_valid_ether_addr(mac)) + return -EADDRNOTAVAIL; - err = enic_vnic_dev_deinit(enic); - if (err) - goto err_out; + vp = vic_provinfo_alloc(GFP_KERNEL, oui, + VIC_PROVINFO_LINUX_TYPE); + if (!vp) + return -ENOMEM; - memset(&enic->pp, 0, sizeof(enic->pp)); + vic_provinfo_add_tlv(vp, + VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR, + strlen(enic->pp.name) + 1, enic->pp.name); - err = enic_dev_init_prov(enic, vp); - if (err) - goto err_out; + vic_provinfo_add_tlv(vp, + VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR, + ETH_ALEN, mac); + + if (enic->pp.set & ENIC_SET_INSTANCE) { + uuid = enic->pp.instance_uuid; + sprintf(uuid_str, uuid_fmt, + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + vic_provinfo_add_tlv(vp, + VIC_LINUX_PROV_TLV_CLIENT_UUID_STR, + sizeof(uuid_str), uuid_str); + } - enic->pp.request = request; - memcpy(enic->pp.name, name, PORT_PROFILE_MAX); - if (instance_uuid) - memcpy(enic->pp.instance_uuid, - instance_uuid, PORT_UUID_MAX); - if (host_uuid) - memcpy(enic->pp.host_uuid, - host_uuid, PORT_UUID_MAX); + if (enic->pp.set & ENIC_SET_HOST) { + uuid = enic->pp.host_uuid; + sprintf(uuid_str, uuid_fmt, + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + vic_provinfo_add_tlv(vp, + VIC_LINUX_PROV_TLV_HOST_UUID_STR, + sizeof(uuid_str), uuid_str); + } -err_out: - vic_provinfo_free(vp); + err = enic_dev_init_prov(enic, vp); + vic_provinfo_free(vp); + if (err) + return err; + break; - return err; -} + case PORT_REQUEST_DISASSOCIATE: + break; -static int enic_unset_port_profile(struct enic *enic) -{ - memset(&enic->pp, 0, sizeof(enic->pp)); - return enic_vnic_dev_deinit(enic); + default: + return -EINVAL; + } + + enic->pp.set |= ENIC_SET_APPLIED; + return 0; } static int enic_set_vf_port(struct net_device *netdev, int vf, struct nlattr *port[]) { struct enic *enic = netdev_priv(netdev); - char *name = NULL; - u8 *instance_uuid = NULL; - u8 *host_uuid = NULL; - u8 request = PORT_REQUEST_DISASSOCIATE; + + memset(&enic->pp, 0, sizeof(enic->pp)); + + if (port[IFLA_PORT_REQUEST]) { + enic->pp.set |= ENIC_SET_REQUEST; + enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); + } + + if (port[IFLA_PORT_PROFILE]) { + enic->pp.set |= ENIC_SET_NAME; + memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]), + PORT_PROFILE_MAX); + } + + if (port[IFLA_PORT_INSTANCE_UUID]) { + enic->pp.set |= ENIC_SET_INSTANCE; + memcpy(enic->pp.instance_uuid, + nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX); + } + + if (port[IFLA_PORT_HOST_UUID]) { + enic->pp.set |= ENIC_SET_HOST; + memcpy(enic->pp.host_uuid, + nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX); + } /* don't support VFs, yet */ if (vf != PORT_SELF_VF) return -EOPNOTSUPP; - if (port[IFLA_PORT_REQUEST]) - request = nla_get_u8(port[IFLA_PORT_REQUEST]); + if (!(enic->pp.set & ENIC_SET_REQUEST)) + return -EOPNOTSUPP; - switch (request) { - case PORT_REQUEST_ASSOCIATE: + if (enic->pp.request == PORT_REQUEST_ASSOCIATE) { /* If the interface mac addr hasn't been assigned, * assign a random mac addr before setting port- @@ -1139,30 +1153,9 @@ static int enic_set_vf_port(struct net_device *netdev, int vf, if (is_zero_ether_addr(netdev->dev_addr)) random_ether_addr(netdev->dev_addr); - - if (port[IFLA_PORT_PROFILE]) - name = nla_data(port[IFLA_PORT_PROFILE]); - - if (port[IFLA_PORT_INSTANCE_UUID]) - instance_uuid = - nla_data(port[IFLA_PORT_INSTANCE_UUID]); - - if (port[IFLA_PORT_HOST_UUID]) - host_uuid = nla_data(port[IFLA_PORT_HOST_UUID]); - - return enic_set_port_profile(enic, request, - netdev->dev_addr, name, - instance_uuid, host_uuid); - - case PORT_REQUEST_DISASSOCIATE: - - return enic_unset_port_profile(enic); - - default: - break; } - return -EOPNOTSUPP; + return enic_set_port_profile(enic, netdev->dev_addr); } static int enic_get_vf_port(struct net_device *netdev, int vf, @@ -1172,14 +1165,12 @@ static int enic_get_vf_port(struct net_device *netdev, int vf, int err, error, done; u16 response = PORT_PROFILE_RESPONSE_SUCCESS; - /* don't support VFs, yet */ - if (vf != PORT_SELF_VF) - return -EOPNOTSUPP; + if (!(enic->pp.set & ENIC_SET_APPLIED)) + return -ENODATA; err = enic_dev_init_done(enic, &done, &error); - if (err) - return err; + error = err; switch (error) { case ERR_SUCCESS: @@ -1202,12 +1193,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf, NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request); NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); - NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX, - enic->pp.name); - NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, - enic->pp.instance_uuid); - NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX, - enic->pp.host_uuid); + if (enic->pp.set & ENIC_SET_NAME) + NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX, + enic->pp.name); + if (enic->pp.set & ENIC_SET_INSTANCE) + NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, + enic->pp.instance_uuid); + if (enic->pp.set & ENIC_SET_HOST) + NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX, + enic->pp.host_uuid); return 0; -- GitLab From 21896bc010c17e5ac58951e771496ec2fb1051ed Mon Sep 17 00:00:00 2001 From: Takashi Iwai <tiwai@suse.de> Date: Wed, 2 Jun 2010 12:08:37 +0200 Subject: [PATCH 512/842] ALSA: asihpi - Fix uninitialized variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize prev_ctl properly before reference: sound/pci/asihpi/asihpi.c: In function ‘snd_card_asihpi_mixer_new’: sound/pci/asihpi/asihpi.c:2568:30: warning: ‘prev_ctl.dst_node_index’ may be used uninitialized in this function Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/asihpi/asihpi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index f74c7372b3d1..1db586af4f9c 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -2578,6 +2578,9 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) if (err) return -err; + memset(&prev_ctl, 0, sizeof(prev_ctl)); + prev_ctl.control_type = -1; + for (idx = 0; idx < 2000; idx++) { err = hpi_mixer_get_control_by_index( ss, asihpi->h_mixer, -- GitLab From 194dbcc8a1a97cbac9a619a563e5f6b7f7d5a485 Mon Sep 17 00:00:00 2001 From: John Fastabend <john.r.fastabend@intel.com> Date: Wed, 12 May 2010 21:31:06 +0000 Subject: [PATCH 513/842] net: init_vlan should not copy slave or master flags The vlan device should not copy the slave or master flags from the real device. It is not in the bond until added nor is it a master. Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/8021q/vlan_dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 55be90826f5f..529842677817 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -708,7 +708,8 @@ static int vlan_dev_init(struct net_device *dev) netif_carrier_off(dev); /* IFF_BROADCAST|IFF_MULTICAST; ??? */ - dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI); + dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | + IFF_MASTER | IFF_SLAVE); dev->iflink = real_dev->ifindex; dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))) | -- GitLab From 2df4a0fa1540c460ec69788ab2a901cc72a75644 Mon Sep 17 00:00:00 2001 From: John Fastabend <john.r.fastabend@intel.com> Date: Wed, 12 May 2010 21:31:11 +0000 Subject: [PATCH 514/842] net: fix conflict between null_or_orig and null_or_bond If a skb is received on an inactive bond that does not meet the special cases checked for by skb_bond_should_drop it should only be delivered to exact matches as the comment in netif_receive_skb() says. However because null_or_bond could also be null this is not always true. This patch renames null_or_bond to orig_or_bond and initializes it to orig_dev. This keeps the intent of null_or_bond to pass frames received on VLAN interfaces stacked on bonding interfaces without invalidating the statement for null_or_orig. Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/core/dev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 1845b08c624e..d03470f5260a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2795,7 +2795,7 @@ static int __netif_receive_skb(struct sk_buff *skb) struct net_device *orig_dev; struct net_device *master; struct net_device *null_or_orig; - struct net_device *null_or_bond; + struct net_device *orig_or_bond; int ret = NET_RX_DROP; __be16 type; @@ -2868,10 +2868,10 @@ ncls: * device that may have registered for a specific ptype. The * handler may have to adjust skb->dev and orig_dev. */ - null_or_bond = NULL; + orig_or_bond = orig_dev; if ((skb->dev->priv_flags & IFF_802_1Q_VLAN) && (vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING)) { - null_or_bond = vlan_dev_real_dev(skb->dev); + orig_or_bond = vlan_dev_real_dev(skb->dev); } type = skb->protocol; @@ -2879,7 +2879,7 @@ ncls: &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) { if (ptype->type == type && (ptype->dev == null_or_orig || ptype->dev == skb->dev || ptype->dev == orig_dev || - ptype->dev == null_or_bond)) { + ptype->dev == orig_or_bond)) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype; -- GitLab From edb39935c8b19fcd9a8f619d0bc1e9d04594cd2b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela <perex@perex.cz> Date: Wed, 2 Jun 2010 13:29:17 +0200 Subject: [PATCH 515/842] ALSA: hda-intel - fix wallclk variable update and condition This patch fixes thinko introduced in "last minutes" before commiting of the last wallclk patch. It also fixes the condition checking if the first period after last wallclk update is processed. There is a little rounding error in period_wallclk. Signed-off-by: Jaroslav Kysela <perex@perex.cz> --- sound/pci/hda/hda_intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index dc79564fea30..af701a894687 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1913,11 +1913,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) return -1; /* this shouldn't happen! */ - if (wallclk <= azx_dev->period_wallclk && + if (wallclk < (azx_dev->period_wallclk * 5) / 4 && pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) /* NG - it's below the first next period boundary */ return bdl_pos_adj[chip->dev_index] ? 0 : -1; - azx_dev->start_wallclk = wallclk; + azx_dev->start_wallclk += wallclk; return 1; /* OK, it's fine */ } -- GitLab From ceb3d2394532540a52ce34f71e67c8d008913f79 Mon Sep 17 00:00:00 2001 From: Phil Sutter <phil@nwl.cc> Date: Sat, 29 May 2010 13:23:34 +0000 Subject: [PATCH 516/842] korina: fix deadlock on RX FIFO overrun By calling korina_restart(), the IRQ handler tries to disable the interrupt it's currently serving. This leads to a deadlock since disable_irq() waits for any running IRQ handlers to finish before returning. This patch addresses the issue by turning korina_restart() into a workqueue task, which is then scheduled when needed. Reproducing the deadlock is easily done using e.g. GNU netcat to send large amounts of UDP data to the host running this driver. Note that the same problem (and fix) applies to TX FIFO underruns, but apparently these are less easy to trigger. Signed-off-by: Phil Sutter <phil@nwl.cc> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/korina.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 26bf1b76b997..13533f937e05 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -135,6 +135,7 @@ struct korina_private { struct napi_struct napi; struct timer_list media_check_timer; struct mii_if_info mii_if; + struct work_struct restart_task; struct net_device *dev; int phy_addr; }; @@ -890,12 +891,12 @@ static int korina_init(struct net_device *dev) /* * Restart the RC32434 ethernet controller. - * FIXME: check the return status where we call it */ -static int korina_restart(struct net_device *dev) +static void korina_restart_task(struct work_struct *work) { - struct korina_private *lp = netdev_priv(dev); - int ret; + struct korina_private *lp = container_of(work, + struct korina_private, restart_task); + struct net_device *dev = lp->dev; /* * Disable interrupts @@ -916,10 +917,9 @@ static int korina_restart(struct net_device *dev) napi_disable(&lp->napi); - ret = korina_init(dev); - if (ret < 0) { + if (korina_init(dev) < 0) { printk(KERN_ERR "%s: cannot restart device\n", dev->name); - return ret; + return; } korina_multicast_list(dev); @@ -927,8 +927,6 @@ static int korina_restart(struct net_device *dev) enable_irq(lp->ovr_irq); enable_irq(lp->tx_irq); enable_irq(lp->rx_irq); - - return ret; } static void korina_clear_and_restart(struct net_device *dev, u32 value) @@ -937,7 +935,7 @@ static void korina_clear_and_restart(struct net_device *dev, u32 value) netif_stop_queue(dev); writel(value, &lp->eth_regs->ethintfc); - korina_restart(dev); + schedule_work(&lp->restart_task); } /* Ethernet Tx Underflow interrupt */ @@ -962,11 +960,8 @@ static irqreturn_t korina_und_interrupt(int irq, void *dev_id) static void korina_tx_timeout(struct net_device *dev) { struct korina_private *lp = netdev_priv(dev); - unsigned long flags; - spin_lock_irqsave(&lp->lock, flags); - korina_restart(dev); - spin_unlock_irqrestore(&lp->lock, flags); + schedule_work(&lp->restart_task); } /* Ethernet Rx Overflow interrupt */ @@ -1086,6 +1081,8 @@ static int korina_close(struct net_device *dev) napi_disable(&lp->napi); + cancel_work_sync(&lp->restart_task); + free_irq(lp->rx_irq, dev); free_irq(lp->tx_irq, dev); free_irq(lp->ovr_irq, dev); @@ -1198,6 +1195,8 @@ static int korina_probe(struct platform_device *pdev) } setup_timer(&lp->media_check_timer, korina_poll_media, (unsigned long) dev); + INIT_WORK(&lp->restart_task, korina_restart_task); + printk(KERN_INFO "%s: " DRV_NAME "-" DRV_VERSION " " DRV_RELDATE "\n", dev->name); out: -- GitLab From 53ee490ac5836d506ea5830f821045aafa3c196f Mon Sep 17 00:00:00 2001 From: Phil Sutter <phil@nwl.cc> Date: Sat, 29 May 2010 13:23:35 +0000 Subject: [PATCH 517/842] korina: use netdev_alloc_skb_ip_align() here, too This patch completes commit 89d71a66c40d629e3b1285def543ab1425558cd5 which missed this spot, as it seems. Signed-off-by: Phil Sutter <phil@nwl.cc> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/korina.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 13533f937e05..3e9b6b7be42e 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -765,10 +765,9 @@ static int korina_alloc_ring(struct net_device *dev) /* Initialize the receive descriptors */ for (i = 0; i < KORINA_NUM_RDS; i++) { - skb = dev_alloc_skb(KORINA_RBSIZE + 2); + skb = netdev_alloc_skb_ip_align(dev, KORINA_RBSIZE); if (!skb) return -ENOMEM; - skb_reserve(skb, 2); lp->rx_skb[i] = skb; lp->rd_ring[i].control = DMA_DESC_IOD | DMA_COUNT(KORINA_RBSIZE); -- GitLab From b1011b375be106e0a312baafc981a26165283efe Mon Sep 17 00:00:00 2001 From: Phil Sutter <phil@nwl.cc> Date: Sat, 29 May 2010 13:23:36 +0000 Subject: [PATCH 518/842] korina: count RX DMA OVR as rx_fifo_error This way, RX DMA overruns (actually being caused by overrun of the 512byte input FIFO) show up in ifconfig output. The rx_fifo_errors counter is unused otherwise. Signed-off-by: Phil Sutter <phil@nwl.cc> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/korina.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 3e9b6b7be42e..c7a9bef4dfb0 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -376,7 +376,7 @@ static int korina_rx(struct net_device *dev, int limit) if (devcs & ETH_RX_LE) dev->stats.rx_length_errors++; if (devcs & ETH_RX_OVR) - dev->stats.rx_over_errors++; + dev->stats.rx_fifo_errors++; if (devcs & ETH_RX_CV) dev->stats.rx_frame_errors++; if (devcs & ETH_RX_CES) -- GitLab From e3fe8558c7fc182972c3d947d88744482111f304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20B=C3=A9nard?= <eric@eukrea.com> Date: Wed, 2 Jun 2010 06:13:34 -0700 Subject: [PATCH 519/842] net/fec: fix pm to survive to suspend/resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * in the actual driver, calling fec_stop and fec_enet_init doesn't allow to have a working network interface at resume (where a ifconfig down and up is required to recover the interface) * by using fec_enet_close and fec_enet_open, this patch solves this problem and handle the case where the link changed between suspend and resume * this patch also disable clock at suspend and reenable it at resume Signed-off-by: Eric Bénard <eric@eukrea.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/fec.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/fec.c b/drivers/net/fec.c index ddf7a86cd466..edfff92a6d8e 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1373,10 +1373,9 @@ fec_suspend(struct platform_device *dev, pm_message_t state) if (ndev) { fep = netdev_priv(ndev); - if (netif_running(ndev)) { - netif_device_detach(ndev); - fec_stop(ndev); - } + if (netif_running(ndev)) + fec_enet_close(ndev); + clk_disable(fep->clk); } return 0; } @@ -1385,12 +1384,13 @@ static int fec_resume(struct platform_device *dev) { struct net_device *ndev = platform_get_drvdata(dev); + struct fec_enet_private *fep; if (ndev) { - if (netif_running(ndev)) { - fec_enet_init(ndev, 0); - netif_device_attach(ndev); - } + fep = netdev_priv(ndev); + clk_enable(fep->clk); + if (netif_running(ndev)) + fec_enet_open(ndev); } return 0; } -- GitLab From 33c29dde7d04dc0ec0edb649d20ccf1351c13a06 Mon Sep 17 00:00:00 2001 From: Changli Gao <xiaosuo@gmail.com> Date: Sat, 29 May 2010 14:26:59 +0000 Subject: [PATCH 520/842] act_nat: fix the wrong checksum when addr isn't in old_addr/mask fix the wrong checksum when addr isn't in old_addr/mask For TCP and UDP packets, when addr isn't in old_addr/mask we don't do SNAT or DNAT, and we should not update layer 4 checksum. Signed-off-by: Changli Gao <xiaosuo@gmail.com> ---- net/sched/act_nat.c | 4 ++++ 1 file changed, 4 insertions(+) Signed-off-by: David S. Miller <davem@davemloft.net> --- net/sched/act_nat.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index d885ba311564..570949417f38 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -159,6 +159,9 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, iph->daddr = new_addr; csum_replace4(&iph->check, addr, new_addr); + } else if ((iph->frag_off & htons(IP_OFFSET)) || + iph->protocol != IPPROTO_ICMP) { + goto out; } ihl = iph->ihl * 4; @@ -247,6 +250,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, break; } +out: return action; drop: -- GitLab From cc1fed00c9ba84f38717a6cab84409cd48f340e3 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky <maximlevitsky@gmail.com> Date: Wed, 2 Jun 2010 16:01:45 +0300 Subject: [PATCH 521/842] mtd/r852: register IRQ as last step Otherwise, if it fires right away, it might access uninitialized spinlock Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> --- drivers/mtd/nand/r852.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 78a423295474..20a654a94d30 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -940,18 +940,19 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) r852_dma_test(dev); + dev->irq = pci_dev->irq; + spin_lock_init(&dev->irqlock); + + dev->card_detected = 0; + r852_card_update_present(dev); + /*register irq handler*/ error = -ENODEV; if (request_irq(pci_dev->irq, &r852_irq, IRQF_SHARED, DRV_NAME, dev)) goto error10; - dev->irq = pci_dev->irq; - spin_lock_init(&dev->irqlock); - /* kick initial present test */ - dev->card_detected = 0; - r852_card_update_present(dev); queue_delayed_work(dev->card_workqueue, &dev->card_detect_work, 0); -- GitLab From 9489be8ca234c07666e88a4472e4d5f2a2425aa5 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky <maximlevitsky@gmail.com> Date: Wed, 2 Jun 2010 16:01:46 +0300 Subject: [PATCH 522/842] mtd/r852: Fixes in case of DMA timeout * Don't call complete on dma completion * do a INIT_COMPLETE before using it each time * Report DMA read error via ecc 'correct' I finally managed to make my system do suspend to ram propertly, and I see that if card was inserted during suspend (while system was off), I get dma timeouts on resume. Simple card reinsert solves the issue. This patch solves a crash that would happen otherwise Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> --- drivers/mtd/nand/r852.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 20a654a94d30..3f219e61df7d 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -150,7 +150,6 @@ static void r852_dma_done(struct r852_device *dev, int error) if (dev->phys_dma_addr && dev->phys_dma_addr != dev->phys_bounce_buffer) pci_unmap_single(dev->pci_dev, dev->phys_dma_addr, R852_DMA_LEN, dev->dma_dir ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); - complete(&dev->dma_done); } /* @@ -182,6 +181,7 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read) /* Set dma direction */ dev->dma_dir = do_read; dev->dma_stage = 1; + INIT_COMPLETION(dev->dma_done); dbg_verbose("doing dma %s ", do_read ? "read" : "write"); @@ -494,6 +494,11 @@ int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, if (dev->card_unstable) return 0; + if (dev->dma_error) { + dev->dma_error = 0; + return -1; + } + r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS); ecc_reg = r852_read_reg_dword(dev, R852_DATALINE); r852_write_reg(dev, R852_CTL, dev->ctlreg); @@ -796,6 +801,7 @@ static irqreturn_t r852_irq(int irq, void *data) if (dma_status & R852_DMA_IRQ_ERROR) { dbg("recieved dma error IRQ"); r852_dma_done(dev, -EIO); + complete(&dev->dma_done); goto out; } @@ -825,8 +831,10 @@ static irqreturn_t r852_irq(int irq, void *data) r852_dma_enable(dev); /* Operation done */ - if (dev->dma_stage == 3) + if (dev->dma_stage == 3) { r852_dma_done(dev, 0); + complete(&dev->dma_done); + } goto out; } @@ -1082,7 +1090,7 @@ int r852_resume(struct device *device) dev->card_detected ? "added" : "removed"); queue_delayed_work(dev->card_workqueue, - &dev->card_detect_work, 1000); + &dev->card_detect_work, msecs_to_jiffies(1000)); return 0; } -- GitLab From edafe502404f3669d364b6e96d79b54067b634b4 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera <root@danielinux.net> Date: Wed, 2 Jun 2010 02:02:04 +0000 Subject: [PATCH 523/842] TCP: tcp_hybla: Fix integer overflow in slow start increment For large values of rtt, 2^rho operation may overflow u32. Clamp down the increment to 2^16. Signed-off-by: Daniele Lacamera <root@danielinux.net> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv4/tcp_hybla.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c index c209e054a634..377bc9349371 100644 --- a/net/ipv4/tcp_hybla.c +++ b/net/ipv4/tcp_hybla.c @@ -126,8 +126,8 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) * calculate 2^fract in a <<7 value. */ is_slowstart = 1; - increment = ((1 << ca->rho) * hybla_fraction(rho_fractions)) - - 128; + increment = ((1 << min(ca->rho, 16U)) * + hybla_fraction(rho_fractions)) - 128; } else { /* * congestion avoidance -- GitLab From fbc2e7d9cf49e0bf89b9e91fd60a06851a855c5d Mon Sep 17 00:00:00 2001 From: Changli Gao <xiaosuo@gmail.com> Date: Wed, 2 Jun 2010 07:32:42 -0700 Subject: [PATCH 524/842] cls_u32: use skb_header_pointer() to dereference data safely use skb_header_pointer() to dereference data safely the original skb->data dereference isn't safe, as there isn't any skb->len or skb_is_nonlinear() check. skb_header_pointer() is used instead in this patch. And when the skb isn't long enough, we terminate the function u32_classify() immediately with -1. Signed-off-by: Changli Gao <xiaosuo@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/sched/cls_u32.c | 49 +++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 96275422c619..4f522143811e 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -98,11 +98,11 @@ static int u32_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_re { struct { struct tc_u_knode *knode; - u8 *ptr; + unsigned int off; } stack[TC_U32_MAXDEPTH]; struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root; - u8 *ptr = skb_network_header(skb); + unsigned int off = skb_network_offset(skb); struct tc_u_knode *n; int sdepth = 0; int off2 = 0; @@ -134,8 +134,14 @@ next_knode: #endif for (i = n->sel.nkeys; i>0; i--, key++) { - - if ((*(__be32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) { + unsigned int toff; + __be32 *data, _data; + + toff = off + key->off + (off2 & key->offmask); + data = skb_header_pointer(skb, toff, 4, &_data); + if (!data) + goto out; + if ((*data ^ key->val) & key->mask) { n = n->next; goto next_knode; } @@ -174,29 +180,45 @@ check_terminal: if (sdepth >= TC_U32_MAXDEPTH) goto deadloop; stack[sdepth].knode = n; - stack[sdepth].ptr = ptr; + stack[sdepth].off = off; sdepth++; ht = n->ht_down; sel = 0; - if (ht->divisor) - sel = ht->divisor&u32_hash_fold(*(__be32*)(ptr+n->sel.hoff), &n->sel,n->fshift); - + if (ht->divisor) { + __be32 *data, _data; + + data = skb_header_pointer(skb, off + n->sel.hoff, 4, + &_data); + if (!data) + goto out; + sel = ht->divisor & u32_hash_fold(*data, &n->sel, + n->fshift); + } if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT))) goto next_ht; if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) { off2 = n->sel.off + 3; - if (n->sel.flags&TC_U32_VAROFFSET) - off2 += ntohs(n->sel.offmask & *(__be16*)(ptr+n->sel.offoff)) >>n->sel.offshift; + if (n->sel.flags & TC_U32_VAROFFSET) { + __be16 *data, _data; + + data = skb_header_pointer(skb, + off + n->sel.offoff, + 2, &_data); + if (!data) + goto out; + off2 += ntohs(n->sel.offmask & *data) >> + n->sel.offshift; + } off2 &= ~3; } if (n->sel.flags&TC_U32_EAT) { - ptr += off2; + off += off2; off2 = 0; } - if (ptr < skb_tail_pointer(skb)) + if (off < skb->len) goto next_ht; } @@ -204,9 +226,10 @@ check_terminal: if (sdepth--) { n = stack[sdepth].knode; ht = n->ht_up; - ptr = stack[sdepth].ptr; + off = stack[sdepth].off; goto check_terminal; } +out: return -1; deadloop: -- GitLab From ac373f7e2286ed3690e8a93ebf9f6f1ae0c7d4a9 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky <maximlevitsky@gmail.com> Date: Wed, 2 Jun 2010 16:01:47 +0300 Subject: [PATCH 525/842] mtd/r852: update card detect early. This turns out to be the reason for DMA timeouts on resume, if card was inserted while system was suspended Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> --- drivers/mtd/nand/r852.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 3f219e61df7d..bcfc851fe550 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -712,6 +712,7 @@ void r852_card_detect_work(struct work_struct *work) container_of(work, struct r852_device, card_detect_work.work); r852_card_update_present(dev); + r852_update_card_detect(dev); dev->card_unstable = 0; /* False alarm */ @@ -727,7 +728,6 @@ void r852_card_detect_work(struct work_struct *work) else r852_unregister_nand_device(dev); exit: - /* Update detection logic */ r852_update_card_detect(dev); } -- GitLab From 10389536742cefbedecb67a5b2906f155cf3a1c3 Mon Sep 17 00:00:00 2001 From: Stefan Richter <stefanr@s5r6.in-berlin.de> Date: Sun, 30 May 2010 19:43:52 +0200 Subject: [PATCH 526/842] firewire: core: check for 1394a compliant IRM, fix inaccessibility of Sony camcorder Per IEEE 1394 clause 8.4.2.3, a contender for the IRM role shall check whether the current IRM complies to 1394a-2000 or later. If not force a compliant node (e.g. itself) to become IRM. This was implemented in the older ieee1394 driver but not yet in firewire-core. An older Sony camcorder (Sony DCR-TRV25) which implements 1394-1995 IRM but neither 1394a-2000 IRM nor BM was now found to cause an interoperability bug: - Camcorder becomes root node when plugged in, hence gets IRM role. - firewire-core successfully contends for BM role, proceeds to perform gap count optimization and resets the bus. - Sony camcorder ignores presence of a BM (against the spec, this is a firmware bug), performs its idea of gap count optimization and resets the bus. - Preceding two steps are repeated endlessly, bus never settles, regular I/O is practically impossible. http://thread.gmane.org/gmane.linux.kernel.firewire.user/3913 This is an interoperability regression from the old to the new drivers. Fix it indirectly by adding the 1394a IRM check. The spec suggests three and a half methods to determine 1394a compliance of a remote IRM; we choose the method of testing the Config_ROM.Bus_Info.generation field. This is data that firewire-core should have readily available at this point, i.e. does not require extra I/O. Reported-by: Clemens Ladisch <clemens@ladisch.de> (missing 1394a check) Reported-by: H. S. <hs.samix@gmail.com> (issue with Sony DCR-TRV25) Tested-by: H. S. <hs.samix@gmail.com> Cc: <stable@kernel.org> # .32.x and newer Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> --- drivers/firewire/core-card.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 9dcb30466ec0..371713ff0266 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -231,7 +231,7 @@ void fw_schedule_bm_work(struct fw_card *card, unsigned long delay) static void fw_card_bm_work(struct work_struct *work) { struct fw_card *card = container_of(work, struct fw_card, work.work); - struct fw_device *root_device; + struct fw_device *root_device, *irm_device; struct fw_node *root_node; unsigned long flags; int root_id, new_root_id, irm_id, local_id; @@ -239,6 +239,7 @@ static void fw_card_bm_work(struct work_struct *work) bool do_reset = false; bool root_device_is_running; bool root_device_is_cmc; + bool irm_is_1394_1995_only; spin_lock_irqsave(&card->lock, flags); @@ -248,12 +249,18 @@ static void fw_card_bm_work(struct work_struct *work) } generation = card->generation; + root_node = card->root_node; fw_node_get(root_node); root_device = root_node->data; root_device_is_running = root_device && atomic_read(&root_device->state) == FW_DEVICE_RUNNING; root_device_is_cmc = root_device && root_device->cmc; + + irm_device = card->irm_node->data; + irm_is_1394_1995_only = irm_device && irm_device->config_rom && + (irm_device->config_rom[2] & 0x000000f0) == 0; + root_id = root_node->node_id; irm_id = card->irm_node->node_id; local_id = card->local_node->node_id; @@ -276,8 +283,15 @@ static void fw_card_bm_work(struct work_struct *work) if (!card->irm_node->link_on) { new_root_id = local_id; - fw_notify("IRM has link off, making local node (%02x) root.\n", - new_root_id); + fw_notify("%s, making local node (%02x) root.\n", + "IRM has link off", new_root_id); + goto pick_me; + } + + if (irm_is_1394_1995_only) { + new_root_id = local_id; + fw_notify("%s, making local node (%02x) root.\n", + "IRM is not 1394a compliant", new_root_id); goto pick_me; } @@ -316,8 +330,8 @@ static void fw_card_bm_work(struct work_struct *work) * root, and thus, IRM. */ new_root_id = local_id; - fw_notify("BM lock failed, making local node (%02x) root.\n", - new_root_id); + fw_notify("%s, making local node (%02x) root.\n", + "BM lock failed", new_root_id); goto pick_me; } } else if (card->bm_generation != generation) { -- GitLab From 8b27ff4cf6d15964aa2987aeb58db4dfb1f87a19 Mon Sep 17 00:00:00 2001 From: Tejun Heo <tj@kernel.org> Date: Mon, 31 May 2010 16:26:48 +0200 Subject: [PATCH 527/842] sata_via: magic vt6421 fix for transmission problems w/ WD drives vt6421 has problems talking to recent WD drives. It causes a lot of transmission errors while high bandwidth transfer as reported in the following bugzilla entry. https://bugzilla.kernel.org/show_bug.cgi?id=15173 Joseph Chan provided the following fix. I don't have any idea what it does but I can verify the issue is gone with the patch applied. Signed-off-by: Tejun Heo <tj@kernel.org> Originally-from: Joseph Chan <JosephChan@via.com.tw> Reported-by: Jorrit Tijben <sjorrit@gmail.com> Cc: stable@kernel.org Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/sata_via.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 101d8c219caf..0ecd0f6aa2c0 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -575,6 +575,19 @@ static void svia_configure(struct pci_dev *pdev) tmp8 |= NATIVE_MODE_ALL; pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); } + + /* + * vt6421 has problems talking to some drives. The following + * is the magic fix from Joseph Chan <JosephChan@via.com.tw>. + * Please add proper documentation if possible. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=15173 + */ + if (pdev->device == 0x3249) { + pci_read_config_byte(pdev, 0x52, &tmp8); + tmp8 |= 1 << 2; + pci_write_config_byte(pdev, 0x52, tmp8); + } } static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -- GitLab From f3faf8fc3fab45c3526efe8c9e99bb23f8723350 Mon Sep 17 00:00:00 2001 From: Tejun Heo <tj@kernel.org> Date: Tue, 1 Jun 2010 17:29:21 +0200 Subject: [PATCH 528/842] sata_nv: don't diddle with nIEN on mcp55 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On mcp55, nIEN gets stuck once set and liteon blueray rom iHOS104-08 violates ATA specification and fails to set I on D2H Reg FIS if nIEN is set when the command was issued. When the other party is following the spec, both devices can work fine but when the two flaws are put together, they can't talk to each other. mcp55 has its own IRQ masking mechanism and there's no reason to mess with nIEN in the first place. Fix it by dropping nIEN diddling from nv_mcp55_freeze/thaw(). This was originally reported by Cengiz. Although Cengiz hasn't verified the fix yet, I could reproduce this problem and verfiy the fix. Even if Cengiz is experiencing different or additional problems, this patch is needed. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Cengiz Günay <cgunay@emory.edu> Cc: stable@kernel.org Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/sata_nv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 6fd114784116..21161136cad0 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1669,7 +1669,6 @@ static void nv_mcp55_freeze(struct ata_port *ap) mask = readl(mmio_base + NV_INT_ENABLE_MCP55); mask &= ~(NV_INT_ALL_MCP55 << shift); writel(mask, mmio_base + NV_INT_ENABLE_MCP55); - ata_sff_freeze(ap); } static void nv_mcp55_thaw(struct ata_port *ap) @@ -1683,7 +1682,6 @@ static void nv_mcp55_thaw(struct ata_port *ap) mask = readl(mmio_base + NV_INT_ENABLE_MCP55); mask |= (NV_INT_MASK_MCP55 << shift); writel(mask, mmio_base + NV_INT_ENABLE_MCP55); - ata_sff_thaw(ap); } static void nv_adma_error_handler(struct ata_port *ap) -- GitLab From ed4e2f801cf1484a68c4b41878353f26e6554c6a Mon Sep 17 00:00:00 2001 From: Stefan Richter <stefanr@s5r6.in-berlin.de> Date: Sat, 29 May 2010 12:47:45 +0200 Subject: [PATCH 529/842] libata-sff: trivial corrections to Kconfig help text Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 73f883333a0d..aa85a98d3a4f 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -168,10 +168,10 @@ config ATA_BMDMA default y help This option adds support for SFF ATA controllers with BMDMA - capability. BMDMA stands for bus-master DMA and the - de-facto DMA interface for SFF controllers. + capability. BMDMA stands for bus-master DMA and is the + de facto DMA interface for SFF controllers. - If unuser, say Y. + If unsure, say Y. if ATA_BMDMA -- GitLab From 72ec24bd7725545bc149d80cbd21a7578d9aa206 Mon Sep 17 00:00:00 2001 From: Tejun Heo <tj@kernel.org> Date: Sat, 15 May 2010 20:09:32 +0200 Subject: [PATCH 530/842] SCSI: implement sd_unlock_native_capacity() Implement sd_unlock_native_capacity() method which calls into hostt->unlock_native_capacity() if implemented. This will be invoked by block layer if partitions extend beyond the end of the device and can be used to implement, for example, on-demand ATA host protected area unlocking. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/scsi/sd.c | 22 ++++++++++++++++++++++ include/scsi/scsi_host.h | 8 ++++++++ 2 files changed, 30 insertions(+) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 829cc37abc41..8802e48bc063 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -97,6 +97,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); #endif static int sd_revalidate_disk(struct gendisk *); +static void sd_unlock_native_capacity(struct gendisk *disk); static int sd_probe(struct device *); static int sd_remove(struct device *); static void sd_shutdown(struct device *); @@ -1101,6 +1102,7 @@ static const struct block_device_operations sd_fops = { #endif .media_changed = sd_media_changed, .revalidate_disk = sd_revalidate_disk, + .unlock_native_capacity = sd_unlock_native_capacity, }; static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) @@ -2120,6 +2122,26 @@ static int sd_revalidate_disk(struct gendisk *disk) return 0; } +/** + * sd_unlock_native_capacity - unlock native capacity + * @disk: struct gendisk to set capacity for + * + * Block layer calls this function if it detects that partitions + * on @disk reach beyond the end of the device. If the SCSI host + * implements ->unlock_native_capacity() method, it's invoked to + * give it a chance to adjust the device capacity. + * + * CONTEXT: + * Defined by block layer. Might sleep. + */ +static void sd_unlock_native_capacity(struct gendisk *disk) +{ + struct scsi_device *sdev = scsi_disk(disk)->device; + + if (sdev->host->hostt->unlock_native_capacity) + sdev->host->hostt->unlock_native_capacity(sdev); +} + /** * sd_format_disk_name - format disk name * @prefix: name prefix - ie. "sd" for SCSI disks diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index c50a97fc76f9..b7bdecb7b76e 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -326,6 +326,14 @@ struct scsi_host_template { int (* bios_param)(struct scsi_device *, struct block_device *, sector_t, int []); + /* + * This function is called when one or more partitions on the + * device reach beyond the end of the device. + * + * Status: OPTIONAL + */ + void (*unlock_native_capacity)(struct scsi_device *); + /* * Can be used to export driver statistics and other infos to the * world outside the kernel ie. userspace and it also provides an -- GitLab From 68939ce5fc17ee9c03ef6e543d4f82bd9f5583d4 Mon Sep 17 00:00:00 2001 From: Tejun Heo <tj@kernel.org> Date: Sat, 15 May 2010 20:09:33 +0200 Subject: [PATCH 531/842] libata: use the enlarged capacity after late HPA unlock After late HPA unlock, libata kept using the original capacity ignoring the new larger native capacity. Enlarging device on the fly doesn't cause any harm. Use the larger native capacity instead. This will enable on-demand HPA unlocking. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 06b7e49e039c..1e5d0a36a0a4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4119,9 +4119,8 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, dev->n_sectors > n_sectors && dev->n_sectors == n_native_sectors) { ata_dev_printk(dev, KERN_WARNING, "new n_sectors matches native, probably " - "late HPA unlock, continuing\n"); - /* keep using the old n_sectors */ - dev->n_sectors = n_sectors; + "late HPA unlock, n_sectors updated\n"); + /* use the larger n_sectors */ return 0; } -- GitLab From d8d9129ea28e2177749627c82962feb26e8d11e9 Mon Sep 17 00:00:00 2001 From: Tejun Heo <tj@kernel.org> Date: Sat, 15 May 2010 20:09:34 +0200 Subject: [PATCH 532/842] libata: implement on-demand HPA unlocking Implement ata_scsi_unlock_native_capacity() which will be called through SCSI layer when block layer notices that partitions on a device extend beyond the end of the device. It requests EH to unlock HPA, waits for completion and returns the current device capacity. This allows libata to unlock HPA on demand instead of having to decide whether to unlock upfront. Unlocking on demand is safer than unlocking by upfront because some BIOSes write private data to the area beyond HPA limit. This was suggested by Ben Hutchings. Signed-off-by: Tejun Heo <tj@kernel.org> Suggested-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libata-core.c | 1 + drivers/ata/libata-scsi.c | 29 +++++++++++++++++++++++++++++ include/linux/libata.h | 2 ++ 3 files changed, 32 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1e5d0a36a0a4..ddf8e4862787 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6668,6 +6668,7 @@ EXPORT_SYMBOL_GPL(ata_dummy_port_info); EXPORT_SYMBOL_GPL(ata_link_next); EXPORT_SYMBOL_GPL(ata_dev_next); EXPORT_SYMBOL_GPL(ata_std_bios_param); +EXPORT_SYMBOL_GPL(ata_scsi_unlock_native_capacity); EXPORT_SYMBOL_GPL(ata_host_init); EXPORT_SYMBOL_GPL(ata_host_alloc); EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index cfa9dd3d7253..a54273d2c3c6 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -414,6 +414,35 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, return 0; } +/** + * ata_scsi_unlock_native_capacity - unlock native capacity + * @sdev: SCSI device to adjust device capacity for + * + * This function is called if a partition on @sdev extends beyond + * the end of the device. It requests EH to unlock HPA. + * + * LOCKING: + * Defined by the SCSI layer. Might sleep. + */ +void ata_scsi_unlock_native_capacity(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev; + unsigned long flags; + + spin_lock_irqsave(ap->lock, flags); + + dev = ata_scsi_find_dev(ap, sdev); + if (dev && dev->n_sectors < dev->n_native_sectors) { + dev->flags |= ATA_DFLAG_UNLOCK_HPA; + dev->link->eh_info.action |= ATA_EH_RESET; + ata_port_schedule_eh(ap); + } + + spin_unlock_irqrestore(ap->lock, flags); + ata_port_wait_eh(ap); +} + /** * ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl * @ap: target port diff --git a/include/linux/libata.h b/include/linux/libata.h index 3bad2701bfa6..b85f3ff34d7d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1023,6 +1023,7 @@ extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, extern int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]); +extern void ata_scsi_unlock_native_capacity(struct scsi_device *sdev); extern int ata_scsi_slave_config(struct scsi_device *sdev); extern void ata_scsi_slave_destroy(struct scsi_device *sdev); extern int ata_scsi_change_queue_depth(struct scsi_device *sdev, @@ -1174,6 +1175,7 @@ extern struct device_attribute *ata_common_sdev_attrs[]; .slave_configure = ata_scsi_slave_config, \ .slave_destroy = ata_scsi_slave_destroy, \ .bios_param = ata_std_bios_param, \ + .unlock_native_capacity = ata_scsi_unlock_native_capacity, \ .sdev_attrs = ata_common_sdev_attrs #define ATA_NCQ_SHT(drv_name) \ -- GitLab From ffabc9a6e8b34151a97fc91fcbef827f07504f75 Mon Sep 17 00:00:00 2001 From: Grant Likely <grant.likely@secretlab.ca> Date: Wed, 2 Jun 2010 13:35:02 -0600 Subject: [PATCH 533/842] of/usb: fix build error due to of_node pointer move Fix driver to use new location of of_node pointer (introduced by commit use new location of of_node pointer (introduced by commit 61c7a080a5a061c976988fd4b844dfb468dda255; of: Always use 'struct device.of_node' to get device node pointer) Signed-off-by: Grant Likely <grant.likely@secretlab.ca> Reported-by: John Linn <john.linn@xilinx.com> CC: Greg Kroah-Hartman <gregkh@suse.de> CC: Alan Stern <stern@rowland.harvard.edu> CC: linux-usb@vger.kernel.org CC: devicetree-discuss@lists.ozlabs.org --- drivers/usb/host/ehci-xilinx-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index 013972bbde57..4899f451add9 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -151,7 +151,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = { static int __devinit ehci_hcd_xilinx_of_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dn = op->node; + struct device_node *dn = op->dev.of_node; struct usb_hcd *hcd; struct ehci_hcd *ehci; struct resource res; -- GitLab From b53550781b7d51036aea3b3ee63ece3c6c8f4597 Mon Sep 17 00:00:00 2001 From: Grant Likely <grant.likely@secretlab.ca> Date: Tue, 25 May 2010 23:24:02 -0600 Subject: [PATCH 534/842] of/spi: Fix build failure on spi_ppc4xx.c This patch fixes a build error caused by the OF device_node pointer being moved into struct device. Fixes bug introduced by commit 61c7a080a5a061c976988fd4b844dfb468dda255 (of: Always use 'struct device.of_node' to get device node pointer) Signed-off-by: Grant Likely <grant.likely@secretlab.ca> CC: Sean MacLennan <smaclennan@pikatech.com> CC: spi-devel-general@lists.sourceforge.net CC: devicetree-discuss@lists.ozlabs.org --- drivers/spi/spi_ppc4xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c index 19c0b3b34fce..d53466a249d9 100644 --- a/drivers/spi/spi_ppc4xx.c +++ b/drivers/spi/spi_ppc4xx.c @@ -397,7 +397,7 @@ static int __init spi_ppc4xx_of_probe(struct of_device *op, struct spi_master *master; struct spi_bitbang *bbp; struct resource resource; - struct device_node *np = op->node; + struct device_node *np = op->dev.of_node; struct device *dev = &op->dev; struct device_node *opbnp; int ret; -- GitLab From de2b606c24f178038b95a831f21a35a29faa6eab Mon Sep 17 00:00:00 2001 From: Michael Guntsche <mike@it-loops.com> Date: Wed, 2 Jun 2010 02:25:52 -0600 Subject: [PATCH 535/842] watchdog: Fix build failure with OF changes commit 61c7a080a5a061c976988fd4b844dfb468dda255 ( of: Always use 'struct device.of_node' to get device node pointer.) missed drivers/watchdog/mpc8xxx_wdt.c. This patch fixes it Signed-off-by: Michael Guntsche <mike@it-loops.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/watchdog/mpc8xxx_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 6622335773bb..4cda64dd309c 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -189,7 +189,7 @@ static int __devinit mpc8xxx_wdt_probe(struct of_device *ofdev, const struct of_device_id *match) { int ret; - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct mpc8xxx_wdt_type *wdt_type = match->data; u32 freq = fsl_get_sys_freq(); bool enabled; -- GitLab From ef7f2e831c3a563505c9bc5b16ef4bcae3cf4b53 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Mon, 31 May 2010 18:34:54 +0200 Subject: [PATCH 536/842] of/spi: mpc512x_psc_spi.c: Fix build failures Fixes build errors caused by the: - OF device_node pointer being moved into struct device - removal of the match_table field from struct of_platform_driver Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/spi/mpc512x_psc_spi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/spi/mpc512x_psc_spi.c b/drivers/spi/mpc512x_psc_spi.c index 28a126d2742b..2534b1ec3edd 100644 --- a/drivers/spi/mpc512x_psc_spi.c +++ b/drivers/spi/mpc512x_psc_spi.c @@ -512,29 +512,29 @@ static int __init mpc512x_psc_spi_of_probe(struct of_device *op, u64 regaddr64, size64; s16 id = -1; - regaddr_p = of_get_address(op->node, 0, &size64, NULL); + regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL); if (!regaddr_p) { dev_err(&op->dev, "Invalid PSC address\n"); return -EINVAL; } - regaddr64 = of_translate_address(op->node, regaddr_p); + regaddr64 = of_translate_address(op->dev.of_node, regaddr_p); /* get PSC id (0..11, used by port_config) */ if (op->dev.platform_data == NULL) { const u32 *psc_nump; - psc_nump = of_get_property(op->node, "cell-index", NULL); + psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL); if (!psc_nump || *psc_nump > 11) { dev_err(&op->dev, "mpc512x_psc_spi: Device node %s " "has invalid cell-index property\n", - op->node->full_name); + op->dev.of_node->full_name); return -EINVAL; } id = *psc_nump; } return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64, - irq_of_parse_and_map(op->node, 0), id); + irq_of_parse_and_map(op->dev.of_node, 0), id); } static int __exit mpc512x_psc_spi_of_remove(struct of_device *op) @@ -550,12 +550,12 @@ static struct of_device_id mpc512x_psc_spi_of_match[] = { MODULE_DEVICE_TABLE(of, mpc512x_psc_spi_of_match); static struct of_platform_driver mpc512x_psc_spi_of_driver = { - .match_table = mpc512x_psc_spi_of_match, .probe = mpc512x_psc_spi_of_probe, .remove = __exit_p(mpc512x_psc_spi_of_remove), .driver = { .name = "mpc512x-psc-spi", .owner = THIS_MODULE, + .of_match_table = mpc512x_psc_spi_of_match, }, }; -- GitLab From 14acbbf8bada18f19930d38ce33c3947b2c718e0 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Mon, 31 May 2010 18:37:15 +0200 Subject: [PATCH 537/842] of/mtd/nand: mpc5121_nfc.c: Fix build failures Fixes build errors caused by the: - OF device_node pointer being moved into struct device - removal of the match_table field from struct of_platform_driver Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/mtd/nand/mpc5121_nfc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 3d0867d829cb..0a130dcaa129 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -650,7 +650,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd) static int __devinit mpc5121_nfc_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *rootnode, *dn = op->node; + struct device_node *rootnode, *dn = op->dev.of_node; struct device *dev = &op->dev; struct mpc5121_nfc_prv *prv; struct resource res; @@ -889,12 +889,12 @@ static struct of_device_id mpc5121_nfc_match[] __devinitdata = { }; static struct of_platform_driver mpc5121_nfc_driver = { - .match_table = mpc5121_nfc_match, .probe = mpc5121_nfc_probe, .remove = __devexit_p(mpc5121_nfc_remove), .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = mpc5121_nfc_match, }, }; -- GitLab From b4a75c91b8a6cb80ba7772f69613025ddf75ebc2 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Mon, 31 May 2010 18:39:13 +0200 Subject: [PATCH 538/842] of/dma: mpc512x_dma.c: Fix build failures Fixes build errors caused by the: - OF device_node pointer being moved into struct device - removal of the match_table field from struct of_platform_driver Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/dma/mpc512x_dma.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 201e6e19c344..14a8c0f1698e 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -630,7 +630,7 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, static int __devinit mpc_dma_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dn = op->node; + struct device_node *dn = op->dev.of_node; struct device *dev = &op->dev; struct dma_device *dma; struct mpc_dma *mdma; @@ -771,12 +771,12 @@ static struct of_device_id mpc_dma_match[] = { }; static struct of_platform_driver mpc_dma_driver = { - .match_table = mpc_dma_match, .probe = mpc_dma_probe, .remove = __devexit_p(mpc_dma_remove), - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = mpc_dma_match, }, }; -- GitLab From 295bdd9c52e57daf995fe80eff8c53938443fa2f Mon Sep 17 00:00:00 2001 From: Grant Likely <grant.likely@secretlab.ca> Date: Wed, 2 Jun 2010 14:06:09 -0600 Subject: [PATCH 539/842] of/rtc: rtc-mpc5121.c: Fix build failures Fixes build errors caused by the: - OF device_node pointer being moved into struct device - removal of the match_table field from struct of_platform_driver Signed-off-by: Grant Likely <grant.likely@secretlab.ca> CC: Paul Gortmaker <p_gortmaker@yahoo.com> CC: Alessandro Zummo <a.zummo@towertech.it> CC: Wolfgang Denk <wd@denx.de> CC: Tejun Heo <tj@kernel.org> CC: Anatolij Gustschin <agust@denx.de> CC: rtc-linux@googlegroups.com CC: devicetree-discuss@lists.ozlabs.org --- drivers/rtc/rtc-mpc5121.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index f0dbf9cb8f9c..db5d8c416d26 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -279,7 +279,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op, if (!rtc) return -ENOMEM; - rtc->regs = of_iomap(op->node, 0); + rtc->regs = of_iomap(op->dev.of_node, 0); if (!rtc->regs) { dev_err(&op->dev, "%s: couldn't map io space\n", __func__); err = -ENOSYS; @@ -290,7 +290,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op, dev_set_drvdata(&op->dev, rtc); - rtc->irq = irq_of_parse_and_map(op->node, 1); + rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1); err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED, "mpc5121-rtc", &op->dev); if (err) { @@ -299,7 +299,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op, goto out_dispose; } - rtc->irq_periodic = irq_of_parse_and_map(op->node, 0); + rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0); err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd, IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev); if (err) { @@ -365,9 +365,11 @@ static struct of_device_id mpc5121_rtc_match[] __devinitdata = { }; static struct of_platform_driver mpc5121_rtc_driver = { - .owner = THIS_MODULE, - .name = "mpc5121-rtc", - .match_table = mpc5121_rtc_match, + .driver = { + .name = "mpc5121-rtc", + .owner = THIS_MODULE, + .of_match_table = mpc5121_rtc_match, + }, .probe = mpc5121_rtc_probe, .remove = __devexit_p(mpc5121_rtc_remove), }; -- GitLab From a57ee627499d116f6872a5634ea4f015da0eacd2 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka <mpatocka@redhat.com> Date: Wed, 2 Jun 2010 11:09:04 -0400 Subject: [PATCH 540/842] Fix colors for Mach64 Use the same color-calculating algorithm as in atyfb_imageblit in this driver or in generic cfb_fillrect. This patch fixes bad colors when using an accelerator in 15-bit and 16-bit modes. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/video/aty/mach64_accel.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index 51fcc0a2c94a..e45833ce975b 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c @@ -242,7 +242,7 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct atyfb_par *par = (struct atyfb_par *) info->par; - u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0; + u32 color, dx = rect->dx, width = rect->width, rotation = 0; if (par->asleep) return; @@ -253,8 +253,11 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) return; } - color |= (rect->color << 8); - color |= (rect->color << 16); + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + color = ((u32 *)(info->pseudo_palette))[rect->color]; + else + color = rect->color; if (info->var.bits_per_pixel == 24) { /* In 24 bpp, the engine is in 8 bpp - this requires that all */ -- GitLab From 1f5a81e41f8b1a782c68d3843e9ec1bfaadf7d72 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o <tytso@mit.edu> Date: Wed, 2 Jun 2010 22:04:39 -0400 Subject: [PATCH 541/842] ext4: Make sure the MOVE_EXT ioctl can't overwrite append-only files Dan Roseberg has reported a problem with the MOVE_EXT ioctl. If the donor file is an append-only file, we should not allow the operation to proceed, lest we end up overwriting the contents of an append-only file. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Cc: Dan Rosenberg <dan.j.rosenberg@gmail.com> --- fs/ext4/move_extent.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 3a6c92ac131c..52abfa12762a 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -960,6 +960,9 @@ mext_check_arguments(struct inode *orig_inode, return -EINVAL; } + if (IS_IMMUTABLE(donor_inode) || IS_APPEND(donor_inode)) + return -EPERM; + /* Ext4 move extent does not support swapfile */ if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { ext4_debug("ext4 move extent: The argument files should " -- GitLab From 2005ce3521b7a38f12085e0420f405a8ee06f606 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Thu, 3 Jun 2010 01:38:57 +0200 Subject: [PATCH 542/842] of/pcmcia: m8xx_pcmcia.c: Fix build failures Fixes build errors caused by the: - OF device_node pointer being moved into struct device - typo in match_table field in the struct device_driver (which shoud be of_match_table) Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/pcmcia/m8xx_pcmcia.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 1a648b90b634..25e5e30a18af 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -1157,7 +1157,7 @@ static int __init m8xx_probe(struct of_device *ofdev, unsigned int i, m, hwirq; pcmconf8xx_t *pcmcia; int status; - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; pcmcia_info("%s\n", version); @@ -1301,7 +1301,7 @@ static struct of_platform_driver m8xx_pcmcia_driver = { .driver = { .name = driver_name, .owner = THIS_MODULE, - .match_table = m8xx_pcmcia_match, + .of_match_table = m8xx_pcmcia_match, }, .probe = m8xx_probe, .remove = m8xx_remove, -- GitLab From d4b8b2c2c0b980fa756267e43e39e5ac3c894857 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Thu, 3 Jun 2010 02:20:44 +0200 Subject: [PATCH 543/842] of/video: fix build breakage in FB drivers Fixes build errors in a number of framebuffer drivers caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/video/bw2.c | 2 +- drivers/video/cg14.c | 2 +- drivers/video/cg3.c | 2 +- drivers/video/leo.c | 2 +- drivers/video/mb862xx/mb862xxfb.c | 2 +- drivers/video/p9100.c | 2 +- drivers/video/tcx.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 2c371c07f0da..09f1b9b462f4 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -275,7 +275,7 @@ static int __devinit bw2_do_default_mode(struct bw2_par *par, static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct bw2_par *par; int linebytes, err; diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index d12e05b6e63f..e5dc2241194f 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -465,7 +465,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info, static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct cg14_par *par; int is_8mb, linebytes, i, err; diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index b98f93f7f663..558d73a948a0 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -349,7 +349,7 @@ static int __devinit cg3_do_default_mode(struct cg3_par *par) static int __devinit cg3_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct cg3_par *par; int linebytes, err; diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 3d7895316eaf..9e8bf7d5e249 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -550,7 +550,7 @@ static void leo_unmap_regs(struct of_device *op, struct fb_info *info, static int __devinit leo_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct leo_par *par; int linebytes, err; diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index 0540de4f5cb4..4e2b8cc3d460 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c @@ -553,7 +553,7 @@ static int mb862xx_gdc_init(struct mb862xxfb_par *par) static int __devinit of_platform_mb862xx_probe(struct of_device *ofdev, const struct of_device_id *id) { - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct device *dev = &ofdev->dev; struct mb862xxfb_par *par; struct fb_info *info; diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index c85dd408a9b8..6552751e81aa 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -251,7 +251,7 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct p9100_par *par; int linebytes, err; diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index ef7a7bd8b503..cc039b33d2d8 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -365,7 +365,7 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info, static int __devinit tcx_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; + struct device_node *dp = op->dev.of_node; struct fb_info *info; struct tcx_par *par; int linebytes, i, err; -- GitLab From c8a4d0fd2ac2ce6b3409f51fcf918dcb3617ec97 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Thu, 3 Jun 2010 02:37:17 +0200 Subject: [PATCH 544/842] of/mtd: nand: fix build breakage in drivers Fixes build errors in drivers caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/mtd/nand/fsl_upm.c | 17 +++++++++-------- drivers/mtd/nand/socrates_nand.c | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 00aea6f7d1f1..1312eda57ba6 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -232,7 +232,7 @@ static int __devinit fun_probe(struct of_device *ofdev, if (!fun) return -ENOMEM; - ret = of_address_to_resource(ofdev->node, 0, &io_res); + ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res); if (ret) { dev_err(&ofdev->dev, "can't get IO base\n"); goto err1; @@ -244,7 +244,8 @@ static int __devinit fun_probe(struct of_device *ofdev, goto err1; } - prop = of_get_property(ofdev->node, "fsl,upm-addr-offset", &size); + prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-offset", + &size); if (!prop || size != sizeof(uint32_t)) { dev_err(&ofdev->dev, "can't get UPM address offset\n"); ret = -EINVAL; @@ -252,7 +253,7 @@ static int __devinit fun_probe(struct of_device *ofdev, } fun->upm_addr_offset = *prop; - prop = of_get_property(ofdev->node, "fsl,upm-cmd-offset", &size); + prop = of_get_property(ofdev->dev.of_node, "fsl,upm-cmd-offset", &size); if (!prop || size != sizeof(uint32_t)) { dev_err(&ofdev->dev, "can't get UPM command offset\n"); ret = -EINVAL; @@ -260,7 +261,7 @@ static int __devinit fun_probe(struct of_device *ofdev, } fun->upm_cmd_offset = *prop; - prop = of_get_property(ofdev->node, + prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-line-cs-offsets", &size); if (prop && (size / sizeof(uint32_t)) > 0) { fun->mchip_count = size / sizeof(uint32_t); @@ -276,7 +277,7 @@ static int __devinit fun_probe(struct of_device *ofdev, for (i = 0; i < fun->mchip_count; i++) { fun->rnb_gpio[i] = -1; - rnb_gpio = of_get_gpio(ofdev->node, i); + rnb_gpio = of_get_gpio(ofdev->dev.of_node, i); if (rnb_gpio >= 0) { ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev)); if (ret) { @@ -292,13 +293,13 @@ static int __devinit fun_probe(struct of_device *ofdev, } } - prop = of_get_property(ofdev->node, "chip-delay", NULL); + prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL); if (prop) fun->chip_delay = *prop; else fun->chip_delay = 50; - prop = of_get_property(ofdev->node, "fsl,upm-wait-flags", &size); + prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size); if (prop && size == sizeof(uint32_t)) fun->wait_flags = *prop; else @@ -315,7 +316,7 @@ static int __devinit fun_probe(struct of_device *ofdev, fun->dev = &ofdev->dev; fun->last_ctrl = NAND_CLE; - ret = fun_chip_init(fun, ofdev->node, &io_res); + ret = fun_chip_init(fun, ofdev->dev.of_node, &io_res); if (ret) goto err2; diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index 884852dc7eb4..cc728b12de82 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -183,7 +183,7 @@ static int __devinit socrates_nand_probe(struct of_device *ofdev, return -ENOMEM; } - host->io_base = of_iomap(ofdev->node, 0); + host->io_base = of_iomap(ofdev->dev.of_node, 0); if (host->io_base == NULL) { printk(KERN_ERR "socrates_nand: ioremap failed\n"); kfree(host); @@ -244,7 +244,7 @@ static int __devinit socrates_nand_probe(struct of_device *ofdev, #ifdef CONFIG_MTD_OF_PARTS if (num_partitions == 0) { num_partitions = of_mtd_parse_partitions(&ofdev->dev, - ofdev->node, + ofdev->dev.of_node, &partitions); if (num_partitions < 0) { res = num_partitions; -- GitLab From 05c02542c20aa00dc9a66f4bfb1a89d1131457f2 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Thu, 3 Jun 2010 02:46:37 +0200 Subject: [PATCH 545/842] of/dma: fix build breakage in ppc4xx adma driver Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/dma/ppc4xx/adma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index fa98abe4686f..5a22ca6927e5 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -4394,7 +4394,7 @@ static void ppc440spe_adma_release_irqs(struct ppc440spe_adma_device *adev, static int __devinit ppc440spe_adma_probe(struct of_device *ofdev, const struct of_device_id *match) { - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct resource res; struct ppc440spe_adma_device *adev; struct ppc440spe_adma_chan *chan; @@ -4626,7 +4626,7 @@ out: static int __devexit ppc440spe_adma_remove(struct of_device *ofdev) { struct ppc440spe_adma_device *adev = dev_get_drvdata(&ofdev->dev); - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct resource res; struct dma_chan *chan, *_chan; struct ppc_dma_chan_ref *ref, *_ref; -- GitLab From 7cea8cc4705d25d9c7baee06efd665db27481242 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Thu, 3 Jun 2010 02:53:18 +0200 Subject: [PATCH 546/842] of/crypto: crypto4xx_core.c: fix build breakage Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/crypto/amcc/crypto4xx_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 9d65b371de64..983530ba04a7 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1158,7 +1158,7 @@ static int __init crypto4xx_probe(struct of_device *ofdev, struct device *dev = &ofdev->dev; struct crypto4xx_core_device *core_dev; - rc = of_address_to_resource(ofdev->node, 0, &res); + rc = of_address_to_resource(ofdev->dev.of_node, 0, &res); if (rc) return -ENODEV; @@ -1215,13 +1215,13 @@ static int __init crypto4xx_probe(struct of_device *ofdev, (unsigned long) dev); /* Register for Crypto isr, Crypto Engine IRQ */ - core_dev->irq = irq_of_parse_and_map(ofdev->node, 0); + core_dev->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); rc = request_irq(core_dev->irq, crypto4xx_ce_interrupt_handler, 0, core_dev->dev->name, dev); if (rc) goto err_request_irq; - core_dev->dev->ce_base = of_iomap(ofdev->node, 0); + core_dev->dev->ce_base = of_iomap(ofdev->dev.of_node, 0); if (!core_dev->dev->ce_base) { dev_err(dev, "failed to of_iomap\n"); goto err_iomap; -- GitLab From 3ed3880230288c3eba1174b865ea7cdfbcb20033 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Thu, 3 Jun 2010 02:59:55 +0200 Subject: [PATCH 547/842] of/usb: fsl_qe_udc.c: fix build breakage Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/usb/gadget/fsl_qe_udc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 2928523268b5..82506ca297d5 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2400,7 +2400,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver); static struct qe_udc __devinit *qe_udc_config(struct of_device *ofdev) { struct qe_udc *udc; - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; unsigned int tmp_addr = 0; struct usb_device_para __iomem *usbpram; unsigned int i; @@ -2525,7 +2525,7 @@ static void qe_udc_release(struct device *dev) static int __devinit qe_udc_probe(struct of_device *ofdev, const struct of_device_id *match) { - struct device_node *np = ofdev->node; + struct device_node *np = ofdev->dev.of_node; struct qe_ep *ep; unsigned int ret = 0; unsigned int i; -- GitLab From 4eecb17825a9cd2ea750c177487000fab4c19ea2 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Thu, 3 Jun 2010 03:06:54 +0200 Subject: [PATCH 548/842] of/net: fs_enet/mii-bitbang.c: fix build breakage Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/net/fs_enet/mii-bitbang.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 0f90685d3d19..3607340f3da7 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -169,7 +169,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, new_bus->name = "CPM2 Bitbanged MII", - ret = fs_mii_bitbang_init(new_bus, ofdev->node); + ret = fs_mii_bitbang_init(new_bus, ofdev->dev.of_node); if (ret) goto out_free_bus; @@ -181,7 +181,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); - ret = of_mdiobus_register(new_bus, ofdev->node); + ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); if (ret) goto out_free_irqs; -- GitLab From a26f95fed31d917eee616d1cd6360e4ce782e3dc Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Thu, 3 Jun 2010 03:17:42 +0200 Subject: [PATCH 549/842] of/edac: fix build breakage in drivers Fixes build errors in EDAC drivers caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/edac/mpc85xx_edac.c | 12 ++++++------ drivers/edac/ppc4xx_edac.c | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 6c1886b497ff..52ca09bf4726 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -229,7 +229,7 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op, pdata->edac_idx = edac_pci_idx++; - res = of_address_to_resource(op->node, 0, &r); + res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { printk(KERN_ERR "%s: Unable to get resource for " "PCI err regs\n", __func__); @@ -274,7 +274,7 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op, } if (edac_op_state == EDAC_OPSTATE_INT) { - pdata->irq = irq_of_parse_and_map(op->node, 0); + pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); res = devm_request_irq(&op->dev, pdata->irq, mpc85xx_pci_isr, IRQF_DISABLED, "[EDAC] PCI err", pci); @@ -529,7 +529,7 @@ static int __devinit mpc85xx_l2_err_probe(struct of_device *op, edac_dev->ctl_name = pdata->name; edac_dev->dev_name = pdata->name; - res = of_address_to_resource(op->node, 0, &r); + res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { printk(KERN_ERR "%s: Unable to get resource for " "L2 err regs\n", __func__); @@ -576,7 +576,7 @@ static int __devinit mpc85xx_l2_err_probe(struct of_device *op, } if (edac_op_state == EDAC_OPSTATE_INT) { - pdata->irq = irq_of_parse_and_map(op->node, 0); + pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); res = devm_request_irq(&op->dev, pdata->irq, mpc85xx_l2_isr, IRQF_DISABLED, "[EDAC] L2 err", edac_dev); @@ -978,7 +978,7 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op, mci->ctl_name = pdata->name; mci->dev_name = pdata->name; - res = of_address_to_resource(op->node, 0, &r); + res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { printk(KERN_ERR "%s: Unable to get resource for MC err regs\n", __func__); @@ -1052,7 +1052,7 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op, out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000); /* register interrupts */ - pdata->irq = irq_of_parse_and_map(op->node, 0); + pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); res = devm_request_irq(&op->dev, pdata->irq, mpc85xx_mc_isr, IRQF_DISABLED | IRQF_SHARED, diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 9d6f6783328c..e78839e89a06 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -1022,7 +1022,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci, int status = 0; const u32 memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK); struct ppc4xx_edac_pdata *pdata = NULL; - const struct device_node *np = op->node; + const struct device_node *np = op->dev.of_node; if (match == NULL) return -EINVAL; @@ -1113,7 +1113,7 @@ ppc4xx_edac_register_irq(struct of_device *op, struct mem_ctl_info *mci) int status = 0; int ded_irq, sec_irq; struct ppc4xx_edac_pdata *pdata = mci->pvt_info; - struct device_node *np = op->node; + struct device_node *np = op->dev.of_node; ded_irq = irq_of_parse_and_map(np, INTMAP_ECCDED_INDEX); sec_irq = irq_of_parse_and_map(np, INTMAP_ECCSEC_INDEX); @@ -1243,7 +1243,7 @@ ppc4xx_edac_probe(struct of_device *op, const struct of_device_id *match) int status = 0; u32 mcopt1, memcheck; dcr_host_t dcr_host; - const struct device_node *np = op->node; + const struct device_node *np = op->dev.of_node; struct mem_ctl_info *mci = NULL; static int ppc4xx_edac_instance; -- GitLab From b74dbf2aed8d8c4f93ac2c44bab5c81f65be62a0 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Thu, 3 Jun 2010 03:30:31 +0200 Subject: [PATCH 550/842] of/watchdog: gef_wdt.c: fix build breakage Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- drivers/watchdog/gef_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c index ca0f4c6cf5ab..1df284f9c2a1 100644 --- a/drivers/watchdog/gef_wdt.c +++ b/drivers/watchdog/gef_wdt.c @@ -273,7 +273,7 @@ static int __devinit gef_wdt_probe(struct of_device *dev, bus_clk = freq; /* Map devices registers into memory */ - gef_wdt_regs = of_iomap(dev->node, 0); + gef_wdt_regs = of_iomap(dev->dev.of_node, 0); if (gef_wdt_regs == NULL) return -ENOMEM; -- GitLab From 7ac9aa5a1f1b87adb69bcbec2b89e228f074103a Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Thu, 27 May 2010 19:25:54 -0400 Subject: [PATCH 551/842] drm/radeon/kms/pm: add support for SetVoltage cmd table (V2) - This enables voltage adjustment on r6xx+ and certain r5xx asics. - Voltage drop support is already available for most r1xx-r5xx asics. V2: endian fix for voltage table. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/r600.c | 6 ++++ drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_atombios.c | 36 ++++++++++++++++++++++++ drivers/gpu/drm/radeon/rs600.c | 3 +- 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 44e96a2ae25a..e14f59748e65 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -475,6 +475,12 @@ void r600_pm_init_profile(struct radeon_device *rdev) void r600_pm_misc(struct radeon_device *rdev) { + int requested_index = rdev->pm.requested_power_state_index; + struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; + struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + + if ((voltage->type == VOLTAGE_SW) && voltage->voltage) + radeon_atom_set_voltage(rdev, voltage->voltage); } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 669feb689bfc..5f96fe871b3f 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -176,6 +176,7 @@ void radeon_pm_suspend(struct radeon_device *rdev); void radeon_pm_resume(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); +void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level); /* * Fences. diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 24ea683f7cf5..24ebb4ea7984 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1998,6 +1998,42 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev, atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +union set_voltage { + struct _SET_VOLTAGE_PS_ALLOCATION alloc; + struct _SET_VOLTAGE_PARAMETERS v1; + struct _SET_VOLTAGE_PARAMETERS_V2 v2; +}; + +void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level) +{ + union set_voltage args; + int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); + u8 frev, crev, volt_index = level; + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (crev) { + case 1: + args.v1.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC; + args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE; + args.v1.ucVoltageIndex = volt_index; + break; + case 2: + args.v2.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC; + args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE; + args.v2.usVoltageLevel = cpu_to_le16(level); + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + return; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + + + void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 79887cac5b54..7bb4c3e52f3b 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -74,7 +74,8 @@ void rs600_pm_misc(struct radeon_device *rdev) if (voltage->delay) udelay(voltage->delay); } - } + } else if (voltage->type == VOLTAGE_VDDC) + radeon_atom_set_voltage(rdev, voltage->vddc_id); dyn_pwrmgt_sclk_length = RREG32_PLL(DYN_PWRMGT_SCLK_LENGTH); dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_HILEN(0xf); -- GitLab From 9349d5cc920c10845693f906ebd67f394f1d0d04 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Fri, 28 May 2010 19:35:01 -0400 Subject: [PATCH 552/842] drm/radeon/kms/pm: enable SetVoltage on r7xx/evergreen I missed these in the r6xx commit. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/evergreen.c | 5 +++++ drivers/gpu/drm/radeon/rv770.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 8c8e4d3cbaa3..0440c0939bdd 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -41,7 +41,12 @@ void evergreen_fini(struct radeon_device *rdev); void evergreen_pm_misc(struct radeon_device *rdev) { + int requested_index = rdev->pm.requested_power_state_index; + struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; + struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + if ((voltage->type == VOLTAGE_SW) && voltage->voltage) + radeon_atom_set_voltage(rdev, voltage->voltage); } void evergreen_pm_prepare(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 253f24aec031..33952da65340 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -44,7 +44,12 @@ void rv770_fini(struct radeon_device *rdev); void rv770_pm_misc(struct radeon_device *rdev) { + int requested_index = rdev->pm.requested_power_state_index; + struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; + struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + if ((voltage->type == VOLTAGE_SW) && voltage->voltage) + radeon_atom_set_voltage(rdev, voltage->voltage); } /* -- GitLab From c5e8ce61d64995f4076c6a9b2f8b4b71e0be2e37 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Thu, 27 May 2010 17:01:40 -0400 Subject: [PATCH 553/842] drm/radeon/kms/pm: patch default power state with default clocks/voltages on r6xx+ The default power state does not always match the default clocks and voltage for a particular card. The information in the firmware info table is correct and should be used in preference to the info the default power state. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_atombios.c | 25 +++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 24ebb4ea7984..42bcaf41b8c4 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1755,9 +1755,22 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].misc2 = 0; } } else { + int fw_index = GetIndexIntoMasterTable(DATA, FirmwareInfo); + uint8_t fw_frev, fw_crev; + uint16_t fw_data_offset, vddc = 0; + union firmware_info *firmware_info; + ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController; + + if (atom_parse_data_header(mode_info->atom_context, fw_index, NULL, + &fw_frev, &fw_crev, &fw_data_offset)) { + firmware_info = + (union firmware_info *)(mode_info->atom_context->bios + + fw_data_offset); + vddc = firmware_info->info_14.usBootUpVDDCVoltage; + } + /* add the i2c bus for thermal/fan chip */ /* no support for internal controller yet */ - ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController; if (controller->ucType > 0) { if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) || (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) || @@ -1904,6 +1917,16 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; + /* patch the table values with the default slck/mclk from firmware info */ + for (j = 0; j < mode_index; j++) { + rdev->pm.power_state[state_index].clock_info[j].mclk = + rdev->clock.default_mclk; + rdev->pm.power_state[state_index].clock_info[j].sclk = + rdev->clock.default_sclk; + if (vddc) + rdev->pm.power_state[state_index].clock_info[j].voltage.voltage = + vddc; + } } state_index++; } -- GitLab From 92645879d07a48897fe8888c2e37607aa1189cc9 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Thu, 27 May 2010 17:01:41 -0400 Subject: [PATCH 554/842] drm/radeon/kms/pm: radeon_set_power_state fixes - wait for vbl for both profile and dynpm - unify profile and dynpm code paths more - call pm_misc before of after clocks to make sure voltage is changed in the proper order. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_pm.c | 75 ++++++++++++++---------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index a8d162c6f829..02281269a881 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -151,6 +151,7 @@ static void radeon_sync_with_vblank(struct radeon_device *rdev) static void radeon_set_power_state(struct radeon_device *rdev) { u32 sclk, mclk; + bool misc_after = false; if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) @@ -167,55 +168,47 @@ static void radeon_set_power_state(struct radeon_device *rdev) if (mclk > rdev->clock.default_mclk) mclk = rdev->clock.default_mclk; - /* voltage, pcie lanes, etc.*/ - radeon_pm_misc(rdev); + /* upvolt before raising clocks, downvolt after lowering clocks */ + if (sclk < rdev->pm.current_sclk) + misc_after = true; - if (rdev->pm.pm_method == PM_METHOD_DYNPM) { - radeon_sync_with_vblank(rdev); + radeon_sync_with_vblank(rdev); + if (rdev->pm.pm_method == PM_METHOD_DYNPM) { if (!radeon_pm_in_vbl(rdev)) return; + } - radeon_pm_prepare(rdev); - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_sclk = sclk; - DRM_DEBUG("Setting: e: %d\n", sclk); - } + radeon_pm_prepare(rdev); - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_pm_debug_check_in_vbl(rdev, false); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_debug_check_in_vbl(rdev, true); - rdev->pm.current_mclk = mclk; - DRM_DEBUG("Setting: m: %d\n", mclk); - } - radeon_pm_finish(rdev); - } else { - /* set engine clock */ - if (sclk != rdev->pm.current_sclk) { - radeon_sync_with_vblank(rdev); - radeon_pm_prepare(rdev); - radeon_set_engine_clock(rdev, sclk); - radeon_pm_finish(rdev); - rdev->pm.current_sclk = sclk; - DRM_DEBUG("Setting: e: %d\n", sclk); - } - /* set memory clock */ - if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { - radeon_sync_with_vblank(rdev); - radeon_pm_prepare(rdev); - radeon_set_memory_clock(rdev, mclk); - radeon_pm_finish(rdev); - rdev->pm.current_mclk = mclk; - DRM_DEBUG("Setting: m: %d\n", mclk); - } + if (!misc_after) + /* voltage, pcie lanes, etc.*/ + radeon_pm_misc(rdev); + + /* set engine clock */ + if (sclk != rdev->pm.current_sclk) { + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_engine_clock(rdev, sclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_sclk = sclk; + DRM_DEBUG("Setting: e: %d\n", sclk); + } + + /* set memory clock */ + if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { + radeon_pm_debug_check_in_vbl(rdev, false); + radeon_set_memory_clock(rdev, mclk); + radeon_pm_debug_check_in_vbl(rdev, true); + rdev->pm.current_mclk = mclk; + DRM_DEBUG("Setting: m: %d\n", mclk); } + if (misc_after) + /* voltage, pcie lanes, etc.*/ + radeon_pm_misc(rdev); + + radeon_pm_finish(rdev); + rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; } else -- GitLab From 84d88f4c92763f519b9e081cdd685a44de14f8c0 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Thu, 27 May 2010 17:01:42 -0400 Subject: [PATCH 555/842] drm/radeon/kms/pm: voltage fixes - Enable GPIO voltage for non pm modes as well so resetting the default voltage works. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_atombios.c | 9 ++++++--- drivers/gpu/drm/radeon/radeon_combios.c | 7 ++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 42bcaf41b8c4..4305cd55d0ac 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1538,7 +1538,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state[state_index].pcie_lanes = power_info->info.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); - if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || + (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = @@ -1605,7 +1606,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); - if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || + (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = @@ -1679,7 +1681,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); - if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) { + if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || + (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO; rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 7b5e10d3e9c9..102c744eaf5a 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2454,7 +2454,12 @@ default_mode: rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk; rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; - rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; + if ((state_index > 0) && + (rdev->pm.power_state[0].clock_info[0].voltage.type = VOLTAGE_GPIO)) + rdev->pm.power_state[state_index].clock_info[0].voltage = + rdev->pm.power_state[0].clock_info[0].voltage; + else + rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; rdev->pm.power_state[state_index].pcie_lanes = 16; rdev->pm.power_state[state_index].flags = 0; rdev->pm.default_power_state_index = state_index; -- GitLab From ce04cc089b22862f7d6ad5aa3ada0dd07e41b833 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser <nikai@nikai.net> Date: Fri, 28 May 2010 07:33:49 +0200 Subject: [PATCH 556/842] drm: fix typos in Linux DRM Developer's Guide A few typos in the DRM Developer's Guide. Signed-off-by: Nicolas Kaiser <nikai@nikai.net> Acked-by: Jesse Barnes <jesse.barnes@intel.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- Documentation/DocBook/drm.tmpl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 7583dc7cf64d..910c923a9b86 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -389,7 +389,7 @@ </para> <para> If your driver supports memory management (it should!), you'll - need to set that up at load time as well. How you intialize + need to set that up at load time as well. How you initialize it depends on which memory manager you're using, TTM or GEM. </para> <sect3> @@ -399,7 +399,7 @@ aperture space for graphics devices. TTM supports both UMA devices and devices with dedicated video RAM (VRAM), i.e. most discrete graphics devices. If your device has dedicated RAM, supporting - TTM is desireable. TTM also integrates tightly with your + TTM is desirable. TTM also integrates tightly with your driver specific buffer execution function. See the radeon driver for examples. </para> @@ -443,7 +443,7 @@ likely eventually calling ttm_bo_global_init and ttm_bo_global_release, respectively. Also like the previous object, ttm_global_item_ref is used to create an initial reference - count for the TTM, which will call your initalization function. + count for the TTM, which will call your initialization function. </para> </sect3> <sect3> @@ -557,7 +557,7 @@ void intel_crt_init(struct drm_device *dev) CRT connector and encoder combination is created. A device specific i2c bus is also created, for fetching EDID data and performing monitor detection. Once the process is complete, - the new connector is regsitered with sysfs, to make its + the new connector is registered with sysfs, to make its properties available to applications. </para> <sect4> @@ -581,12 +581,12 @@ void intel_crt_init(struct drm_device *dev) <para> For each encoder, CRTC and connector, several functions must be provided, depending on the object type. Encoder objects - need should provide a DPMS (basically on/off) function, mode fixup + need to provide a DPMS (basically on/off) function, mode fixup (for converting requested modes into native hardware timings), and prepare, set and commit functions for use by the core DRM helper functions. Connector helpers need to provide mode fetch and validity functions as well as an encoder matching function for - returing an ideal encoder for a given connector. The core + returning an ideal encoder for a given connector. The core connector functions include a DPMS callback, (deprecated) save/restore routines, detection, mode probing, property handling, and cleanup functions. -- GitLab From 2d6e9b91971034103ac51b20fa692258bf6bdd40 Mon Sep 17 00:00:00 2001 From: Tiago Vignatti <tiago.vignatti@nokia.com> Date: Mon, 24 May 2010 18:24:30 +0300 Subject: [PATCH 557/842] vgaarb: convert pr_devel() to pr_debug() We want to be able to use CONFIG_DYNAMIC_DEBUG in arbiter code, switch the few existing pr_devel() calls to pr_debug(). Also, add one more debug information regarding decoding count. Signed-off-by: Tiago Vignatti <tiago.vignatti@nokia.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/vga/vgaarb.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 441e38c95a85..290b0ccea63d 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -155,8 +155,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, (vgadev->decodes & VGA_RSRC_LEGACY_MEM)) rsrc |= VGA_RSRC_LEGACY_MEM; - pr_devel("%s: %d\n", __func__, rsrc); - pr_devel("%s: owns: %d\n", __func__, vgadev->owns); + pr_debug("%s: %d\n", __func__, rsrc); + pr_debug("%s: owns: %d\n", __func__, vgadev->owns); /* Check what resources we need to acquire */ wants = rsrc & ~vgadev->owns; @@ -268,7 +268,7 @@ static void __vga_put(struct vga_device *vgadev, unsigned int rsrc) { unsigned int old_locks = vgadev->locks; - pr_devel("%s\n", __func__); + pr_debug("%s\n", __func__); /* Update our counters, and account for equivalent legacy resources * if we decode them @@ -575,6 +575,7 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev, else vga_decode_count--; } + pr_debug("vgaarb: decoding count now is: %d\n", vga_decode_count); } void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace) @@ -831,7 +832,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, curr_pos += 5; remaining -= 5; - pr_devel("client 0x%p called 'lock'\n", priv); + pr_debug("client 0x%p called 'lock'\n", priv); if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { ret_val = -EPROTO; @@ -867,7 +868,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, curr_pos += 7; remaining -= 7; - pr_devel("client 0x%p called 'unlock'\n", priv); + pr_debug("client 0x%p called 'unlock'\n", priv); if (strncmp(curr_pos, "all", 3) == 0) io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; @@ -917,7 +918,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, curr_pos += 8; remaining -= 8; - pr_devel("client 0x%p called 'trylock'\n", priv); + pr_debug("client 0x%p called 'trylock'\n", priv); if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { ret_val = -EPROTO; @@ -961,7 +962,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, curr_pos += 7; remaining -= 7; - pr_devel("client 0x%p called 'target'\n", priv); + pr_debug("client 0x%p called 'target'\n", priv); /* if target is default */ if (!strncmp(curr_pos, "default", 7)) pdev = pci_dev_get(vga_default_device()); @@ -971,11 +972,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, ret_val = -EPROTO; goto done; } - pr_devel("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos, + pr_debug("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos, domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); pbus = pci_find_bus(domain, bus); - pr_devel("vgaarb: pbus %p\n", pbus); + pr_debug("vgaarb: pbus %p\n", pbus); if (pbus == NULL) { pr_err("vgaarb: invalid PCI domain and/or bus address %x:%x\n", domain, bus); @@ -983,7 +984,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, goto done; } pdev = pci_get_slot(pbus, devfn); - pr_devel("vgaarb: pdev %p\n", pdev); + pr_debug("vgaarb: pdev %p\n", pdev); if (!pdev) { pr_err("vgaarb: invalid PCI address %x:%x\n", bus, devfn); @@ -993,7 +994,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, } vgadev = vgadev_find(pdev); - pr_devel("vgaarb: vgadev %p\n", vgadev); + pr_debug("vgaarb: vgadev %p\n", vgadev); if (vgadev == NULL) { pr_err("vgaarb: this pci device is not a vga device\n"); pci_dev_put(pdev); @@ -1029,7 +1030,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, } else if (strncmp(curr_pos, "decodes ", 8) == 0) { curr_pos += 8; remaining -= 8; - pr_devel("vgaarb: client 0x%p called 'decodes'\n", priv); + pr_debug("vgaarb: client 0x%p called 'decodes'\n", priv); if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { ret_val = -EPROTO; @@ -1058,7 +1059,7 @@ static unsigned int vga_arb_fpoll(struct file *file, poll_table * wait) { struct vga_arb_private *priv = file->private_data; - pr_devel("%s\n", __func__); + pr_debug("%s\n", __func__); if (priv == NULL) return -ENODEV; @@ -1071,7 +1072,7 @@ static int vga_arb_open(struct inode *inode, struct file *file) struct vga_arb_private *priv; unsigned long flags; - pr_devel("%s\n", __func__); + pr_debug("%s\n", __func__); priv = kmalloc(sizeof(struct vga_arb_private), GFP_KERNEL); if (priv == NULL) @@ -1101,7 +1102,7 @@ static int vga_arb_release(struct inode *inode, struct file *file) unsigned long flags; int i; - pr_devel("%s\n", __func__); + pr_debug("%s\n", __func__); if (priv == NULL) return -ENODEV; @@ -1112,7 +1113,7 @@ static int vga_arb_release(struct inode *inode, struct file *file) uc = &priv->cards[i]; if (uc->pdev == NULL) continue; - pr_devel("uc->io_cnt == %d, uc->mem_cnt == %d\n", + pr_debug("uc->io_cnt == %d, uc->mem_cnt == %d\n", uc->io_cnt, uc->mem_cnt); while (uc->io_cnt--) vga_put(uc->pdev, VGA_RSRC_LEGACY_IO); @@ -1165,7 +1166,7 @@ static int pci_notify(struct notifier_block *nb, unsigned long action, struct pci_dev *pdev = to_pci_dev(dev); bool notify = false; - pr_devel("%s\n", __func__); + pr_debug("%s\n", __func__); /* For now we're only intereted in devices added and removed. I didn't * test this thing here, so someone needs to double check for the -- GitLab From c0db9cbc73338d8e2987a19a02388d67aeec0bfe Mon Sep 17 00:00:00 2001 From: Tiago Vignatti <tiago.vignatti@nokia.com> Date: Mon, 24 May 2010 18:24:31 +0300 Subject: [PATCH 558/842] vgaarb: use MIT license Signed-off-by: Tiago Vignatti <tiago.vignatti@nokia.com> Cc: Henry Zhao <Henry.Zhao@Sun.COM> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/vga/vgaarb.c | 26 +++++++++++++++++++++++--- include/linux/vgaarb.h | 21 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 290b0ccea63d..b87569e96b16 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -1,12 +1,32 @@ /* - * vgaarb.c + * vgaarb.c: Implements the VGA arbitration. For details refer to + * Documentation/vgaarbiter.txt + * * * (C) Copyright 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org> * (C) Copyright 2007 Paulo R. Zanoni <przanoni@gmail.com> * (C) Copyright 2007, 2009 Tiago Vignatti <vignatti@freedesktop.org> * - * Implements the VGA arbitration. For details refer to - * Documentation/vgaarbiter.txt + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS + * IN THE SOFTWARE. + * */ #include <linux/module.h> diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h index 2dfaa293ae8c..c9a975976995 100644 --- a/include/linux/vgaarb.h +++ b/include/linux/vgaarb.h @@ -5,6 +5,27 @@ * (C) Copyright 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org> * (C) Copyright 2007 Paulo R. Zanoni <przanoni@gmail.com> * (C) Copyright 2007, 2009 Tiago Vignatti <vignatti@freedesktop.org> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS + * IN THE SOFTWARE. + * */ #ifndef LINUX_VGA_H -- GitLab From 7c4f77801f103c9eb0465bf42313d5e1721d2991 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Tue, 1 Jun 2010 11:38:17 +0200 Subject: [PATCH 559/842] drm/vmwgfx: Fix vga save / restore with display topology. vga save / restore previously didn't handle the display topology case. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 15 ++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 48 +++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 1341adef408d..e577af5bb3d6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -47,6 +47,7 @@ #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 #define VMWGFX_MAX_GMRS 2048 +#define VMWGFX_MAX_DISPLAYS 16 struct vmw_fpriv { struct drm_master *locked_master; @@ -152,6 +153,14 @@ struct vmw_master { struct ttm_lock lock; }; +struct vmw_vga_topology_state { + uint32_t width; + uint32_t height; + uint32_t primary; + uint32_t pos_x; + uint32_t pos_y; +}; + struct vmw_private { struct ttm_bo_device bdev; struct ttm_bo_global_ref bo_global_ref; @@ -179,16 +188,20 @@ struct vmw_private { * VGA registers. */ + struct vmw_vga_topology_state vga_save[VMWGFX_MAX_DISPLAYS]; uint32_t vga_width; uint32_t vga_height; uint32_t vga_depth; uint32_t vga_bpp; uint32_t vga_pseudo; uint32_t vga_red_mask; - uint32_t vga_blue_mask; uint32_t vga_green_mask; + uint32_t vga_blue_mask; + uint32_t vga_bpl; uint32_t vga_pitchlock; + uint32_t num_displays; + /* * Framebuffer info. */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index b78dcf001858..648ba044f6f8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -865,30 +865,52 @@ void vmw_kms_write_svga(struct vmw_private *vmw_priv, int vmw_kms_save_vga(struct vmw_private *vmw_priv) { + struct vmw_vga_topology_state *save; + uint32_t i; + vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH); vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT); - vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); vmw_priv->vga_depth = vmw_read(vmw_priv, SVGA_REG_DEPTH); + vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); vmw_priv->vga_pseudo = vmw_read(vmw_priv, SVGA_REG_PSEUDOCOLOR); vmw_priv->vga_red_mask = vmw_read(vmw_priv, SVGA_REG_RED_MASK); - vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK); vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_MASK); + vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK); if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) vmw_priv->vga_pitchlock = - vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); + vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); else if (vmw_fifo_have_pitchlock(vmw_priv)) - vmw_priv->vga_pitchlock = - ioread32(vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); + vmw_priv->vga_pitchlock = ioread32(vmw_priv->mmio_virt + + SVGA_FIFO_PITCHLOCK); + + if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) + return 0; + vmw_priv->num_displays = vmw_read(vmw_priv, + SVGA_REG_NUM_GUEST_DISPLAYS); + + for (i = 0; i < vmw_priv->num_displays; ++i) { + save = &vmw_priv->vga_save[i]; + vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i); + save->primary = vmw_read(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY); + save->pos_x = vmw_read(vmw_priv, SVGA_REG_DISPLAY_POSITION_X); + save->pos_y = vmw_read(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y); + save->width = vmw_read(vmw_priv, SVGA_REG_DISPLAY_WIDTH); + save->height = vmw_read(vmw_priv, SVGA_REG_DISPLAY_HEIGHT); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); + } return 0; } int vmw_kms_restore_vga(struct vmw_private *vmw_priv) { + struct vmw_vga_topology_state *save; + uint32_t i; + vmw_write(vmw_priv, SVGA_REG_WIDTH, vmw_priv->vga_width); vmw_write(vmw_priv, SVGA_REG_HEIGHT, vmw_priv->vga_height); - vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp); vmw_write(vmw_priv, SVGA_REG_DEPTH, vmw_priv->vga_depth); + vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp); vmw_write(vmw_priv, SVGA_REG_PSEUDOCOLOR, vmw_priv->vga_pseudo); vmw_write(vmw_priv, SVGA_REG_RED_MASK, vmw_priv->vga_red_mask); vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, vmw_priv->vga_green_mask); @@ -900,5 +922,19 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv) iowrite32(vmw_priv->vga_pitchlock, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); + if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) + return 0; + + for (i = 0; i < vmw_priv->num_displays; ++i) { + save = &vmw_priv->vga_save[i]; + vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, save->primary); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, save->pos_x); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, save->pos_y); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, save->width); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, save->height); + vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); + } + return 0; } -- GitLab From 991b7b44f8cfa1b9beff8c4c2f2ec888b925c2a7 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Tue, 1 Jun 2010 11:38:16 +0200 Subject: [PATCH 560/842] drm/vmwgfx: Fix framebuffer modesetting Must set SVGA_NUM_REG_GUEST_DISPLAY before setting up the display information. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 181f47222580..b0866f04ec76 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -152,20 +152,12 @@ static int vmw_fb_set_par(struct fb_info *info) struct vmw_fb_par *par = info->par; struct vmw_private *vmw_priv = par->vmw_priv; + vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, + info->fix.line_length, + par->bpp, par->depth); if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) { - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - - vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, - info->fix.line_length, - par->bpp, par->depth); - /* TODO check if pitch and offset changes */ + vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, info->var.xoffset); @@ -173,12 +165,6 @@ static int vmw_fb_set_par(struct fb_info *info) vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); - } else { - vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, - info->fix.line_length, - par->bpp, par->depth); - } /* This is really helpful since if this fails the user -- GitLab From d8bd19d2aff95e52c7f356cc2fc722584a656065 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz <jakob@vmware.com> Date: Tue, 1 Jun 2010 11:54:20 +0200 Subject: [PATCH 561/842] drm/vmwgfx: Allow userspace to change default layout. Bump minor. The host may change the layout and, since the change is communicated to the master, the master needs a way to communicate the change to the kernel driver. The minor version number is bumped to advertize the availability of this feature. Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 7 ++- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 45 ++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 83 ++++++++++++++++++++++++++--- include/drm/vmwgfx_drm.h | 26 +++++++++ 6 files changed, 160 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 7597323d5a5a..b793c8c9acb3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -88,6 +88,9 @@ #define DRM_IOCTL_VMW_FENCE_WAIT \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT, \ struct drm_vmw_fence_wait_arg) +#define DRM_IOCTL_VMW_UPDATE_LAYOUT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT, \ + struct drm_vmw_update_layout_arg) /** @@ -135,7 +138,9 @@ static struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl, DRM_AUTH | DRM_ROOT_ONLY | DRM_MASTER | DRM_UNLOCKED), VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl, - DRM_AUTH | DRM_UNLOCKED) + DRM_AUTH | DRM_UNLOCKED), + VMW_IOCTL_DEF(DRM_IOCTL_VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl, + DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED) }; static struct pci_device_id vmw_pci_id_list[] = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index e577af5bb3d6..eaad52095339 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -41,7 +41,7 @@ #define VMWGFX_DRIVER_DATE "20100209" #define VMWGFX_DRIVER_MAJOR 1 -#define VMWGFX_DRIVER_MINOR 1 +#define VMWGFX_DRIVER_MINOR 2 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) @@ -509,6 +509,8 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, void vmw_kms_write_svga(struct vmw_private *vmw_priv, unsigned width, unsigned height, unsigned pitch, unsigned bbp, unsigned depth); +int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /** * Overlay control - vmwgfx_overlay.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 648ba044f6f8..f1d626112415 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -938,3 +938,48 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv) return 0; } + +int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct drm_vmw_update_layout_arg *arg = + (struct drm_vmw_update_layout_arg *)data; + struct vmw_master *vmaster = vmw_master(file_priv->master); + void __user *user_rects; + struct drm_vmw_rect *rects; + unsigned rects_size; + int ret; + + ret = ttm_read_lock(&vmaster->lock, true); + if (unlikely(ret != 0)) + return ret; + + if (!arg->num_outputs) { + struct drm_vmw_rect def_rect = {0, 0, 800, 600}; + vmw_kms_ldu_update_layout(dev_priv, 1, &def_rect); + goto out_unlock; + } + + rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect); + rects = kzalloc(rects_size, GFP_KERNEL); + if (unlikely(!rects)) { + ret = -ENOMEM; + goto out_unlock; + } + + user_rects = (void __user *)(unsigned long)arg->rects; + ret = copy_from_user(rects, user_rects, rects_size); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed to get rects.\n"); + goto out_free; + } + + vmw_kms_ldu_update_layout(dev_priv, arg->num_outputs, rects); + +out_free: + kfree(rects); +out_unlock: + ttm_read_unlock(&vmaster->lock); + return ret; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 8b95249f0531..8a398a0339b6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -94,9 +94,11 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); /* - * Legacy display unit functions - vmwgfx_ldu.h + * Legacy display unit functions - vmwgfx_ldu.c */ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv); int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv); +int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num, + struct drm_vmw_rect *rects); #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index f7094dde18f9..cfaf690a5b2f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -49,6 +49,11 @@ struct vmw_legacy_display { struct vmw_legacy_display_unit { struct vmw_display_unit base; + unsigned pref_width; + unsigned pref_height; + bool pref_active; + struct drm_display_mode *pref_mode; + struct list_head active; }; @@ -332,8 +337,7 @@ static void vmw_ldu_connector_restore(struct drm_connector *connector) static enum drm_connector_status vmw_ldu_connector_detect(struct drm_connector *connector) { - /* XXX vmwctrl should control connection status */ - if (vmw_connector_to_ldu(connector)->base.unit == 0) + if (vmw_connector_to_ldu(connector)->pref_active) return connector_status_connected; return connector_status_disconnected; } @@ -344,10 +348,9 @@ static struct drm_display_mode vmw_ldu_connector_builtin[] = { 752, 800, 0, 480, 489, 492, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 800x600@60Hz */ - { DRM_MODE("800x600", - DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, - 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, - 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, + 968, 1056, 0, 600, 601, 605, 628, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@60Hz */ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, @@ -419,10 +422,34 @@ static struct drm_display_mode vmw_ldu_connector_builtin[] = { static int vmw_ldu_connector_fill_modes(struct drm_connector *connector, uint32_t max_width, uint32_t max_height) { + struct vmw_legacy_display_unit *ldu = vmw_connector_to_ldu(connector); struct drm_device *dev = connector->dev; struct drm_display_mode *mode = NULL; + struct drm_display_mode prefmode = { DRM_MODE("preferred", + DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) + }; int i; + /* Add preferred mode */ + { + mode = drm_mode_duplicate(dev, &prefmode); + if (!mode) + return 0; + mode->hdisplay = ldu->pref_width; + mode->vdisplay = ldu->pref_height; + mode->vrefresh = drm_mode_vrefresh(mode); + drm_mode_probed_add(connector, mode); + + if (ldu->pref_mode) { + list_del_init(&ldu->pref_mode->head); + drm_mode_destroy(dev, ldu->pref_mode); + } + + ldu->pref_mode = mode; + } + for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) { if (vmw_ldu_connector_builtin[i].hdisplay > max_width || vmw_ldu_connector_builtin[i].vdisplay > max_height) @@ -482,6 +509,11 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) INIT_LIST_HEAD(&ldu->active); + ldu->pref_active = (unit == 0); + ldu->pref_width = 800; + ldu->pref_height = 600; + ldu->pref_mode = NULL; + drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, DRM_MODE_CONNECTOR_LVDS); connector->status = vmw_ldu_connector_detect(connector); @@ -546,3 +578,42 @@ int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv) return 0; } + +int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num, + struct drm_vmw_rect *rects) +{ + struct drm_device *dev = dev_priv->dev; + struct vmw_legacy_display_unit *ldu; + struct drm_connector *con; + int i; + + mutex_lock(&dev->mode_config.mutex); + +#if 0 + DRM_INFO("%s: new layout ", __func__); + for (i = 0; i < (int)num; i++) + DRM_INFO("(%i, %i %ux%u) ", rects[i].x, rects[i].y, + rects[i].w, rects[i].h); + DRM_INFO("\n"); +#else + (void)i; +#endif + + list_for_each_entry(con, &dev->mode_config.connector_list, head) { + ldu = vmw_connector_to_ldu(con); + if (num > ldu->base.unit) { + ldu->pref_width = rects[ldu->base.unit].w; + ldu->pref_height = rects[ldu->base.unit].h; + ldu->pref_active = true; + } else { + ldu->pref_width = 800; + ldu->pref_height = 600; + ldu->pref_active = false; + } + con->status = vmw_ldu_connector_detect(con); + } + + mutex_unlock(&dev->mode_config.mutex); + + return 0; +} diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h index c7645f480d12..4d0842391edc 100644 --- a/include/drm/vmwgfx_drm.h +++ b/include/drm/vmwgfx_drm.h @@ -50,6 +50,8 @@ #define DRM_VMW_EXECBUF 12 #define DRM_VMW_FIFO_DEBUG 13 #define DRM_VMW_FENCE_WAIT 14 +/* guarded by minor version >= 2 */ +#define DRM_VMW_UPDATE_LAYOUT 15 /*************************************************************************/ @@ -585,4 +587,28 @@ struct drm_vmw_stream_arg { * sure that the stream has been stopped. */ +/*************************************************************************/ +/** + * DRM_VMW_UPDATE_LAYOUT - Update layout + * + * Updates the prefered modes and connection status for connectors. The + * command conisits of one drm_vmw_update_layout_arg pointing out a array + * of num_outputs drm_vmw_rect's. + */ + +/** + * struct drm_vmw_update_layout_arg + * + * @num_outputs: number of active + * @rects: pointer to array of drm_vmw_rect + * + * Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl. + */ + +struct drm_vmw_update_layout_arg { + uint32_t num_outputs; + uint32_t pad64; + uint64_t rects; +}; + #endif -- GitLab From d8dcaa1dc50f5aecd38d34180cd99d6af8566c88 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Wed, 2 Jun 2010 12:08:41 -0400 Subject: [PATCH 562/842] drm/radeon/kms: make sure display hw is disabled when suspending Disable the display hw when suspending. Should fix bug: https://bugzilla.redhat.com/show_bug.cgi?id=522393 Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_device.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index db338522191f..f10faed21567 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -713,6 +713,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) { struct radeon_device *rdev; struct drm_crtc *crtc; + struct drm_connector *connector; int r; if (dev == NULL || dev->dev_private == NULL) { @@ -725,6 +726,12 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) if (rdev->powered_down) return 0; + + /* turn off display hw */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + } + /* unpin the front buffers */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb); -- GitLab From ee227c577cde47f78e2df359f9c32ba047060767 Mon Sep 17 00:00:00 2001 From: Wolfram Sang <w.sang@pengutronix.de> Date: Thu, 3 Jun 2010 06:03:46 +0200 Subject: [PATCH 563/842] of/powerpc: fix fsl_msi device node pointer Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca> --- arch/powerpc/sysdev/fsl_msi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 0f5bee90ee4e..962c2d8dd8d9 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -347,7 +347,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, goto error_out; } offset = 0; - p = of_get_property(dev->node, "msi-available-ranges", &len); + p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); if (p) offset = *p / IRQS_PER_MSI_REG; -- GitLab From 5b257b4a1f9239624c6b5e669763de04e482c2b3 Mon Sep 17 00:00:00 2001 From: Dave Chinner <david@fromorbit.com> Date: Thu, 3 Jun 2010 16:22:29 +1000 Subject: [PATCH 564/842] xfs: fix race in inode cluster freeing failing to stale inodes When an inode cluster is freed, it needs to mark all inodes in memory as XFS_ISTALE before marking the buffer as stale. This is eeded because the inodes have a different life cycle to the buffer, and once the buffer is torn down during transaction completion, we must ensure none of the inodes get written back (which is what XFS_ISTALE does). Unfortunately, xfs_ifree_cluster() has some bugs that lead to inodes not being marked with XFS_ISTALE. This shows up when xfs_iflush() is called on these inodes either during inode reclaim or tail pushing on the AIL. The buffer is read back, but no longer contains inodes and so triggers assert failures and shutdowns. This was reproducable with at run.dbench10 invocation from xfstests. There are two main causes of xfs_ifree_cluster() failing. The first is simple - it checks in-memory inodes it finds in the per-ag icache to see if they are clean without holding the flush lock. if they are clean it skips them completely. However, If an inode is flushed delwri, it will appear clean, but is not guaranteed to be written back until the flush lock has been dropped. Hence we may have raced on the clean check and the inode may actually be dirty. Hence always mark inodes found in memory stale before we check properly if they are clean. The second is more complex, and makes the first problem easier to hit. Basically the in-memory inode scan is done with full knowledge it can be racing with inode flushing and AIl tail pushing, which means that inodes that it can't get the flush lock on might not be attached to the buffer after then in-memory inode scan due to IO completion occurring. This is actually documented in the code as "needs better interlocking". i.e. this is a zero-day bug. Effectively, the in-memory scan must be done while the inode buffer is locked and Io cannot be issued on it while we do the in-memory inode scan. This ensures that inodes we couldn't get the flush lock on are guaranteed to be attached to the cluster buffer, so we can then catch all in-memory inodes and mark them stale. Now that the inode cluster buffer is locked before the in-memory scan is done, there is no need for the two-phase update of the in-memory inodes, so simplify the code into two loops and remove the allocation of the temporary buffer used to hold locked inodes across the phases. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> --- fs/xfs/xfs_inode.c | 142 ++++++++++++++++++++------------------------- 1 file changed, 62 insertions(+), 80 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 6ba7765026f6..d53c39de7d05 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1940,10 +1940,10 @@ xfs_ifree_cluster( int blks_per_cluster; int nbufs; int ninodes; - int i, j, found, pre_flushed; + int i, j; xfs_daddr_t blkno; xfs_buf_t *bp; - xfs_inode_t *ip, **ip_found; + xfs_inode_t *ip; xfs_inode_log_item_t *iip; xfs_log_item_t *lip; struct xfs_perag *pag; @@ -1960,114 +1960,97 @@ xfs_ifree_cluster( nbufs = XFS_IALLOC_BLOCKS(mp) / blks_per_cluster; } - ip_found = kmem_alloc(ninodes * sizeof(xfs_inode_t *), KM_NOFS); - for (j = 0; j < nbufs; j++, inum += ninodes) { + int found = 0; + blkno = XFS_AGB_TO_DADDR(mp, XFS_INO_TO_AGNO(mp, inum), XFS_INO_TO_AGBNO(mp, inum)); + /* + * We obtain and lock the backing buffer first in the process + * here, as we have to ensure that any dirty inode that we + * can't get the flush lock on is attached to the buffer. + * If we scan the in-memory inodes first, then buffer IO can + * complete before we get a lock on it, and hence we may fail + * to mark all the active inodes on the buffer stale. + */ + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, + mp->m_bsize * blks_per_cluster, + XBF_LOCK); + + /* + * Walk the inodes already attached to the buffer and mark them + * stale. These will all have the flush locks held, so an + * in-memory inode walk can't lock them. + */ + lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + while (lip) { + if (lip->li_type == XFS_LI_INODE) { + iip = (xfs_inode_log_item_t *)lip; + ASSERT(iip->ili_logged == 1); + lip->li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*)) xfs_istale_done; + xfs_trans_ail_copy_lsn(mp->m_ail, + &iip->ili_flush_lsn, + &iip->ili_item.li_lsn); + xfs_iflags_set(iip->ili_inode, XFS_ISTALE); + found++; + } + lip = lip->li_bio_list; + } /* - * Look for each inode in memory and attempt to lock it, - * we can be racing with flush and tail pushing here. - * any inode we get the locks on, add to an array of - * inode items to process later. + * For each inode in memory attempt to add it to the inode + * buffer and set it up for being staled on buffer IO + * completion. This is safe as we've locked out tail pushing + * and flushing by locking the buffer. * - * The get the buffer lock, we could beat a flush - * or tail pushing thread to the lock here, in which - * case they will go looking for the inode buffer - * and fail, we need some other form of interlock - * here. + * We have already marked every inode that was part of a + * transaction stale above, which means there is no point in + * even trying to lock them. */ - found = 0; for (i = 0; i < ninodes; i++) { read_lock(&pag->pag_ici_lock); ip = radix_tree_lookup(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, (inum + i))); - /* Inode not in memory or we found it already, - * nothing to do - */ + /* Inode not in memory or stale, nothing to do */ if (!ip || xfs_iflags_test(ip, XFS_ISTALE)) { read_unlock(&pag->pag_ici_lock); continue; } - if (xfs_inode_clean(ip)) { - read_unlock(&pag->pag_ici_lock); - continue; - } - - /* If we can get the locks then add it to the - * list, otherwise by the time we get the bp lock - * below it will already be attached to the - * inode buffer. - */ - - /* This inode will already be locked - by us, lets - * keep it that way. - */ - - if (ip == free_ip) { - if (xfs_iflock_nowait(ip)) { - xfs_iflags_set(ip, XFS_ISTALE); - if (xfs_inode_clean(ip)) { - xfs_ifunlock(ip); - } else { - ip_found[found++] = ip; - } - } + /* don't try to lock/unlock the current inode */ + if (ip != free_ip && + !xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { read_unlock(&pag->pag_ici_lock); continue; } + read_unlock(&pag->pag_ici_lock); - if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { - if (xfs_iflock_nowait(ip)) { - xfs_iflags_set(ip, XFS_ISTALE); - - if (xfs_inode_clean(ip)) { - xfs_ifunlock(ip); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - } else { - ip_found[found++] = ip; - } - } else { + if (!xfs_iflock_nowait(ip)) { + if (ip != free_ip) xfs_iunlock(ip, XFS_ILOCK_EXCL); - } + continue; } - read_unlock(&pag->pag_ici_lock); - } - bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, - mp->m_bsize * blks_per_cluster, - XBF_LOCK); - - pre_flushed = 0; - lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); - while (lip) { - if (lip->li_type == XFS_LI_INODE) { - iip = (xfs_inode_log_item_t *)lip; - ASSERT(iip->ili_logged == 1); - lip->li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*)) xfs_istale_done; - xfs_trans_ail_copy_lsn(mp->m_ail, - &iip->ili_flush_lsn, - &iip->ili_item.li_lsn); - xfs_iflags_set(iip->ili_inode, XFS_ISTALE); - pre_flushed++; + xfs_iflags_set(ip, XFS_ISTALE); + if (xfs_inode_clean(ip)) { + ASSERT(ip != free_ip); + xfs_ifunlock(ip); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + continue; } - lip = lip->li_bio_list; - } - for (i = 0; i < found; i++) { - ip = ip_found[i]; iip = ip->i_itemp; - if (!iip) { + /* inode with unlogged changes only */ + ASSERT(ip != free_ip); ip->i_update_core = 0; xfs_ifunlock(ip); xfs_iunlock(ip, XFS_ILOCK_EXCL); continue; } + found++; iip->ili_last_fields = iip->ili_format.ilf_fields; iip->ili_format.ilf_fields = 0; @@ -2078,17 +2061,16 @@ xfs_ifree_cluster( xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t*,xfs_log_item_t*)) xfs_istale_done, (xfs_log_item_t *)iip); - if (ip != free_ip) { + + if (ip != free_ip) xfs_iunlock(ip, XFS_ILOCK_EXCL); - } } - if (found || pre_flushed) + if (found) xfs_trans_stale_inode_buf(tp, bp); xfs_trans_binval(tp, bp); } - kmem_free(ip_found); xfs_perag_put(pag); } -- GitLab From 99a4d54620264a614c89597bc5aaab22ec83f89c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig <hch@infradead.org> Date: Thu, 3 Jun 2010 16:22:29 +1000 Subject: [PATCH 565/842] xfs: remove done roadmap item from xfs-delayed-logging-design.txt Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> --- Documentation/filesystems/xfs-delayed-logging-design.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Documentation/filesystems/xfs-delayed-logging-design.txt b/Documentation/filesystems/xfs-delayed-logging-design.txt index d8119e9d2d60..96d0df28bed3 100644 --- a/Documentation/filesystems/xfs-delayed-logging-design.txt +++ b/Documentation/filesystems/xfs-delayed-logging-design.txt @@ -794,11 +794,6 @@ designed. Roadmap: -2.6.35 Inclusion in mainline as an experimental mount option - => approximately 2-3 months to merge window - => needs to be in xfs-dev tree in 4-6 weeks - => code is nearing readiness for review - 2.6.37 Remove experimental tag from mount option => should be roughly 6 months after initial merge => enough time to: -- GitLab From 070ecdca54dde9577d2697088e74e45568f48efb Mon Sep 17 00:00:00 2001 From: Christoph Hellwig <hch@infradead.org> Date: Thu, 3 Jun 2010 16:22:29 +1000 Subject: [PATCH 566/842] xfs: skip writeback from reclaim context Allowing writeback from reclaim context causes massive problems with stack overflows as we can call into the writeback code which tends to be a heavy stack user both in the generic code and XFS from random contexts that perform memory allocations. Follow the example of btrfs (and in slightly different form ext4) and refuse to write out data from reclaim context. This issue should really be handled by the VM so that we can tune better for this case, but until we get it sorted out there we have to hack around this in each filesystem with a complex writeback path. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> --- fs/xfs/linux-2.6/xfs_aops.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 089eaca860b4..a0fa3bf0d1bb 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -1332,6 +1332,21 @@ xfs_vm_writepage( trace_xfs_writepage(inode, page, 0); + /* + * Refuse to write the page out if we are called from reclaim context. + * + * This is primarily to avoid stack overflows when called from deep + * used stacks in random callers for direct reclaim, but disabling + * reclaim for kswap is a nice side-effect as kswapd causes rather + * suboptimal I/O patters, too. + * + * This should really be done by the core VM, but until that happens + * filesystems like XFS, btrfs and ext4 have to take care of this + * by themselves. + */ + if (current->flags & PF_MEMALLOC) + goto out_fail; + /* * We need a transaction if: * 1. There are delalloc buffers on the page -- GitLab From f9369729496a0f4c607a4cc1ea4dfeddbbfc505a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig <hch@infradead.org> Date: Thu, 3 Jun 2010 16:22:29 +1000 Subject: [PATCH 567/842] xfs: improve xfs_isilocked Use rwsem_is_locked to make the assertations for shared locks work. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> --- fs/xfs/xfs_iget.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index f44a367907a8..75df75f43d48 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -741,30 +741,24 @@ xfs_ilock_demote( } #ifdef DEBUG -/* - * Debug-only routine, without additional rw_semaphore APIs, we can - * now only answer requests regarding whether we hold the lock for write - * (reader state is outside our visibility, we only track writer state). - * - * Note: this means !xfs_isilocked would give false positives, so don't do that. - */ int xfs_isilocked( xfs_inode_t *ip, uint lock_flags) { - if ((lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) == - XFS_ILOCK_EXCL) { - if (!ip->i_lock.mr_writer) - return 0; + if (lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) { + if (!(lock_flags & XFS_ILOCK_SHARED)) + return !!ip->i_lock.mr_writer; + return rwsem_is_locked(&ip->i_lock.mr_lock); } - if ((lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) == - XFS_IOLOCK_EXCL) { - if (!ip->i_iolock.mr_writer) - return 0; + if (lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) { + if (!(lock_flags & XFS_IOLOCK_SHARED)) + return !!ip->i_iolock.mr_writer; + return rwsem_is_locked(&ip->i_iolock.mr_lock); } - return 1; + ASSERT(0); + return 0; } #endif -- GitLab From 5869d2c387e75814334697c9d702d91b7c63a308 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky <maximlevitsky@gmail.com> Date: Wed, 2 Jun 2010 18:22:48 +0300 Subject: [PATCH 568/842] mtd: Fix NAND submenu Move MTD_NAND_ECC and MTD_NAND_ECC_SMC above NAND memuconfig, to unbreak display in xconfig. This shouldn't change any dependencies. Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> --- drivers/mtd/nand/Kconfig | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 98a04b3c9526..ffc3720929f1 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,13 +1,3 @@ -menuconfig MTD_NAND - tristate "NAND Device Support" - depends on MTD - select MTD_NAND_IDS - select MTD_NAND_ECC - help - This enables support for accessing all type of NAND flash - devices. For further information see - <http://www.linux-mtd.infradead.org/doc/nand.html>. - config MTD_NAND_ECC tristate @@ -19,6 +9,17 @@ config MTD_NAND_ECC_SMC Software ECC according to the Smart Media Specification. The original Linux implementation had byte 0 and 1 swapped. + +menuconfig MTD_NAND + tristate "NAND Device Support" + depends on MTD + select MTD_NAND_IDS + select MTD_NAND_ECC + help + This enables support for accessing all type of NAND flash + devices. For further information see + <http://www.linux-mtd.infradead.org/doc/nand.html>. + if MTD_NAND config MTD_NAND_VERIFY_WRITE -- GitLab From 0f0a8fa735bbde4b0bc3e96e4bb2e5b380a324db Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin <agust@denx.de> Date: Thu, 3 Jun 2010 16:53:49 +1000 Subject: [PATCH 569/842] crypto: crypto4xx - Fix build breakage Fixes build error caused by the OF device_node pointer being moved into struct device Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> --- drivers/crypto/amcc/crypto4xx_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 9d65b371de64..983530ba04a7 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1158,7 +1158,7 @@ static int __init crypto4xx_probe(struct of_device *ofdev, struct device *dev = &ofdev->dev; struct crypto4xx_core_device *core_dev; - rc = of_address_to_resource(ofdev->node, 0, &res); + rc = of_address_to_resource(ofdev->dev.of_node, 0, &res); if (rc) return -ENODEV; @@ -1215,13 +1215,13 @@ static int __init crypto4xx_probe(struct of_device *ofdev, (unsigned long) dev); /* Register for Crypto isr, Crypto Engine IRQ */ - core_dev->irq = irq_of_parse_and_map(ofdev->node, 0); + core_dev->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); rc = request_irq(core_dev->irq, crypto4xx_ce_interrupt_handler, 0, core_dev->dev->name, dev); if (rc) goto err_request_irq; - core_dev->dev->ce_base = of_iomap(ofdev->node, 0); + core_dev->dev->ce_base = of_iomap(ofdev->dev.of_node, 0); if (!core_dev->dev->ce_base) { dev_err(dev, "failed to of_iomap\n"); goto err_iomap; -- GitLab From f324e4cb2cadd9a42932c8a158e761ae31b88e72 Mon Sep 17 00:00:00 2001 From: David Woodhouse <David.Woodhouse@intel.com> Date: Thu, 3 Jun 2010 08:03:39 +0100 Subject: [PATCH 570/842] jffs2: Fix in-core inode leaks on error paths Pointed out by Al Viro. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> --- fs/jffs2/dir.c | 115 ++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 7aa4417e085f..cb7ef34d384c 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -360,8 +360,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char /* Eeek. Wave bye bye */ mutex_unlock(&f->sem); jffs2_complete_reservation(c); - jffs2_clear_inode(inode); - return PTR_ERR(fn); + ret = PTR_ERR(fn); + goto fail; } /* We use f->target field to store the target path. */ @@ -370,8 +370,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); mutex_unlock(&f->sem); jffs2_complete_reservation(c); - jffs2_clear_inode(inode); - return -ENOMEM; + ret = -ENOMEM; + goto fail; } memcpy(f->target, target, targetlen + 1); @@ -386,30 +386,24 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char jffs2_complete_reservation(c); ret = jffs2_init_security(inode, dir_i); - if (ret) { - jffs2_clear_inode(inode); - return ret; - } + if (ret) + goto fail; + ret = jffs2_init_acl_post(inode); - if (ret) { - jffs2_clear_inode(inode); - return ret; - } + if (ret) + goto fail; ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); - if (ret) { - /* Eep. */ - jffs2_clear_inode(inode); - return ret; - } + if (ret) + goto fail; rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); - jffs2_clear_inode(inode); - return -ENOMEM; + ret = -ENOMEM; + goto fail; } dir_f = JFFS2_INODE_INFO(dir_i); @@ -437,8 +431,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); mutex_unlock(&dir_f->sem); - jffs2_clear_inode(inode); - return PTR_ERR(fd); + ret = PTR_ERR(fd); + goto fail; } dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); @@ -454,6 +448,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char d_instantiate(dentry, inode); return 0; + + fail: + make_bad_inode(inode); + iput(inode); + return ret; } @@ -519,8 +518,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) /* Eeek. Wave bye bye */ mutex_unlock(&f->sem); jffs2_complete_reservation(c); - jffs2_clear_inode(inode); - return PTR_ERR(fn); + ret = PTR_ERR(fn); + goto fail; } /* No data here. Only a metadata node, which will be obsoleted by the first data write @@ -531,30 +530,24 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) jffs2_complete_reservation(c); ret = jffs2_init_security(inode, dir_i); - if (ret) { - jffs2_clear_inode(inode); - return ret; - } + if (ret) + goto fail; + ret = jffs2_init_acl_post(inode); - if (ret) { - jffs2_clear_inode(inode); - return ret; - } + if (ret) + goto fail; ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); - if (ret) { - /* Eep. */ - jffs2_clear_inode(inode); - return ret; - } + if (ret) + goto fail; rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); - jffs2_clear_inode(inode); - return -ENOMEM; + ret = -ENOMEM; + goto fail; } dir_f = JFFS2_INODE_INFO(dir_i); @@ -582,8 +575,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); mutex_unlock(&dir_f->sem); - jffs2_clear_inode(inode); - return PTR_ERR(fd); + ret = PTR_ERR(fd); + goto fail; } dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); @@ -600,6 +593,11 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) d_instantiate(dentry, inode); return 0; + + fail: + make_bad_inode(inode); + iput(inode); + return ret; } static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) @@ -693,8 +691,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de /* Eeek. Wave bye bye */ mutex_unlock(&f->sem); jffs2_complete_reservation(c); - jffs2_clear_inode(inode); - return PTR_ERR(fn); + ret = PTR_ERR(fn); + goto fail; } /* No data here. Only a metadata node, which will be obsoleted by the first data write @@ -705,30 +703,24 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de jffs2_complete_reservation(c); ret = jffs2_init_security(inode, dir_i); - if (ret) { - jffs2_clear_inode(inode); - return ret; - } + if (ret) + goto fail; + ret = jffs2_init_acl_post(inode); - if (ret) { - jffs2_clear_inode(inode); - return ret; - } + if (ret) + goto fail; ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); - if (ret) { - /* Eep. */ - jffs2_clear_inode(inode); - return ret; - } + if (ret) + goto fail; rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); - jffs2_clear_inode(inode); - return -ENOMEM; + ret = -ENOMEM; + goto fail; } dir_f = JFFS2_INODE_INFO(dir_i); @@ -759,8 +751,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); mutex_unlock(&dir_f->sem); - jffs2_clear_inode(inode); - return PTR_ERR(fd); + ret = PTR_ERR(fd); + goto fail; } dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); @@ -777,6 +769,11 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de d_instantiate(dentry, inode); return 0; + + fail: + make_bad_inode(inode); + iput(inode); + return ret; } static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, -- GitLab From e72e6497e74811e01d72b4c1b7537b3aea3ee857 Mon Sep 17 00:00:00 2001 From: David Woodhouse <David.Woodhouse@intel.com> Date: Thu, 3 Jun 2010 08:09:12 +0100 Subject: [PATCH 571/842] jffs2: Fix NFS race by using insert_inode_locked() New inodes need to be locked as we're creating them, so they don't get used by other things (like NFSd) before they're ready. Pointed out by Al Viro. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> --- fs/jffs2/dir.c | 12 ++++++++++-- fs/jffs2/fs.c | 7 ++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index cb7ef34d384c..166062a68230 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -222,15 +222,18 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime)); jffs2_free_raw_inode(ri); - d_instantiate(dentry, inode); D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->pino_nlink, inode->i_mapping->nrpages)); + + d_instantiate(dentry, inode); + unlock_new_inode(inode); return 0; fail: make_bad_inode(inode); + unlock_new_inode(inode); iput(inode); jffs2_free_raw_inode(ri); return ret; @@ -447,10 +450,12 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char jffs2_complete_reservation(c); d_instantiate(dentry, inode); + unlock_new_inode(inode); return 0; fail: make_bad_inode(inode); + unlock_new_inode(inode); iput(inode); return ret; } @@ -592,10 +597,12 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) jffs2_complete_reservation(c); d_instantiate(dentry, inode); + unlock_new_inode(inode); return 0; fail: make_bad_inode(inode); + unlock_new_inode(inode); iput(inode); return ret; } @@ -767,11 +774,12 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de jffs2_complete_reservation(c); d_instantiate(dentry, inode); - + unlock_new_inode(inode); return 0; fail: make_bad_inode(inode); + unlock_new_inode(inode); iput(inode); return ret; } diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 86e0821fc989..26037e2d6154 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -465,7 +465,12 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i inode->i_blocks = 0; inode->i_size = 0; - insert_inode_hash(inode); + if (insert_inode_locked(inode) < 0) { + make_bad_inode(inode); + unlock_new_inode(inode); + iput(inode); + return ERR_PTR(-EINVAL); + } return inode; } -- GitLab From cbab05f041a4cff6ca15856bdd35238b282b64eb Mon Sep 17 00:00:00 2001 From: Richard Kennedy <richard@rsk.demon.co.uk> Date: Thu, 27 May 2010 10:22:28 +0100 Subject: [PATCH 572/842] gconfig: fix build failure on fedora 13 Making gconfig fails on fedora 13 as the linker cannot resolve dlsym. Adding libdl to the link command fixes this. make shows this error :- /usr/bin/ld: scripts/kconfig/kconfig_load.o: undefined reference to symbol 'dlsym@@GLIBC_2.2.5' /usr/bin/ld: note: 'dlsym@@GLIBC_2.2.5' is defined in DSO /lib64/libdl.so.2 so try adding it to the linker command line /lib64/libdl.so.2: could not read symbols: Invalid operation tested on x86_64 fedora 13. Signed-off-by: Richard Kennedy <richard@rsk.demon.co.uk> Reviewed-by: WANG Cong <xiyou.wangcong@gmail.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/kconfig/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 999e8a7d5bf7..25a518310038 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -198,7 +198,7 @@ HOSTCFLAGS_zconf.tab.o := -I$(src) HOSTLOADLIBES_qconf = $(KC_QT_LIBS) -ldl HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK -HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` +HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ -D LKC_DIRECT_LINK -- GitLab From cd52e17ea8278f8449b6174a8e5ed439a2e44ffb Mon Sep 17 00:00:00 2001 From: Ian Campbell <ian.campbell@citrix.com> Date: Wed, 19 May 2010 16:19:25 +0100 Subject: [PATCH 573/842] xen: ensure timer tick is resumed even on CPU driving the resume The core suspend/resume code is run from stop_machine on CPU0 but parts of the suspend/resume machinery (including xen_arch_resume) are run on whichever CPU happened to schedule the xenwatch kernel thread. As part of the non-core resume code xen_arch_resume is called in order to restart the timer tick on non-boot processors. The boot processor itself is taken care of by core timekeeping code. xen_arch_resume uses smp_call_function which does not call the given function on the current processor. This means that we can end up with one CPU not receiving timer ticks if the xenwatch thread happened to be scheduled on CPU > 0. Use on_each_cpu instead of smp_call_function to ensure the timer tick is resumed everywhere. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Jeremy Fitzhardinge <jeremy@goop.org> Cc: Stable Kernel <stable@kernel.org> # .32.x --- arch/x86/xen/suspend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index 987267f79bf5..a9c661108034 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c @@ -60,6 +60,6 @@ static void xen_vcpu_notify_restore(void *data) void xen_arch_resume(void) { - smp_call_function(xen_vcpu_notify_restore, - (void *)CLOCK_EVT_NOTIFY_RESUME, 1); + on_each_cpu(xen_vcpu_notify_restore, + (void *)CLOCK_EVT_NOTIFY_RESUME, 1); } -- GitLab From b3831cb55d383e8eb55d3b56c715fb48459b87c9 Mon Sep 17 00:00:00 2001 From: Ian Campbell <ian.campbell@citrix.com> Date: Tue, 25 May 2010 10:45:35 +0100 Subject: [PATCH 574/842] xen: avoid allocation causing potential swap activity on the resume path Since the device we are resuming could be the device containing the swap device we should ensure that the allocation cannot cause IO. On resume, this path is triggered when the running system tries to continue using its devices. If it cannot then the resume will fail; to try to avoid this we let it dip into the emergency pools. The majority of these changes were made when linux-2.6.18-xen.hg changeset e8b49cfbdac0 was ported upstream in a144ff09bc52ef3f3684ed23eadc9c7c0e57b3aa but somehow this hunk was dropped. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Jeremy Fitzhardinge <jeremy@goop.org> Cc: Stable Kernel <stable@kernel.org> # .32.x --- drivers/xen/xenbus/xenbus_xs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index eab33f1dbdf7..7b547f53f65e 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -499,7 +499,7 @@ int xenbus_printf(struct xenbus_transaction t, #define PRINTF_BUFFER_SIZE 4096 char *printf_buffer; - printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); + printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_NOIO | __GFP_HIGH); if (printf_buffer == NULL) return -ENOMEM; -- GitLab From 89140f41575ae2a7a5c24e856880594ccbdfcaff Mon Sep 17 00:00:00 2001 From: Andrea Gelmini <andrea.gelmini@gelma.net> Date: Thu, 3 Jun 2010 11:33:50 +0200 Subject: [PATCH 575/842] Documentation/i2c: Checkpatch cleanup Remove all trailing whitespace in Documentation/i2c. Signed-off-by: Andrea Gelmini <andrea.gelmini@gelma.net> Signed-off-by: Jean Delvare <khali@linux-fr.org> --- Documentation/i2c/busses/i2c-ali1535 | 4 +- Documentation/i2c/busses/i2c-ali1563 | 2 +- Documentation/i2c/busses/i2c-ali15x3 | 16 ++++---- Documentation/i2c/busses/i2c-pca-isa | 14 +++---- Documentation/i2c/busses/i2c-sis5595 | 58 ++++++++++++++-------------- Documentation/i2c/busses/i2c-sis630 | 8 ++-- Documentation/i2c/ten-bit-addresses | 6 +-- 7 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Documentation/i2c/busses/i2c-ali1535 b/Documentation/i2c/busses/i2c-ali1535 index 0db3b4c74ad1..acbc65a08097 100644 --- a/Documentation/i2c/busses/i2c-ali1535 +++ b/Documentation/i2c/busses/i2c-ali1535 @@ -6,12 +6,12 @@ Supported adapters: http://www.ali.com.tw/eng/support/datasheet_request.php Authors: - Frodo Looijaard <frodol@dds.nl>, + Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, Mark D. Studebaker <mdsxyz123@yahoo.com>, Dan Eaton <dan.eaton@rocketlogix.com>, Stephen Rousset<stephen.rousset@rocketlogix.com> - + Description ----------- diff --git a/Documentation/i2c/busses/i2c-ali1563 b/Documentation/i2c/busses/i2c-ali1563 index 99ad4b9bcc32..54691698d2dd 100644 --- a/Documentation/i2c/busses/i2c-ali1563 +++ b/Documentation/i2c/busses/i2c-ali1563 @@ -18,7 +18,7 @@ For an overview of these chips see http://www.acerlabs.com The M1563 southbridge is deceptively similar to the M1533, with a few notable exceptions. One of those happens to be the fact they upgraded the i2c core to be SMBus 2.0 compliant, and happens to be almost identical to -the i2c controller found in the Intel 801 south bridges. +the i2c controller found in the Intel 801 south bridges. Features -------- diff --git a/Documentation/i2c/busses/i2c-ali15x3 b/Documentation/i2c/busses/i2c-ali15x3 index ff28d381bebe..600da90b8f12 100644 --- a/Documentation/i2c/busses/i2c-ali15x3 +++ b/Documentation/i2c/busses/i2c-ali15x3 @@ -6,8 +6,8 @@ Supported adapters: http://www.ali.com.tw/eng/support/datasheet_request.php Authors: - Frodo Looijaard <frodol@dds.nl>, - Philip Edelbrock <phil@netroedge.com>, + Frodo Looijaard <frodol@dds.nl>, + Philip Edelbrock <phil@netroedge.com>, Mark D. Studebaker <mdsxyz123@yahoo.com> Module Parameters @@ -40,10 +40,10 @@ M1541 and M1543C South Bridges. The M1543C is a South bridge for desktop systems. The M1541 is a South bridge for portable systems. They are part of the following ALI chipsets: - - * "Aladdin Pro 2" includes the M1621 Slot 1 North bridge with AGP and + + * "Aladdin Pro 2" includes the M1621 Slot 1 North bridge with AGP and 100MHz CPU Front Side bus - * "Aladdin V" includes the M1541 Socket 7 North bridge with AGP and 100MHz + * "Aladdin V" includes the M1541 Socket 7 North bridge with AGP and 100MHz CPU Front Side bus Some Aladdin V motherboards: Asus P5A @@ -77,7 +77,7 @@ output of lspci will show something similar to the following: ** then run lspci. ** If you see the 1533 and 5229 devices but NOT the 7101 device, ** then you must enable ACPI, the PMU, SMB, or something similar -** in the BIOS. +** in the BIOS. ** The driver won't work if it can't find the M7101 device. The SMB controller is part of the M7101 device, which is an ACPI-compliant @@ -87,8 +87,8 @@ The whole M7101 device has to be enabled for the SMB to work. You can't just enable the SMB alone. The SMB and the ACPI have separate I/O spaces. We make sure that the SMB is enabled. We leave the ACPI alone. -Features --------- +Features +-------- This driver controls the SMB Host only. The SMB Slave controller on the M15X3 is not enabled. This driver does not use diff --git a/Documentation/i2c/busses/i2c-pca-isa b/Documentation/i2c/busses/i2c-pca-isa index 6fc8f4c27c3c..b044e5265488 100644 --- a/Documentation/i2c/busses/i2c-pca-isa +++ b/Documentation/i2c/busses/i2c-pca-isa @@ -1,10 +1,10 @@ Kernel driver i2c-pca-isa Supported adapters: -This driver supports ISA boards using the Philips PCA 9564 -Parallel bus to I2C bus controller +This driver supports ISA boards using the Philips PCA 9564 +Parallel bus to I2C bus controller -Author: Ian Campbell <icampbell@arcom.com>, Arcom Control Systems +Author: Ian Campbell <icampbell@arcom.com>, Arcom Control Systems Module Parameters ----------------- @@ -12,12 +12,12 @@ Module Parameters * base int I/O base address * irq int - IRQ interrupt -* clock int + IRQ interrupt +* clock int Clock rate as described in table 1 of PCA9564 datasheet Description ----------- -This driver supports ISA boards using the Philips PCA 9564 -Parallel bus to I2C bus controller +This driver supports ISA boards using the Philips PCA 9564 +Parallel bus to I2C bus controller diff --git a/Documentation/i2c/busses/i2c-sis5595 b/Documentation/i2c/busses/i2c-sis5595 index cc47db7d00a9..ecd21fb49a8f 100644 --- a/Documentation/i2c/busses/i2c-sis5595 +++ b/Documentation/i2c/busses/i2c-sis5595 @@ -1,41 +1,41 @@ Kernel driver i2c-sis5595 -Authors: +Authors: Frodo Looijaard <frodol@dds.nl>, Mark D. Studebaker <mdsxyz123@yahoo.com>, - Philip Edelbrock <phil@netroedge.com> + Philip Edelbrock <phil@netroedge.com> Supported adapters: * Silicon Integrated Systems Corp. SiS5595 Southbridge Datasheet: Publicly available at the Silicon Integrated Systems Corp. site. -Note: all have mfr. ID 0x1039. - - SUPPORTED PCI ID - 5595 0008 - - Note: these chips contain a 0008 device which is incompatible with the - 5595. We recognize these by the presence of the listed - "blacklist" PCI ID and refuse to load. - - NOT SUPPORTED PCI ID BLACKLIST PCI ID - 540 0008 0540 - 550 0008 0550 - 5513 0008 5511 - 5581 0008 5597 - 5582 0008 5597 - 5597 0008 5597 - 5598 0008 5597/5598 - 630 0008 0630 - 645 0008 0645 - 646 0008 0646 - 648 0008 0648 - 650 0008 0650 - 651 0008 0651 - 730 0008 0730 - 735 0008 0735 - 745 0008 0745 - 746 0008 0746 +Note: all have mfr. ID 0x1039. + + SUPPORTED PCI ID + 5595 0008 + + Note: these chips contain a 0008 device which is incompatible with the + 5595. We recognize these by the presence of the listed + "blacklist" PCI ID and refuse to load. + + NOT SUPPORTED PCI ID BLACKLIST PCI ID + 540 0008 0540 + 550 0008 0550 + 5513 0008 5511 + 5581 0008 5597 + 5582 0008 5597 + 5597 0008 5597 + 5598 0008 5597/5598 + 630 0008 0630 + 645 0008 0645 + 646 0008 0646 + 648 0008 0648 + 650 0008 0650 + 651 0008 0651 + 730 0008 0730 + 735 0008 0735 + 745 0008 0745 + 746 0008 0746 Module Parameters ----------------- diff --git a/Documentation/i2c/busses/i2c-sis630 b/Documentation/i2c/busses/i2c-sis630 index 9aca6889f748..629ea2c356fd 100644 --- a/Documentation/i2c/busses/i2c-sis630 +++ b/Documentation/i2c/busses/i2c-sis630 @@ -14,9 +14,9 @@ Module Parameters * force = [1|0] Forcibly enable the SIS630. DANGEROUS! This can be interesting for chipsets not named above to check if it works for you chipset, but DANGEROUS! - -* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default, - what your BIOS use). DANGEROUS! This should be a bit + +* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default, + what your BIOS use). DANGEROUS! This should be a bit faster, but freeze some systems (i.e. my Laptop). @@ -44,6 +44,6 @@ Philip Edelbrock <phil@netroedge.com> - testing SiS730 support Mark M. Hoffman <mhoffman@lightlink.com> - bug fixes - + To anyone else which I forgot here ;), thanks! diff --git a/Documentation/i2c/ten-bit-addresses b/Documentation/i2c/ten-bit-addresses index 200074f81360..e9890709c508 100644 --- a/Documentation/i2c/ten-bit-addresses +++ b/Documentation/i2c/ten-bit-addresses @@ -1,17 +1,17 @@ -The I2C protocol knows about two kinds of device addresses: normal 7 bit +The I2C protocol knows about two kinds of device addresses: normal 7 bit addresses, and an extended set of 10 bit addresses. The sets of addresses do not intersect: the 7 bit address 0x10 is not the same as the 10 bit address 0x10 (though a single device could respond to both of them). You select a 10 bit address by adding an extra byte after the address byte: - S Addr7 Rd/Wr .... + S Addr7 Rd/Wr .... becomes S 11110 Addr10 Rd/Wr S is the start bit, Rd/Wr the read/write bit, and if you count the number of bits, you will see the there are 8 after the S bit for 7 bit addresses, and 16 after the S bit for 10 bit addresses. -WARNING! The current 10 bit address support is EXPERIMENTAL. There are +WARNING! The current 10 bit address support is EXPERIMENTAL. There are several places in the code that will cause SEVERE PROBLEMS with 10 bit addresses, even though there is some basic handling and hooks. Also, almost no supported adapter handles the 10 bit addresses correctly. -- GitLab From 63e4e80218803ff506b3ea4f2349b17916a35730 Mon Sep 17 00:00:00 2001 From: Jean Delvare <khali@linux-fr.org> Date: Thu, 3 Jun 2010 11:33:51 +0200 Subject: [PATCH 576/842] i2c: Share the I2C device presence detection code Use the same I2C device presence detection code for legacy and new device detection functions. This is more consistent and makes the code smaller. Signed-off-by: Jean Delvare <khali@linux-fr.org> Cc: Matthieu Castet <castet.matthieu@free.fr> --- drivers/i2c/i2c-core.c | 80 +++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index e0f833cca3f1..f744f73e3ff5 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1277,6 +1277,41 @@ EXPORT_SYMBOL(i2c_master_recv); * ---------------------------------------------------- */ +/* + * Legacy default probe function, mostly relevant for SMBus. The default + * probe method is a quick write, but it is known to corrupt the 24RF08 + * EEPROMs due to a state machine bug, and could also irreversibly + * write-protect some EEPROMs, so for address ranges 0x30-0x37 and 0x50-0x5f, + * we use a short byte read instead. Also, some bus drivers don't implement + * quick write, so we fallback to a byte read in that case too. + * On x86, there is another special case for FSC hardware monitoring chips, + * which want regular byte reads (address 0x73.) Fortunately, these are the + * only known chips using this I2C address on PC hardware. + * Returns 1 if probe succeeded, 0 if not. + */ +static int i2c_default_probe(struct i2c_adapter *adap, unsigned short addr) +{ + int err; + union i2c_smbus_data dummy; + +#ifdef CONFIG_X86 + if (addr == 0x73 && (adap->class & I2C_CLASS_HWMON) + && i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA)) + err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE_DATA, &dummy); + else +#endif + if ((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50 + || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) + err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE, &dummy); + else + err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0, + I2C_SMBUS_QUICK, NULL); + + return err >= 0; +} + static int i2c_detect_address(struct i2c_client *temp_client, struct i2c_driver *driver) { @@ -1297,23 +1332,8 @@ static int i2c_detect_address(struct i2c_client *temp_client, return 0; /* Make sure there is something at this address */ - if (addr == 0x73 && (adapter->class & I2C_CLASS_HWMON)) { - /* Special probe for FSC hwmon chips */ - union i2c_smbus_data dummy; - - if (i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_READ, 0, - I2C_SMBUS_BYTE_DATA, &dummy) < 0) - return 0; - } else { - if (i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, 0, - I2C_SMBUS_QUICK, NULL) < 0) - return 0; - - /* Prevent 24RF08 corruption */ - if ((addr & ~0x0f) == 0x50) - i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, 0, - I2C_SMBUS_QUICK, NULL); - } + if (!i2c_default_probe(adapter, addr)) + return 0; /* Finally call the custom detection function */ memset(&info, 0, sizeof(struct i2c_board_info)); @@ -1420,29 +1440,9 @@ i2c_new_probed_device(struct i2c_adapter *adap, continue; } - /* Test address responsiveness - The default probe method is a quick write, but it is known - to corrupt the 24RF08 EEPROMs due to a state machine bug, - and could also irreversibly write-protect some EEPROMs, so - for address ranges 0x30-0x37 and 0x50-0x5f, we use a byte - read instead. Also, some bus drivers don't implement - quick write, so we fallback to a byte read it that case - too. */ - if ((addr_list[i] & ~0x07) == 0x30 - || (addr_list[i] & ~0x0f) == 0x50 - || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) { - union i2c_smbus_data data; - - if (i2c_smbus_xfer(adap, addr_list[i], 0, - I2C_SMBUS_READ, 0, - I2C_SMBUS_BYTE, &data) >= 0) - break; - } else { - if (i2c_smbus_xfer(adap, addr_list[i], 0, - I2C_SMBUS_WRITE, 0, - I2C_SMBUS_QUICK, NULL) >= 0) - break; - } + /* Test address responsiveness */ + if (i2c_default_probe(adap, addr_list[i])) + break; } if (addr_list[i] == I2C_CLIENT_END) { -- GitLab From 3a89db5f30576654bf1b0036af9b50ed5ab1b6c5 Mon Sep 17 00:00:00 2001 From: Jean Delvare <khali@linux-fr.org> Date: Thu, 3 Jun 2010 11:33:52 +0200 Subject: [PATCH 577/842] i2c: Check for address validity on client registration Do basic address validity checks when a client is being registered. We already had checks in place for devices which are being detected, but not for devices which are simply instantiated. This is a very basic check. We don't want to do strict checking here because some devices are known to infringe the I2C address constraints (e.g. IR receivers at 7-bit address 0x7a while this value is supposedly reserved for 10-bit addresses.) So we assume the caller knows what it is doing. Signed-off-by: Jean Delvare <khali@linux-fr.org> Cc: Matthieu Castet <castet.matthieu@free.fr> --- drivers/i2c/i2c-core.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f744f73e3ff5..96f01331544d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -371,6 +371,22 @@ struct i2c_client *i2c_verify_client(struct device *dev) EXPORT_SYMBOL(i2c_verify_client); +/* This is a permissive address validity check, I2C address map constraints + * are purposedly not enforced, except for the general call address. */ +static int i2c_check_client_addr_validity(const struct i2c_client *client) +{ + if (client->flags & I2C_CLIENT_TEN) { + /* 10-bit address, all values are valid */ + if (client->addr > 0x3ff) + return -EINVAL; + } else { + /* 7-bit address, reject the general call address */ + if (client->addr == 0x00 || client->addr > 0x7f) + return -EINVAL; + } + return 0; +} + /** * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device @@ -410,6 +426,14 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) strlcpy(client->name, info->type, sizeof(client->name)); + /* Check for address validity */ + status = i2c_check_client_addr_validity(client); + if (status) { + dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n", + client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr); + goto out_err_silent; + } + /* Check for address business */ status = i2c_check_addr(adap, client->addr); if (status) @@ -436,6 +460,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " "(%d)\n", client->name, client->addr, status); +out_err_silent: kfree(client); return NULL; } @@ -561,15 +586,9 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, return -EINVAL; } - if (info.addr < 0x03 || info.addr > 0x77) { - dev_err(dev, "%s: Invalid I2C address 0x%hx\n", "new_device", - info.addr); - return -EINVAL; - } - client = i2c_new_device(adap, &info); if (!client) - return -EEXIST; + return -EINVAL; /* Keep track of the added device */ i2c_lock_adapter(adap); -- GitLab From 656b8761ab21715eb1a35bb078dfd05e901be4ec Mon Sep 17 00:00:00 2001 From: Jean Delvare <khali@linux-fr.org> Date: Thu, 3 Jun 2010 11:33:53 +0200 Subject: [PATCH 578/842] i2c: Document reserved I2C addresses Move strict I2C address validity check to a single function, and document the reserved I2C addresses there. Signed-off-by: Jean Delvare <khali@linux-fr.org> Cc: Hans Verkuil <hverkuil@xs4all.nl> --- drivers/i2c/i2c-core.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 96f01331544d..af5172486fab 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -387,6 +387,27 @@ static int i2c_check_client_addr_validity(const struct i2c_client *client) return 0; } +/* And this is a strict address validity check, used when probing. If a + * device uses a reserved address, then it shouldn't be probed. 7-bit + * addressing is assumed, 10-bit address devices are rare and should be + * explicitly enumerated. */ +static int i2c_check_addr_validity(unsigned short addr) +{ + /* + * Reserved addresses per I2C specification: + * 0x00 General call address / START byte + * 0x01 CBUS address + * 0x02 Reserved for different bus format + * 0x03 Reserved for future purposes + * 0x04-0x07 Hs-mode master code + * 0x78-0x7b 10-bit slave addressing + * 0x7c-0x7f Reserved for future purposes + */ + if (addr < 0x08 || addr > 0x77) + return -EINVAL; + return 0; +} + /** * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device @@ -1340,10 +1361,11 @@ static int i2c_detect_address(struct i2c_client *temp_client, int err; /* Make sure the address is valid */ - if (addr < 0x03 || addr > 0x77) { + err = i2c_check_addr_validity(addr); + if (err) { dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", addr); - return -EINVAL; + return err; } /* Skip if already in use */ @@ -1446,7 +1468,7 @@ i2c_new_probed_device(struct i2c_adapter *adap, for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ - if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { + if (i2c_check_addr_validity(addr_list[i]) < 0) { dev_warn(&adap->dev, "Invalid 7-bit address " "0x%02x\n", addr_list[i]); continue; -- GitLab From 3b5f794b8b647409155cade4eac2825bc49b4a66 Mon Sep 17 00:00:00 2001 From: Jean Delvare <khali@linux-fr.org> Date: Thu, 3 Jun 2010 11:33:55 +0200 Subject: [PATCH 579/842] i2c: Rename i2c_check_addr to i2c_check_addr_busy Otherwise it's not clear what it is checking. Also move the function to save a forward declaration. Signed-off-by: Jean Delvare <khali@linux-fr.org> --- drivers/i2c/i2c-core.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index af5172486fab..1cca2631e5b3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -47,7 +47,6 @@ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); static struct device_type i2c_client_type; -static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); /* ------------------------------------------------------------------------- */ @@ -408,6 +407,22 @@ static int i2c_check_addr_validity(unsigned short addr) return 0; } +static int __i2c_check_addr_busy(struct device *dev, void *addrp) +{ + struct i2c_client *client = i2c_verify_client(dev); + int addr = *(int *)addrp; + + if (client && client->addr == addr) + return -EBUSY; + return 0; +} + +static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) +{ + return device_for_each_child(&adapter->dev, &addr, + __i2c_check_addr_busy); +} + /** * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device @@ -456,7 +471,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) } /* Check for address business */ - status = i2c_check_addr(adap, client->addr); + status = i2c_check_addr_busy(adap, client->addr); if (status) goto out_err; @@ -1064,21 +1079,6 @@ EXPORT_SYMBOL(i2c_del_driver); /* ------------------------------------------------------------------------- */ -static int __i2c_check_addr(struct device *dev, void *addrp) -{ - struct i2c_client *client = i2c_verify_client(dev); - int addr = *(int *)addrp; - - if (client && client->addr == addr) - return -EBUSY; - return 0; -} - -static int i2c_check_addr(struct i2c_adapter *adapter, int addr) -{ - return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); -} - /** * i2c_use_client - increments the reference count of the i2c client structure * @client: the client being referenced @@ -1369,7 +1369,7 @@ static int i2c_detect_address(struct i2c_client *temp_client, } /* Skip if already in use */ - if (i2c_check_addr(adapter, addr)) + if (i2c_check_addr_busy(adapter, addr)) return 0; /* Make sure there is something at this address */ @@ -1475,7 +1475,7 @@ i2c_new_probed_device(struct i2c_adapter *adap, } /* Check address availability */ - if (i2c_check_addr(adap, addr_list[i])) { + if (i2c_check_addr_busy(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in " "use, not probing\n", addr_list[i]); continue; -- GitLab From 35bfc353dcaecc99c277e3646564f3f785760bde Mon Sep 17 00:00:00 2001 From: Wolfram Sang <w.sang@pengutronix.de> Date: Thu, 3 Jun 2010 11:33:56 +0200 Subject: [PATCH 580/842] i2c/busses: Move two drivers to embedded section And fix a typo while we are here Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> Signed-off-by: Jean Delvare <khali@linux-fr.org> --- drivers/i2c/busses/Kconfig | 40 ++++++++++++++++++------------------- drivers/i2c/busses/Makefile | 6 +++--- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 87ab0568bb0e..bceafbfa7268 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -475,6 +475,26 @@ config I2C_PASEMI help Supports the PA Semi PWRficient on-chip SMBus interfaces. +config I2C_PCA_PLATFORM + tristate "PCA9564/PCA9665 as platform device" + select I2C_ALGOPCA + default n + help + This driver supports a memory mapped Philips PCA9564/PCA9665 + parallel bus to I2C bus controller. + + This driver can also be built as a module. If so, the module + will be called i2c-pca-platform. + +config I2C_PMCMSP + tristate "PMC MSP I2C TWI Controller" + depends on PMC_MSP + help + This driver supports the PMC TWI controller on MSP devices. + + This driver can also be built as module. If so, the module + will be called i2c-pmcmsp. + config I2C_PNX tristate "I2C bus support for Philips PNX targets" depends on ARCH_PNX4008 @@ -711,26 +731,6 @@ config I2C_PCA_ISA delays when I2C/SMBus chip drivers are loaded (e.g. at boot time). If unsure, say N. -config I2C_PCA_PLATFORM - tristate "PCA9564/PCA9665 as platform device" - select I2C_ALGOPCA - default n - help - This driver supports a memory mapped Philips PCA9564/PCA9665 - parallel bus to I2C bus controller. - - This driver can also be built as a module. If so, the module - will be called i2c-pca-platform. - -config I2C_PMCMSP - tristate "PMC MSP I2C TWI Controller" - depends on PMC_MSP - help - This driver supports the PMC TWI controller on MSP devices. - - This driver can also be built as module. If so, the module - will be called i2c-pmcmsp. - config I2C_SIBYTE tristate "SiByte SMBus interface" depends on SIBYTE_SB1xxx_SOC diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 097236f631e8..936880bd1dc5 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o -# Embebbed system I2C/SMBus host controller drivers +# Embedded system I2C/SMBus host controller drivers obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o @@ -46,6 +46,8 @@ obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o +obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o +obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o @@ -68,8 +70,6 @@ obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o -obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o -obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o -- GitLab From fbae3fb1546e199ab0cd185348f8124411a1ca9d Mon Sep 17 00:00:00 2001 From: Wolfram Sang <w.sang@pengutronix.de> Date: Thu, 3 Jun 2010 11:33:58 +0200 Subject: [PATCH 581/842] i2c: Remove all i2c_set_clientdata(client, NULL) in drivers I2C drivers can use the clientdata-pointer to point to private data. As I2C devices are not really unregistered, but merely detached from their driver, it used to be the drivers obligation to clear this pointer during remove() or a failed probe(). As a couple of drivers forgot to do this, it was agreed that it was cleaner if the i2c-core does this clearance when appropriate, as there is no guarantee for the lifetime of the clientdata-pointer after remove() anyhow. This feature was added to the core with commit e4a7b9b04de15f6b63da5ccdd373ffa3057a3681 to fix the faulty drivers. As there is no need anymore to clear the clientdata-pointer, remove all current occurrences in the drivers to simplify the code and prevent confusion. Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Acked-by: Richard Purdie <rpurdie@linux.intel.com> Acked-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Jean Delvare <khali@linux-fr.org> --- drivers/hwmon/adt7411.c | 2 -- drivers/hwmon/asc7621.c | 2 -- drivers/hwmon/f75375s.c | 2 -- drivers/hwmon/g760a.c | 2 -- drivers/hwmon/lm73.c | 1 - drivers/hwmon/lm75.c | 2 -- drivers/hwmon/lm95241.c | 1 - drivers/hwmon/tmp102.c | 2 -- drivers/hwmon/tmp421.c | 2 -- drivers/hwmon/w83781d.c | 2 -- drivers/i2c/i2c-smbus.c | 1 - drivers/input/keyboard/adp5588-keys.c | 1 - drivers/input/keyboard/lm8323.c | 2 -- drivers/input/keyboard/max7359_keypad.c | 1 - drivers/input/keyboard/qt2160.c | 1 - drivers/input/keyboard/tca6416-keypad.c | 2 -- drivers/input/misc/ad714x-i2c.c | 1 - drivers/input/misc/pcf8574_keypad.c | 2 -- drivers/input/mouse/synaptics_i2c.c | 1 - drivers/input/touchscreen/ad7879.c | 5 +---- drivers/input/touchscreen/eeti_ts.c | 2 -- drivers/input/touchscreen/mcs5000_ts.c | 1 - drivers/input/touchscreen/tsc2007.c | 2 -- drivers/leds/leds-bd2802.c | 2 -- drivers/leds/leds-lp3944.c | 1 - drivers/leds/leds-pca9532.c | 5 +---- drivers/leds/leds-pca955x.c | 2 -- drivers/macintosh/therm_adt746x.c | 2 -- drivers/macintosh/windfarm_lm75_sensor.c | 5 +---- drivers/macintosh/windfarm_max6690_sensor.c | 1 - drivers/macintosh/windfarm_smu_sat.c | 1 - drivers/media/radio/si470x/radio-si470x-i2c.c | 1 - drivers/media/video/mt9m001.c | 2 -- drivers/media/video/mt9m111.c | 2 -- drivers/media/video/mt9t031.c | 2 -- drivers/media/video/mt9t112.c | 2 -- drivers/media/video/mt9v022.c | 2 -- drivers/media/video/ov772x.c | 2 -- drivers/media/video/ov9640.c | 2 -- drivers/media/video/rj54n1cb0c.c | 2 -- drivers/media/video/tcm825x.c | 8 +------- drivers/media/video/tw9910.c | 2 -- drivers/mfd/88pm860x-i2c.c | 2 -- drivers/mfd/ab3100-core.c | 2 -- drivers/mfd/ab3550-core.c | 1 - drivers/mfd/adp5520.c | 2 -- drivers/mfd/da903x.c | 2 -- drivers/mfd/max8925-i2c.c | 1 - drivers/mfd/menelaus.c | 2 -- drivers/mfd/pcf50633-core.c | 2 -- drivers/mfd/tc35892.c | 2 -- drivers/mfd/tps65010.c | 1 - drivers/mfd/wm8350-i2c.c | 2 -- drivers/mfd/wm8400-core.c | 2 -- drivers/misc/eeprom/at24.c | 1 - drivers/mtd/maps/pismo.c | 2 -- drivers/power/max17040_battery.c | 2 -- drivers/regulator/lp3971.c | 2 -- drivers/regulator/max1586.c | 1 - drivers/regulator/max8649.c | 2 -- drivers/regulator/max8660.c | 1 - drivers/regulator/tps65023-regulator.c | 3 --- drivers/rtc/rtc-ds1374.c | 2 -- drivers/rtc/rtc-rx8025.c | 2 -- drivers/rtc/rtc-s35390a.c | 2 -- drivers/staging/dream/synaptics_i2c_rmi.c | 2 -- drivers/staging/go7007/wis-saa7113.c | 2 -- drivers/staging/go7007/wis-saa7115.c | 2 -- drivers/staging/go7007/wis-sony-tuner.c | 1 - drivers/staging/go7007/wis-tw2804.c | 1 - drivers/staging/go7007/wis-tw9903.c | 2 -- drivers/staging/iio/adc/max1363_core.c | 2 -- drivers/staging/iio/light/tsl2563.c | 2 -- drivers/video/backlight/adp8860_bl.c | 2 -- drivers/video/backlight/tosa_bl.c | 2 -- 75 files changed, 4 insertions(+), 141 deletions(-) diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 4086c7257f91..f13c843a2964 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -316,7 +316,6 @@ static int __devinit adt7411_probe(struct i2c_client *client, exit_remove: sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp); exit_free: - i2c_set_clientdata(client, NULL); kfree(data); return ret; } @@ -327,7 +326,6 @@ static int __devexit adt7411_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp); - i2c_set_clientdata(client, NULL); kfree(data); return 0; } diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index 0f388adc6187..3b973f30b1f6 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -1141,7 +1141,6 @@ exit_remove: &(asc7621_params[i].sda.dev_attr)); } - i2c_set_clientdata(client, NULL); kfree(data); return err; } @@ -1196,7 +1195,6 @@ static int asc7621_remove(struct i2c_client *client) &(asc7621_params[i].sda.dev_attr)); } - i2c_set_clientdata(client, NULL); kfree(data); return 0; } diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index bad2cf3ef4a4..0f58ecc5334d 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -662,7 +662,6 @@ exit_remove: sysfs_remove_group(&client->dev.kobj, &f75375_group); exit_free: kfree(data); - i2c_set_clientdata(client, NULL); return err; } @@ -672,7 +671,6 @@ static int f75375_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &f75375_group); kfree(data); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c index 09ea12e0a551..1f63d1a3af5e 100644 --- a/drivers/hwmon/g760a.c +++ b/drivers/hwmon/g760a.c @@ -236,7 +236,6 @@ error_hwmon_device_register: sysfs_remove_group(&client->dev.kobj, &g760a_group); error_sysfs_create_group: kfree(data); - i2c_set_clientdata(client, NULL); return err; } @@ -247,7 +246,6 @@ static int g760a_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &g760a_group); kfree(data); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 4d1b76bc8148..29b9030d42c3 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -136,7 +136,6 @@ static int lm73_remove(struct i2c_client *client) hwmon_device_unregister(hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm73_group); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 56463428a419..393f354f92a4 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -192,7 +192,6 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) exit_remove: sysfs_remove_group(&client->dev.kobj, &lm75_group); exit_free: - i2c_set_clientdata(client, NULL); kfree(data); return status; } @@ -204,7 +203,6 @@ static int lm75_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm75_group); lm75_write_value(client, LM75_REG_CONF, data->orig_conf); - i2c_set_clientdata(client, NULL); kfree(data); return 0; } diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 8fc8eb8cba47..94741d42112d 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -399,7 +399,6 @@ static int lm95241_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm95241_group); - i2c_set_clientdata(client, NULL); kfree(data); return 0; } diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 8013895a1faf..93187c3cb5e7 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -224,7 +224,6 @@ fail_remove_sysfs: fail_restore_config: tmp102_write_reg(client, TMP102_CONF_REG, tmp102->config_orig); fail_free: - i2c_set_clientdata(client, NULL); kfree(tmp102); return status; @@ -247,7 +246,6 @@ static int __devexit tmp102_remove(struct i2c_client *client) config | TMP102_CONF_SD); } - i2c_set_clientdata(client, NULL); kfree(tmp102); return 0; diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index 738c472ece27..6b4165c12092 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -295,7 +295,6 @@ exit_remove: sysfs_remove_group(&client->dev.kobj, &tmp421_group); exit_free: - i2c_set_clientdata(client, NULL); kfree(data); return err; @@ -308,7 +307,6 @@ static int tmp421_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &tmp421_group); - i2c_set_clientdata(client, NULL); kfree(data); return 0; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 32d4adee73db..c84b9b4e6960 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1197,7 +1197,6 @@ ERROR4: if (data->lm75[1]) i2c_unregister_device(data->lm75[1]); ERROR3: - i2c_set_clientdata(client, NULL); kfree(data); ERROR1: return err; @@ -1219,7 +1218,6 @@ w83781d_remove(struct i2c_client *client) if (data->lm75[1]) i2c_unregister_device(data->lm75[1]); - i2c_set_clientdata(client, NULL); kfree(data); return 0; diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index a24e0bfe9201..f61ccc1e5ea3 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -173,7 +173,6 @@ static int smbalert_remove(struct i2c_client *ara) cancel_work_sync(&alert->alert); - i2c_set_clientdata(ara, NULL); kfree(alert); return 0; } diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 4771ab172b59..744600eff222 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -287,7 +287,6 @@ static int __devexit adp5588_remove(struct i2c_client *client) free_irq(client->irq, kpad); cancel_delayed_work_sync(&kpad->work); input_unregister_device(kpad->input); - i2c_set_clientdata(client, NULL); kfree(kpad); return 0; diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index bc696931fed7..40b032f0e32c 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -778,8 +778,6 @@ static int __devexit lm8323_remove(struct i2c_client *client) struct lm8323_chip *lm = i2c_get_clientdata(client); int i; - i2c_set_clientdata(client, NULL); - disable_irq_wake(client->irq); free_irq(client->irq, lm); cancel_work_sync(&lm->work); diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index 7fc8185e5c1b..9091ff5ea808 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -265,7 +265,6 @@ static int __devexit max7359_remove(struct i2c_client *client) free_irq(client->irq, keypad); input_unregister_device(keypad->input_dev); - i2c_set_clientdata(client, NULL); kfree(keypad); return 0; diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 31f30087b591..fac695157e8a 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -358,7 +358,6 @@ static int __devexit qt2160_remove(struct i2c_client *client) input_unregister_device(qt2160->input); kfree(qt2160); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 493c93f25e2a..00137bebcf97 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -316,8 +316,6 @@ static int __devexit tca6416_keypad_remove(struct i2c_client *client) input_unregister_device(chip->input); kfree(chip); - i2c_set_clientdata(client, NULL); - return 0; } diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index e9adbe49f6a4..2bef8fa56c94 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -97,7 +97,6 @@ static int __devexit ad714x_i2c_remove(struct i2c_client *client) struct ad714x_chip *chip = i2c_get_clientdata(client); ad714x_remove(chip); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index 5c3ac4e0b055..0ac47d2898ec 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -168,8 +168,6 @@ static int __devexit pcf8574_kp_remove(struct i2c_client *client) input_unregister_device(lp->idev); kfree(lp); - i2c_set_clientdata(client, NULL); - return 0; } diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 8291e7399ffa..0ae62f0bcb32 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -613,7 +613,6 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client) free_irq(client->irq, touch); input_unregister_device(touch->input); - i2c_set_clientdata(client, NULL); kfree(touch); return 0; diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 794d070c6900..4b32fb4704cd 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -812,10 +812,8 @@ static int __devinit ad7879_probe(struct i2c_client *client, ts->bus = client; error = ad7879_construct(client, ts); - if (error) { - i2c_set_clientdata(client, NULL); + if (error) kfree(ts); - } return error; } @@ -825,7 +823,6 @@ static int __devexit ad7879_remove(struct i2c_client *client) struct ad7879 *ts = dev_get_drvdata(&client->dev); ad7879_destroy(client, ts); - i2c_set_clientdata(client, NULL); kfree(ts); return 0; diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 75f8b73010fa..7a3a916f84a8 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -238,7 +238,6 @@ err2: input = NULL; /* so we dont try to free it below */ err1: input_free_device(input); - i2c_set_clientdata(client, NULL); kfree(priv); err0: return err; @@ -256,7 +255,6 @@ static int __devexit eeti_ts_remove(struct i2c_client *client) enable_irq(priv->irq); input_unregister_device(priv->input); - i2c_set_clientdata(client, NULL); kfree(priv); return 0; diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index ce8ab0269f6f..1fb0c2f06a44 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -256,7 +256,6 @@ static int __devexit mcs5000_ts_remove(struct i2c_client *client) free_irq(client->irq, data); input_unregister_device(data->input_dev); kfree(data); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 769b479fcaa6..be23780e8a3e 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -347,8 +347,6 @@ static int __devexit tsc2007_remove(struct i2c_client *client) struct tsc2007 *ts = i2c_get_clientdata(client); struct tsc2007_platform_data *pdata = client->dev.platform_data; - i2c_set_clientdata(client, NULL); - tsc2007_free_irq(ts); if (pdata->exit_platform_hw) diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c index 286b501a3573..5dcdf9d69b3a 100644 --- a/drivers/leds/leds-bd2802.c +++ b/drivers/leds/leds-bd2802.c @@ -742,7 +742,6 @@ failed_unregister_dev_file: for (i--; i >= 0; i--) device_remove_file(&led->client->dev, bd2802_attributes[i]); failed_free: - i2c_set_clientdata(client, NULL); kfree(led); return ret; @@ -759,7 +758,6 @@ static int __exit bd2802_remove(struct i2c_client *client) bd2802_disable_adv_conf(led); for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) device_remove_file(&led->client->dev, bd2802_attributes[i]); - i2c_set_clientdata(client, NULL); kfree(led); return 0; diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c index 932a58da76c4..9010c054615e 100644 --- a/drivers/leds/leds-lp3944.c +++ b/drivers/leds/leds-lp3944.c @@ -432,7 +432,6 @@ static int __devexit lp3944_remove(struct i2c_client *client) } kfree(data); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 6682175fa9f7..43d08756d823 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -320,10 +320,8 @@ static int pca9532_probe(struct i2c_client *client, mutex_init(&data->update_lock); err = pca9532_configure(client, data, pca9532_pdata); - if (err) { + if (err) kfree(data); - i2c_set_clientdata(client, NULL); - } return err; } @@ -351,7 +349,6 @@ static int pca9532_remove(struct i2c_client *client) } kfree(data); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 8ff50f234190..66aa3e8e786f 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -342,7 +342,6 @@ exit: } kfree(pca955x); - i2c_set_clientdata(client, NULL); return err; } @@ -358,7 +357,6 @@ static int __devexit pca955x_remove(struct i2c_client *client) } kfree(pca955x); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 16d82f17ae82..c42eeb43042d 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -182,7 +182,6 @@ remove_thermostat(struct i2c_client *client) thermostat = NULL; - i2c_set_clientdata(client, NULL); kfree(th); return 0; @@ -400,7 +399,6 @@ static int probe_thermostat(struct i2c_client *client, rc = read_reg(th, CONFIG_REG); if (rc < 0) { dev_err(&client->dev, "Thermostat failed to read config!\n"); - i2c_set_clientdata(client, NULL); kfree(th); return -ENODEV; } diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index d8257d35afde..647c6add2193 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -107,10 +107,8 @@ static int wf_lm75_probe(struct i2c_client *client, i2c_set_clientdata(client, lm); rc = wf_register_sensor(&lm->sens); - if (rc) { - i2c_set_clientdata(client, NULL); + if (rc) kfree(lm); - } return rc; } @@ -216,7 +214,6 @@ static int wf_lm75_remove(struct i2c_client *client) /* release sensor */ wf_unregister_sensor(&lm->sens); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index b486eb929fde..8204113268f4 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -81,7 +81,6 @@ static int wf_max6690_probe(struct i2c_client *client, rc = wf_register_sensor(&max->sens); if (rc) { - i2c_set_clientdata(client, NULL); kfree(max); } diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index e20330a28959..65a8ff3e1f8e 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -376,7 +376,6 @@ static int wf_sat_remove(struct i2c_client *client) /* XXX TODO */ sat->i2c = NULL; - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index a5844d08d8b7..67a4ec8768a6 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -482,7 +482,6 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client) cancel_work_sync(&radio->radio_work); video_unregister_device(radio->videodev); kfree(radio); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index b62c0bd3f8ea..e3b9a8ab37f4 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -785,7 +785,6 @@ static int mt9m001_probe(struct i2c_client *client, ret = mt9m001_video_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(mt9m001); } @@ -799,7 +798,6 @@ static int mt9m001_remove(struct i2c_client *client) icd->ops = NULL; mt9m001_video_remove(icd); - i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(mt9m001); diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index d35f536f9fc3..e42162c50f0a 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -1068,7 +1068,6 @@ static int mt9m111_probe(struct i2c_client *client, ret = mt9m111_video_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(mt9m111); } @@ -1081,7 +1080,6 @@ static int mt9m111_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; icd->ops = NULL; - i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(mt9m111); diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 78b4e091d2d5..9f5ff2547f19 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -883,7 +883,6 @@ static int mt9t031_probe(struct i2c_client *client, if (ret) { if (icd) icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(mt9t031); } @@ -897,7 +896,6 @@ static int mt9t031_remove(struct i2c_client *client) if (icd) icd->ops = NULL; - i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(mt9t031); diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 7438f8d775ba..aa4fce95098f 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -1119,7 +1119,6 @@ static int mt9t112_probe(struct i2c_client *client, ret = mt9t112_camera_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); } @@ -1132,7 +1131,6 @@ static int mt9t112_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); return 0; } diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index e5bae4c9393b..fb44ff006628 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -920,7 +920,6 @@ static int mt9v022_probe(struct i2c_client *client, ret = mt9v022_video_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(mt9v022); } @@ -934,7 +933,6 @@ static int mt9v022_remove(struct i2c_client *client) icd->ops = NULL; mt9v022_video_remove(icd); - i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(mt9v022); diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 7f8ece30c77b..c33acc94b747 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -1159,7 +1159,6 @@ static int ov772x_probe(struct i2c_client *client, ret = ov772x_video_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); } @@ -1172,7 +1171,6 @@ static int ov772x_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); return 0; } diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 36599a65f548..035e9ecb0c75 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -783,7 +783,6 @@ static int ov9640_probe(struct i2c_client *client, if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); } @@ -794,7 +793,6 @@ static int ov9640_remove(struct i2c_client *client) { struct ov9640_priv *priv = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(priv); return 0; } diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index bbd9c11e2c5a..2c3b58c99e18 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -1444,7 +1444,6 @@ static int rj54n1_probe(struct i2c_client *client, ret = rj54n1_video_probe(icd, client, rj54n1_priv); if (ret < 0) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(rj54n1); return ret; } @@ -1461,7 +1460,6 @@ static int rj54n1_remove(struct i2c_client *client) icd->ops = NULL; if (icl->free_bus) icl->free_bus(icl); - i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(rj54n1); diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index b90e9da3167d..54681a535822 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -850,7 +850,6 @@ static int tcm825x_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct tcm825x_sensor *sensor = &tcm825x; - int rval; if (i2c_get_clientdata(client)) return -EBUSY; @@ -871,11 +870,7 @@ static int tcm825x_probe(struct i2c_client *client, sensor->pix.height = tcm825x_sizes[QVGA].height; sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565; - rval = v4l2_int_device_register(sensor->v4l2_int_device); - if (rval) - i2c_set_clientdata(client, NULL); - - return rval; + return v4l2_int_device_register(sensor->v4l2_int_device); } static int tcm825x_remove(struct i2c_client *client) @@ -886,7 +881,6 @@ static int tcm825x_remove(struct i2c_client *client) return -ENODEV; /* our client isn't attached */ v4l2_int_device_unregister(sensor->v4l2_int_device); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 76be733eabfd..6eb3395def07 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -977,7 +977,6 @@ static int tw9910_probe(struct i2c_client *client, ret = tw9910_video_probe(icd, client); if (ret) { icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); } @@ -990,7 +989,6 @@ static int tw9910_remove(struct i2c_client *client) struct soc_camera_device *icd = client->dev.platform_data; icd->ops = NULL; - i2c_set_clientdata(client, NULL); kfree(priv); return 0; } diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index c933b64d1283..bc02e6b21608 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -200,8 +200,6 @@ static int __devexit pm860x_remove(struct i2c_client *client) pm860x_device_exit(chip); i2c_unregister_device(chip->companion); - i2c_set_clientdata(chip->client, NULL); - i2c_set_clientdata(client, NULL); kfree(chip); return 0; } diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 53ebfee548fa..66379b413906 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -957,7 +957,6 @@ static int __init ab3100_probe(struct i2c_client *client, i2c_unregister_device(ab3100->testreg_client); exit_no_testreg_client: exit_no_detect: - i2c_set_clientdata(client, NULL); kfree(ab3100); return err; } @@ -979,7 +978,6 @@ static int __exit ab3100_remove(struct i2c_client *client) * their notifiers so deactivate IRQ */ free_irq(client->irq, ab3100); - i2c_set_clientdata(client, NULL); kfree(ab3100); return 0; } diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index 1060f8e1c40a..f54ab62e7bc6 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c @@ -1362,7 +1362,6 @@ static int __exit ab3550_remove(struct i2c_client *client) * their notifiers so deactivate IRQ */ free_irq(client->irq, ab); - i2c_set_clientdata(client, NULL); kfree(ab); return 0; } diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index 005532865654..3122139b4300 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c @@ -302,7 +302,6 @@ out_free_irq: free_irq(chip->irq, chip); out_free_chip: - i2c_set_clientdata(client, NULL); kfree(chip); return ret; @@ -317,7 +316,6 @@ static int __devexit adp5520_remove(struct i2c_client *client) adp5520_remove_subdevs(chip); adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); - i2c_set_clientdata(client, NULL); kfree(chip); return 0; } diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 3ad915d0589c..c07aece900fb 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -534,7 +534,6 @@ static int __devinit da903x_probe(struct i2c_client *client, out_free_irq: free_irq(client->irq, chip); out_free_chip: - i2c_set_clientdata(client, NULL); kfree(chip); return ret; } @@ -544,7 +543,6 @@ static int __devexit da903x_remove(struct i2c_client *client) struct da903x_chip *chip = i2c_get_clientdata(client); da903x_remove_subdevs(chip); - i2c_set_clientdata(client, NULL); kfree(chip); return 0; } diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index e73f3f5252a8..0219115e00c7 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -173,7 +173,6 @@ static int __devexit max8925_remove(struct i2c_client *client) max8925_device_exit(chip); i2c_unregister_device(chip->adc); i2c_unregister_device(chip->rtc); - i2c_set_clientdata(chip->i2c, NULL); kfree(chip); return 0; } diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 721948be12c7..a3fb4bcb9889 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1228,7 +1228,6 @@ fail2: free_irq(client->irq, menelaus); flush_scheduled_work(); fail1: - i2c_set_clientdata(client, NULL); kfree(menelaus); return err; } @@ -1238,7 +1237,6 @@ static int __exit menelaus_remove(struct i2c_client *client) struct menelaus_chip *menelaus = i2c_get_clientdata(client); free_irq(client->irq, menelaus); - i2c_set_clientdata(client, NULL); kfree(menelaus); the_menelaus = NULL; return 0; diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 704736e6e9b9..23e585527285 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -336,7 +336,6 @@ static int __devinit pcf50633_probe(struct i2c_client *client, return 0; err_free: - i2c_set_clientdata(client, NULL); kfree(pcf); return ret; @@ -357,7 +356,6 @@ static int __devexit pcf50633_remove(struct i2c_client *client) for (i = 0; i < PCF50633_NUM_REGULATORS; i++) platform_device_unregister(pcf->regulator_pdev[i]); - i2c_set_clientdata(client, NULL); kfree(pcf); return 0; diff --git a/drivers/mfd/tc35892.c b/drivers/mfd/tc35892.c index 715f095dd7a6..e619e2a55997 100644 --- a/drivers/mfd/tc35892.c +++ b/drivers/mfd/tc35892.c @@ -296,7 +296,6 @@ out_freeirq: out_removeirq: tc35892_irq_remove(tc35892); out_free: - i2c_set_clientdata(i2c, NULL); kfree(tc35892); return ret; } @@ -310,7 +309,6 @@ static int __devexit tc35892_remove(struct i2c_client *client) free_irq(tc35892->i2c->irq, tc35892); tc35892_irq_remove(tc35892); - i2c_set_clientdata(client, NULL); kfree(tc35892); return 0; diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index 9b22a77f70f5..d0016b67d125 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -530,7 +530,6 @@ static int __exit tps65010_remove(struct i2c_client *client) cancel_delayed_work(&tps->work); flush_scheduled_work(); debugfs_remove(tps->file); - i2c_set_clientdata(client, NULL); kfree(tps); the_tps = NULL; return 0; diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c index 7795af4b1fe1..5fe5de166adb 100644 --- a/drivers/mfd/wm8350-i2c.c +++ b/drivers/mfd/wm8350-i2c.c @@ -80,7 +80,6 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, return ret; err: - i2c_set_clientdata(i2c, NULL); kfree(wm8350); return ret; } @@ -90,7 +89,6 @@ static int wm8350_i2c_remove(struct i2c_client *i2c) struct wm8350 *wm8350 = i2c_get_clientdata(i2c); wm8350_device_exit(wm8350); - i2c_set_clientdata(i2c, NULL); kfree(wm8350); return 0; diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index e08aafa663dc..1bfef4846b07 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -415,7 +415,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, return 0; struct_err: - i2c_set_clientdata(i2c, NULL); kfree(wm8400); err: return ret; @@ -426,7 +425,6 @@ static int wm8400_i2c_remove(struct i2c_client *i2c) struct wm8400 *wm8400 = i2c_get_clientdata(i2c); wm8400_release(wm8400); - i2c_set_clientdata(i2c, NULL); kfree(wm8400); return 0; diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index f7ca3a42b490..559b0b3c16c3 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -643,7 +643,6 @@ static int __devexit at24_remove(struct i2c_client *client) kfree(at24->writebuf); kfree(at24); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/mtd/maps/pismo.c b/drivers/mtd/maps/pismo.c index eb476b7f8d11..f4ce273e93fd 100644 --- a/drivers/mtd/maps/pismo.c +++ b/drivers/mtd/maps/pismo.c @@ -234,7 +234,6 @@ static int __devexit pismo_remove(struct i2c_client *client) /* FIXME: set_vpp needs saner arguments */ pismo_setvpp_remove_fix(pismo); - i2c_set_clientdata(client, NULL); kfree(pismo); return 0; @@ -286,7 +285,6 @@ static int __devinit pismo_probe(struct i2c_client *client, return 0; exit_free: - i2c_set_clientdata(client, NULL); kfree(pismo); return ret; } diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index f3e22c9fe20a..2f2f9a6f54fa 100644 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -225,7 +225,6 @@ static int __devinit max17040_probe(struct i2c_client *client, ret = power_supply_register(&client->dev, &chip->battery); if (ret) { dev_err(&client->dev, "failed: power supply register\n"); - i2c_set_clientdata(client, NULL); kfree(chip); return ret; } @@ -245,7 +244,6 @@ static int __devexit max17040_remove(struct i2c_client *client) power_supply_unregister(&chip->battery); cancel_delayed_work(&chip->work); - i2c_set_clientdata(client, NULL); kfree(chip); return 0; } diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 671a7d1f1f0e..8ae3732eb24b 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -519,8 +519,6 @@ static int __devexit lp3971_i2c_remove(struct i2c_client *i2c) struct lp3971 *lp3971 = i2c_get_clientdata(i2c); int i; - i2c_set_clientdata(i2c, NULL); - for (i = 0; i < lp3971->num_regulators; i++) regulator_unregister(lp3971->rdev[i]); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index b3c1afc16889..2b54d9d75f11 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -244,7 +244,6 @@ static int __devexit max1586_pmic_remove(struct i2c_client *client) for (i = 0; i <= MAX1586_V6; i++) if (rdev[i]) regulator_unregister(rdev[i]); - i2c_set_clientdata(client, NULL); kfree(rdev); return 0; diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index bfc4c5ffdc96..4520ace3f7e7 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -357,7 +357,6 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, dev_info(info->dev, "Max8649 regulator device is detected.\n"); return 0; out: - i2c_set_clientdata(client, NULL); kfree(info); return ret; } @@ -369,7 +368,6 @@ static int __devexit max8649_regulator_remove(struct i2c_client *client) if (info) { if (info->regulator) regulator_unregister(info->regulator); - i2c_set_clientdata(client, NULL); kfree(info); } diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 3790b21879ff..d97220efae5a 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -471,7 +471,6 @@ static int __devexit max8660_remove(struct i2c_client *client) for (i = 0; i < MAX8660_V_END; i++) if (rdev[i]) regulator_unregister(rdev[i]); - i2c_set_clientdata(client, NULL); kfree(rdev); return 0; diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 8e2f2098b005..f50afc9f287a 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -538,9 +538,6 @@ static int __devexit tps_65023_remove(struct i2c_client *client) struct tps_pmic *tps = i2c_get_clientdata(client); int i; - /* clear the client data in i2c */ - i2c_set_clientdata(client, NULL); - for (i = 0; i < TPS65023_NUM_REGULATOR; i++) regulator_unregister(tps->rdev[i]); diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 61945734ad00..1f0007fd4431 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -403,7 +403,6 @@ out_irq: free_irq(client->irq, client); out_free: - i2c_set_clientdata(client, NULL); kfree(ds1374); return ret; } @@ -422,7 +421,6 @@ static int __devexit ds1374_remove(struct i2c_client *client) } rtc_device_unregister(ds1374->rtc); - i2c_set_clientdata(client, NULL); kfree(ds1374); return 0; } diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index b65c82f792d9..789f62f9b47d 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -632,7 +632,6 @@ errout_reg: rtc_device_unregister(rx8025->rtc); errout_free: - i2c_set_clientdata(client, NULL); kfree(rx8025); errout: @@ -656,7 +655,6 @@ static int __devexit rx8025_remove(struct i2c_client *client) rx8025_sysfs_unregister(&client->dev); rtc_device_unregister(rx8025->rtc); - i2c_set_clientdata(client, NULL); kfree(rx8025); return 0; } diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index def4d396d0b0..f789e002c9b0 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -275,7 +275,6 @@ exit_dummy: if (s35390a->client[i]) i2c_unregister_device(s35390a->client[i]); kfree(s35390a); - i2c_set_clientdata(client, NULL); exit: return err; @@ -292,7 +291,6 @@ static int s35390a_remove(struct i2c_client *client) rtc_device_unregister(s35390a->rtc); kfree(s35390a); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/staging/dream/synaptics_i2c_rmi.c b/drivers/staging/dream/synaptics_i2c_rmi.c index 1f020dad6234..3320359408a9 100644 --- a/drivers/staging/dream/synaptics_i2c_rmi.c +++ b/drivers/staging/dream/synaptics_i2c_rmi.c @@ -519,7 +519,6 @@ err_input_register_device_failed: err_input_dev_alloc_failed: err_detect_failed: err_power_failed: - i2c_set_clientdata(client, NULL); kfree(ts); err_alloc_data_failed: err_check_functionality_failed: @@ -537,7 +536,6 @@ static int synaptics_ts_remove(struct i2c_client *client) else hrtimer_cancel(&ts->timer); input_unregister_device(ts->input_dev); - i2c_set_clientdata(client, NULL); kfree(ts); return 0; } diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c index bd925457f8b7..72f5c1f56d19 100644 --- a/drivers/staging/go7007/wis-saa7113.c +++ b/drivers/staging/go7007/wis-saa7113.c @@ -289,7 +289,6 @@ static int wis_saa7113_probe(struct i2c_client *client, if (write_regs(client, initial_registers) < 0) { printk(KERN_ERR "wis-saa7113: error initializing SAA7113\n"); - i2c_set_clientdata(client, NULL); kfree(dec); return -ENODEV; } @@ -301,7 +300,6 @@ static int wis_saa7113_remove(struct i2c_client *client) { struct wis_saa7113 *dec = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(dec); return 0; } diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c index b2eb804c1954..cd950b61cf70 100644 --- a/drivers/staging/go7007/wis-saa7115.c +++ b/drivers/staging/go7007/wis-saa7115.c @@ -422,7 +422,6 @@ static int wis_saa7115_probe(struct i2c_client *client, if (write_regs(client, initial_registers) < 0) { printk(KERN_ERR "wis-saa7115: error initializing SAA7115\n"); - i2c_set_clientdata(client, NULL); kfree(dec); return -ENODEV; } @@ -434,7 +433,6 @@ static int wis_saa7115_remove(struct i2c_client *client) { struct wis_saa7115 *dec = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(dec); return 0; } diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c index b1013291190f..981c9b311b8b 100644 --- a/drivers/staging/go7007/wis-sony-tuner.c +++ b/drivers/staging/go7007/wis-sony-tuner.c @@ -684,7 +684,6 @@ static int wis_sony_tuner_remove(struct i2c_client *client) { struct wis_sony_tuner *t = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(t); return 0; } diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c index 315268d130dd..ee28a99dc388 100644 --- a/drivers/staging/go7007/wis-tw2804.c +++ b/drivers/staging/go7007/wis-tw2804.c @@ -323,7 +323,6 @@ static int wis_tw2804_remove(struct i2c_client *client) { struct wis_tw2804 *dec = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(dec); return 0; } diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c index 2afea09091b9..80d47269b1c0 100644 --- a/drivers/staging/go7007/wis-tw9903.c +++ b/drivers/staging/go7007/wis-tw9903.c @@ -294,7 +294,6 @@ static int wis_tw9903_probe(struct i2c_client *client, if (write_regs(client, initial_registers) < 0) { printk(KERN_ERR "wis-tw9903: error initializing TW9903\n"); - i2c_set_clientdata(client, NULL); kfree(dec); return -ENODEV; } @@ -306,7 +305,6 @@ static int wis_tw9903_remove(struct i2c_client *client) { struct wis_tw9903 *dec = i2c_get_clientdata(client); - i2c_set_clientdata(client, NULL); kfree(dec); return 0; } diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c index 20e267448d1f..905f8560d31f 100644 --- a/drivers/staging/iio/adc/max1363_core.c +++ b/drivers/staging/iio/adc/max1363_core.c @@ -1011,7 +1011,6 @@ error_put_reg: if (!IS_ERR(st->reg)) regulator_put(st->reg); error_free_st: - i2c_set_clientdata(client, NULL); kfree(st); error_ret: @@ -1030,7 +1029,6 @@ static int max1363_remove(struct i2c_client *client) regulator_disable(st->reg); regulator_put(st->reg); } - i2c_set_clientdata(client, NULL); kfree(st); return 0; diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index 43aaacff4e74..e4b0a5ef1c1f 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -694,7 +694,6 @@ static int __devinit tsl2563_probe(struct i2c_client *client, fail2: iio_device_unregister(chip->indio_dev); fail1: - i2c_set_clientdata(client, NULL); kfree(chip); return err; } @@ -705,7 +704,6 @@ static int tsl2563_remove(struct i2c_client *client) iio_device_unregister(chip->indio_dev); - i2c_set_clientdata(client, NULL); kfree(chip); return 0; } diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 921ca37398f3..3ec24609151e 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -756,7 +756,6 @@ out: out1: backlight_device_unregister(bl); out2: - i2c_set_clientdata(client, NULL); kfree(data); return ret; @@ -776,7 +775,6 @@ static int __devexit adp8860_remove(struct i2c_client *client) &adp8860_bl_attr_group); backlight_device_unregister(data->bl); - i2c_set_clientdata(client, NULL); kfree(data); return 0; diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index e03e60bbfd85..2a04b382ec48 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -119,7 +119,6 @@ static int __devinit tosa_bl_probe(struct i2c_client *client, err_reg: data->bl = NULL; - i2c_set_clientdata(client, NULL); err_gpio_dir: gpio_free(TOSA_GPIO_BL_C20MA); err_gpio_bl: @@ -133,7 +132,6 @@ static int __devexit tosa_bl_remove(struct i2c_client *client) backlight_device_unregister(data->bl); data->bl = NULL; - i2c_set_clientdata(client, NULL); gpio_free(TOSA_GPIO_BL_C20MA); -- GitLab From d42a8f464ba14467e5d45dc0eb8f789c82bd0679 Mon Sep 17 00:00:00 2001 From: Ben Hutchings <bhutchings@solarflare.com> Date: Tue, 1 Jun 2010 11:32:43 +0000 Subject: [PATCH 582/842] sfc: Get port number from CS_PORT_NUM, not PCI function number A single shared memory region used to communicate with firmware is mapped into both PCI PFs of the SFC9020 and SFL9021. Drivers must be able to identify which port they are addressing in order to use the correct sub-region. Currently we use the PCI function number, but the PCI address may be virtualised. Use the CS_PORT_NUM register field defined for just this purpose. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/sfc/net_driver.h | 4 +++- drivers/net/sfc/siena.c | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 2e6fd89f2a72..5fffd9abffde 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -645,6 +645,7 @@ union efx_multicast_hash { * struct efx_nic - an Efx NIC * @name: Device name (net device name or bus id before net device registered) * @pci_dev: The PCI device + * @port_num: Index of this host port within the controller * @type: Controller type attributes * @legacy_irq: IRQ number * @workqueue: Workqueue for port reconfigures and the HW monitor. @@ -728,6 +729,7 @@ union efx_multicast_hash { struct efx_nic { char name[IFNAMSIZ]; struct pci_dev *pci_dev; + unsigned port_num; const struct efx_nic_type *type; int legacy_irq; struct workqueue_struct *workqueue; @@ -830,7 +832,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx) static inline unsigned int efx_port_num(struct efx_nic *efx) { - return PCI_FUNC(efx->pci_dev->devfn); + return efx->port_num; } /** diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 727b4228e081..7ecd255a7cc0 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -206,6 +206,7 @@ static int siena_probe_nic(struct efx_nic *efx) { struct siena_nic_data *nic_data; bool already_attached = 0; + efx_oword_t reg; int rc; /* Allocate storage for hardware specific data */ @@ -220,6 +221,9 @@ static int siena_probe_nic(struct efx_nic *efx) goto fail1; } + efx_reado(efx, ®, FR_AZ_CS_DEBUG); + efx->port_num = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; + efx_mcdi_init(efx); /* Recover from a failed assertion before probing */ -- GitLab From 3b21b508ecc9e043839a5337563cfc77f9fcedb9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Wed, 2 Jun 2010 13:43:15 +0000 Subject: [PATCH 583/842] e1000e: change logical negate to bitwise The bitwise negate is intended here. With the logical negate the condition is always false. Signed-off-by: Dan Carpenter <error27@gmail.com> Acked-by: Bruce Allan <bruce.w.allan@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/e1000e/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 24507f3b8b17..57a7e41da69e 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2554,7 +2554,7 @@ static void e1000_init_manageability_pt(struct e1000_adapter *adapter) mdef = er32(MDEF(i)); /* Ignore filters with anything other than IPMI ports */ - if (mdef & !(E1000_MDEF_PORT_623 | E1000_MDEF_PORT_664)) + if (mdef & ~(E1000_MDEF_PORT_623 | E1000_MDEF_PORT_664)) continue; /* Enable this decision filter in MANC2H */ -- GitLab From 60a5711db646b87b9530b16cbaf3bd53ac5594a5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Wed, 2 Jun 2010 23:56:13 +0000 Subject: [PATCH 584/842] isdn/kcapi: return -EFAULT on copy_from_user errors copy_from_user() returns the number of bytes remaining but we should return -EFAULT here. The error code gets returned to the user. Both old_capi_manufacturer() and capi20_manufacturer() had other places that already returned -EFAULT so this won't break anything. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/isdn/capi/kcapi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index bde3c88b8b27..b054494df846 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -1020,12 +1020,12 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) if (cmd == AVMB1_ADDCARD) { if ((retval = copy_from_user(&cdef, data, sizeof(avmb1_carddef)))) - return retval; + return -EFAULT; cdef.cardtype = AVM_CARDTYPE_B1; } else { if ((retval = copy_from_user(&cdef, data, sizeof(avmb1_extcarddef)))) - return retval; + return -EFAULT; } cparams.port = cdef.port; cparams.irq = cdef.irq; @@ -1218,7 +1218,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) kcapi_carddef cdef; if ((retval = copy_from_user(&cdef, data, sizeof(cdef)))) - return retval; + return -EFAULT; cparams.port = cdef.port; cparams.irq = cdef.irq; -- GitLab From d23380701876dd93d310b2548c51d0f78f25d7aa Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Thu, 3 Jun 2010 00:05:35 +0000 Subject: [PATCH 585/842] tehuti: return -EFAULT on copy_to_user errors copy_to_user() returns the number of bytes remaining but we want to return a negative error code here. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/tehuti.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 20ab16192325..737df6032bbc 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -646,7 +646,7 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) error = copy_from_user(data, ifr->ifr_data, sizeof(data)); if (error) { pr_err("cant copy from user\n"); - RET(error); + RET(-EFAULT); } DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); } @@ -665,7 +665,7 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) data[2]); error = copy_to_user(ifr->ifr_data, data, sizeof(data)); if (error) - RET(error); + RET(-EFAULT); break; case BDX_OP_WRITE: -- GitLab From 9e2d11b926765681f72db0373d2ecbbac28359b3 Mon Sep 17 00:00:00 2001 From: Roland Dreier <rdreier@cisco.com> Date: Wed, 2 Jun 2010 10:36:53 +0000 Subject: [PATCH 586/842] epic100: Test __BIG_ENDIAN instead of (non-existent) CONFIG_BIG_ENDIAN Probably no one has used this driver on big-endian systems, since it was setting up descriptor swapping if CONFIG_BIG_ENDIAN is set, which it never is, since that symbol is not mentioned anywhere else in the kernel source. Switch this test to a check for __BIG_ENDIAN so it has a chance at working. Signed-off-by: Roland Dreier <rolandd@cisco.com> Acked-by: Jeff Garzik <jgarzik@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/epic100.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 6838dfc9ef23..4c274657283c 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -87,6 +87,7 @@ static int rx_copybreak; #include <linux/bitops.h> #include <asm/io.h> #include <asm/uaccess.h> +#include <asm/byteorder.h> /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = @@ -230,7 +231,7 @@ static const u16 media2miictl[16] = { * The EPIC100 Rx and Tx buffer descriptors. Note that these * really ARE host-endian; it's not a misannotation. We tell * the card to byteswap them internally on big-endian hosts - - * look for #ifdef CONFIG_BIG_ENDIAN in epic_open(). + * look for #ifdef __BIG_ENDIAN in epic_open(). */ struct epic_tx_desc { @@ -690,7 +691,7 @@ static int epic_open(struct net_device *dev) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); /* Tell the chip to byteswap descriptors on big-endian hosts */ -#ifdef CONFIG_BIG_ENDIAN +#ifdef __BIG_ENDIAN outl(0x4432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); inl(ioaddr + GENCTL); outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); @@ -806,7 +807,7 @@ static void epic_restart(struct net_device *dev) for (i = 16; i > 0; i--) outl(0x0008, ioaddr + TEST1); -#ifdef CONFIG_BIG_ENDIAN +#ifdef __BIG_ENDIAN outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); #else outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); -- GitLab From 3df95ce948dc8ceef07b49003ab944aa047f2a79 Mon Sep 17 00:00:00 2001 From: Ben Hutchings <bhutchings@solarflare.com> Date: Wed, 2 Jun 2010 10:39:56 +0000 Subject: [PATCH 587/842] sfc: Store port number in net_device::dev_id This exposes the port number to userland through sysfs. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/sfc/net_driver.h | 4 +--- drivers/net/sfc/siena.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 5fffd9abffde..4762c91cb587 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -645,7 +645,6 @@ union efx_multicast_hash { * struct efx_nic - an Efx NIC * @name: Device name (net device name or bus id before net device registered) * @pci_dev: The PCI device - * @port_num: Index of this host port within the controller * @type: Controller type attributes * @legacy_irq: IRQ number * @workqueue: Workqueue for port reconfigures and the HW monitor. @@ -729,7 +728,6 @@ union efx_multicast_hash { struct efx_nic { char name[IFNAMSIZ]; struct pci_dev *pci_dev; - unsigned port_num; const struct efx_nic_type *type; int legacy_irq; struct workqueue_struct *workqueue; @@ -832,7 +830,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx) static inline unsigned int efx_port_num(struct efx_nic *efx) { - return efx->port_num; + return efx->net_dev->dev_id; } /** diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 7ecd255a7cc0..f2b1e6180753 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -222,7 +222,7 @@ static int siena_probe_nic(struct efx_nic *efx) } efx_reado(efx, ®, FR_AZ_CS_DEBUG); - efx->port_num = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; + efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; efx_mcdi_init(efx); -- GitLab From db2c24175d149b55784f7cb2c303622ce962c1ae Mon Sep 17 00:00:00 2001 From: Changli Gao <xiaosuo@gmail.com> Date: Wed, 2 Jun 2010 04:55:02 +0000 Subject: [PATCH 588/842] act_pedit: access skb->data safely access skb->data safely we should use skb_header_pointer() and skb_store_bits() to access skb->data to handle small or non-linear skbs. Signed-off-by: Changli Gao <xiaosuo@gmail.com> ---- net/sched/act_pedit.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) Signed-off-by: David S. Miller <davem@davemloft.net> --- net/sched/act_pedit.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index fdbd0b7bd840..50e3d945e1f4 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -125,7 +125,7 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a, { struct tcf_pedit *p = a->priv; int i, munged = 0; - u8 *pptr; + unsigned int off; if (!(skb->tc_verd & TC_OK2MUNGE)) { /* should we set skb->cloned? */ @@ -134,7 +134,7 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a, } } - pptr = skb_network_header(skb); + off = skb_network_offset(skb); spin_lock(&p->tcf_lock); @@ -144,17 +144,17 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a, struct tc_pedit_key *tkey = p->tcfp_keys; for (i = p->tcfp_nkeys; i > 0; i--, tkey++) { - u32 *ptr; + u32 *ptr, _data; int offset = tkey->off; if (tkey->offmask) { - if (skb->len > tkey->at) { - char *j = pptr + tkey->at; - offset += ((*j & tkey->offmask) >> - tkey->shift); - } else { + char *d, _d; + + d = skb_header_pointer(skb, off + tkey->at, 1, + &_d); + if (!d) goto bad; - } + offset += (*d & tkey->offmask) >> tkey->shift; } if (offset % 4) { @@ -169,9 +169,13 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a, goto bad; } - ptr = (u32 *)(pptr+offset); + ptr = skb_header_pointer(skb, off + offset, 4, &_data); + if (!ptr) + goto bad; /* just do it, baby */ *ptr = ((*ptr & tkey->mask) ^ tkey->val); + if (ptr == &_data) + skb_store_bits(skb, off + offset, ptr, 4); munged++; } -- GitLab From a1868dc2878e61778b9d6d8c61d5368e51d68a29 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Date: Wed, 2 Jun 2010 12:44:05 +0000 Subject: [PATCH 589/842] ixgbe: return IXGBE_ERR_RAR_INDEX when out of range Based on original patch from Shirley Ma <xma@us.ibm.com> Return IXGBE_ERR_RAR_INDEX when RAR index is out of range, instead of returning IXGBE_SUCCESS. CC: Shirley Ma <xma@us.ibm.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Acked-by: Don Skidmore <donald.c.skidmore@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/ixgbe/ixgbe_common.c | 2 ++ drivers/net/ixgbe/ixgbe_type.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 1159d9138f05..9595b1bfb8dd 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1188,6 +1188,7 @@ s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); } else { hw_dbg(hw, "RAR index %d is out of range.\n", index); + return IXGBE_ERR_RAR_INDEX; } return 0; @@ -1219,6 +1220,7 @@ s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); } else { hw_dbg(hw, "RAR index %d is out of range.\n", index); + return IXGBE_ERR_RAR_INDEX; } /* clear VMDq pool/queue selection for this RAR */ diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 2eb6e151016c..cdd1998f18c7 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -2609,6 +2609,7 @@ struct ixgbe_info { #define IXGBE_ERR_EEPROM_VERSION -24 #define IXGBE_ERR_NO_SPACE -25 #define IXGBE_ERR_OVERTEMP -26 +#define IXGBE_ERR_RAR_INDEX -27 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF #endif /* _IXGBE_TYPE_H_ */ -- GitLab From 6a6ca57de92fcae34603551ac944aa74758c30d4 Mon Sep 17 00:00:00 2001 From: Jens Axboe <jaxboe@fusionio.com> Date: Thu, 3 Jun 2010 12:44:30 +0200 Subject: [PATCH 590/842] pipe: adjust minimum pipe size to 1 page We don't need to pages to guarantee the POSIX requirement that upto a page size write must be atomic to an empty pipe. Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- fs/pipe.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/fs/pipe.c b/fs/pipe.c index 541d6626f9d9..369a0245aab6 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1181,13 +1181,7 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) if (!capable(CAP_SYS_ADMIN) && nr_pages > pipe_max_pages) { ret = -EPERM; goto out; - } - - /* - * The pipe needs to be at least 2 pages large to - * guarantee POSIX behaviour. - */ - if (arg < 2) { + } else if (nr_pages < 1) { ret = -EINVAL; goto out; } -- GitLab From 419f8367ea37e5adc5d95479e8fd5554b92b49fe Mon Sep 17 00:00:00 2001 From: Jens Axboe <jaxboe@fusionio.com> Date: Thu, 3 Jun 2010 12:45:28 +0200 Subject: [PATCH 591/842] pipe: change the privilege required for growing a pipe beyond system max Change it to CAP_SYS_RESOURCE, as that more accurately models what we want to control. Suggested-by: Michael Kerrisk <mtk.manpages@googlemail.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- fs/pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/pipe.c b/fs/pipe.c index 369a0245aab6..f98fae3e36b0 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1178,7 +1178,7 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) nr_pages = (arg + PAGE_SIZE - 1) >> PAGE_SHIFT; nr_pages = roundup_pow_of_two(nr_pages); - if (!capable(CAP_SYS_ADMIN) && nr_pages > pipe_max_pages) { + if (!capable(CAP_SYS_RESOURCE) && nr_pages > pipe_max_pages) { ret = -EPERM; goto out; } else if (nr_pages < 1) { -- GitLab From ff9da691c0498ff81fdd014e7a0731dab2337dac Mon Sep 17 00:00:00 2001 From: Jens Axboe <jaxboe@fusionio.com> Date: Thu, 3 Jun 2010 14:54:39 +0200 Subject: [PATCH 592/842] pipe: change /proc/sys/fs/pipe-max-pages to byte sized interface This changes the interface to be based on bytes instead. The API matches that of F_SETPIPE_SZ in that it rounds up the passed in size so that the resulting page array is a power-of-2 in size. The proc file is renamed to /proc/sys/fs/pipe-max-size to reflect this change. Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- fs/pipe.c | 54 ++++++++++++++++++++++++++++++--------- include/linux/pipe_fs_i.h | 4 ++- kernel/sysctl.c | 8 +++--- 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/fs/pipe.c b/fs/pipe.c index f98fae3e36b0..69c4c7c13ea9 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -26,9 +26,14 @@ /* * The max size that a non-root user is allowed to grow the pipe. Can - * be set by root in /proc/sys/fs/pipe-max-pages + * be set by root in /proc/sys/fs/pipe-max-size */ -unsigned int pipe_max_pages = PIPE_DEF_BUFFERS * 16; +unsigned int pipe_max_size = 1048576; + +/* + * Minimum pipe size, as required by POSIX + */ +unsigned int pipe_min_size = PAGE_SIZE; /* * We use a start+len construction, which provides full use of the @@ -1156,6 +1161,35 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) return nr_pages * PAGE_SIZE; } +/* + * Currently we rely on the pipe array holding a power-of-2 number + * of pages. + */ +static inline unsigned int round_pipe_size(unsigned int size) +{ + unsigned long nr_pages; + + nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + return roundup_pow_of_two(nr_pages) << PAGE_SHIFT; +} + +/* + * This should work even if CONFIG_PROC_FS isn't set, as proc_dointvec_minmax + * will return an error. + */ +int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf, + size_t *lenp, loff_t *ppos) +{ + int ret; + + ret = proc_dointvec_minmax(table, write, buf, lenp, ppos); + if (ret < 0 || !write) + return ret; + + pipe_max_size = round_pipe_size(pipe_max_size); + return ret; +} + long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) { struct pipe_inode_info *pipe; @@ -1169,23 +1203,19 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) switch (cmd) { case F_SETPIPE_SZ: { - unsigned long nr_pages; + unsigned int size, nr_pages; - /* - * Currently the array must be a power-of-2 size, so adjust - * upwards if needed. - */ - nr_pages = (arg + PAGE_SIZE - 1) >> PAGE_SHIFT; - nr_pages = roundup_pow_of_two(nr_pages); + size = round_pipe_size(arg); + nr_pages = size >> PAGE_SHIFT; - if (!capable(CAP_SYS_RESOURCE) && nr_pages > pipe_max_pages) { + if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { ret = -EPERM; goto out; - } else if (nr_pages < 1) { + } else if (nr_pages < PAGE_SIZE) { ret = -EINVAL; goto out; } - ret = pipe_set_size(pipe, arg); + ret = pipe_set_size(pipe, nr_pages); break; } case F_GETPIPE_SZ: diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 16de3933c45e..445796945ac9 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -139,7 +139,9 @@ void pipe_lock(struct pipe_inode_info *); void pipe_unlock(struct pipe_inode_info *); void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *); -extern unsigned int pipe_max_pages; +extern unsigned int pipe_max_size, pipe_min_size; +int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *); + /* Drop the inode semaphore and wait for a pipe event, atomically */ void pipe_wait(struct pipe_inode_info *pipe); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 997080f00e0b..d24f761f4876 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1471,12 +1471,12 @@ static struct ctl_table fs_table[] = { }, #endif { - .procname = "pipe-max-pages", - .data = &pipe_max_pages, + .procname = "pipe-max-size", + .data = &pipe_max_size, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .extra1 = &two, + .proc_handler = &pipe_proc_fn, + .extra1 = &pipe_min_size, }, /* * NOTE: do not add new entries to this table unless you have read -- GitLab From a5b365a652206ca300256974ed9301a7d241a6ed Mon Sep 17 00:00:00 2001 From: Christoph Hellwig <hch@lst.de> Date: Tue, 25 May 2010 14:17:54 +0200 Subject: [PATCH 593/842] virtio-blk: fix minimum number of S/G elements We need at least one S/G element to operate properly, as does the block layer which increments it to one anyway. We hit this due to a qemu bug which advertises a sg_elements of 0 under some circumstances. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (tweaked logic) --- drivers/block/virtio_blk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 83fa09a836ca..258bc2ae2885 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -298,7 +298,9 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX, offsetof(struct virtio_blk_config, seg_max), &sg_elems); - if (err) + + /* We need at least one SG element, whatever they say. */ + if (err || !sg_elems) sg_elems = 1; /* We need an extra sg elements at head and tail. */ -- GitLab From 0047634d3daebca9e99a22eb89167bf77f35cdfa Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Thu, 27 May 2010 13:24:39 +0530 Subject: [PATCH 594/842] virtio: console: Fix crash when hot-unplugging a port and read is blocked When removing a port we don't check if a program was blocked for read. This leads to a crash when SIGTERM is sent to the program after hot-unplugging the port. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> --- drivers/char/virtio_console.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8c99bf1b5e9f..e3fb5296cf25 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1099,6 +1099,13 @@ static int remove_port(struct port *port) { struct port_buffer *buf; + if (port->guest_connected) { + port->guest_connected = false; + port->host_connected = false; + wake_up_interruptible(&port->waitqueue); + send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); + } + spin_lock_irq(&port->portdev->ports_lock); list_del(&port->list); spin_unlock_irq(&port->portdev->ports_lock); @@ -1120,9 +1127,6 @@ static int remove_port(struct port *port) hvc_remove(port->cons.hvc); #endif } - if (port->guest_connected) - send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); - sysfs_remove_group(&port->dev->kobj, &port_attribute_group); device_destroy(pdrvdata.class, port->dev->devt); cdev_del(&port->cdev); -- GitLab From 60e5e0b84045ce0f6ab07a02c7fcd6627b53d2d3 Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Thu, 27 May 2010 13:24:40 +0530 Subject: [PATCH 595/842] virtio: console: Fix crash when port is unplugged and blocked for write When a program that has a virtio port opened and blocked for a write operation, a port hot-unplug event will later led to a crash when SIGTERM was sent to the program. Fix that. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> --- drivers/char/virtio_console.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e3fb5296cf25..942a9826bd23 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -529,6 +529,10 @@ static bool will_write_block(struct port *port) { bool ret; + if (!port->guest_connected) { + /* Port got hot-unplugged. Let's exit. */ + return false; + } if (!port->host_connected) return true; -- GitLab From c6df8d5ab87a246942d138321e1721edbb69f6e1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra <a.p.zijlstra@chello.nl> Date: Thu, 3 Jun 2010 11:21:20 +0200 Subject: [PATCH 596/842] perf: Fix crash in swevents Frederic reported that because swevents handling doesn't disable IRQs anymore, we can get a recursion of perf_adjust_period(), once from overflow handling and once from the tick. If both call ->disable, we get a double hlist_del_rcu() and trigger a LIST_POISON2 dereference. Since we don't actually need to stop/start a swevent to re-programm the hardware (lack of hardware to program), simply nop out these callbacks for the swevent pmu. Reported-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1275557609.27810.35218.camel@twins> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- kernel/perf_event.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 858f56fa2432..31d6afe92594 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -4055,13 +4055,6 @@ static void perf_swevent_overflow(struct perf_event *event, u64 overflow, } } -static void perf_swevent_unthrottle(struct perf_event *event) -{ - /* - * Nothing to do, we already reset hwc->interrupts. - */ -} - static void perf_swevent_add(struct perf_event *event, u64 nr, int nmi, struct perf_sample_data *data, struct pt_regs *regs) @@ -4276,11 +4269,22 @@ static void perf_swevent_disable(struct perf_event *event) hlist_del_rcu(&event->hlist_entry); } +static void perf_swevent_void(struct perf_event *event) +{ +} + +static int perf_swevent_int(struct perf_event *event) +{ + return 0; +} + static const struct pmu perf_ops_generic = { .enable = perf_swevent_enable, .disable = perf_swevent_disable, + .start = perf_swevent_int, + .stop = perf_swevent_void, .read = perf_swevent_read, - .unthrottle = perf_swevent_unthrottle, + .unthrottle = perf_swevent_void, /* hwc->interrupts already reset */ }; /* @@ -4561,8 +4565,10 @@ static int swevent_hlist_get(struct perf_event *event) static const struct pmu perf_ops_tracepoint = { .enable = perf_trace_enable, .disable = perf_trace_disable, + .start = perf_swevent_int, + .stop = perf_swevent_void, .read = perf_swevent_read, - .unthrottle = perf_swevent_unthrottle, + .unthrottle = perf_swevent_void, }; static int perf_tp_filter_match(struct perf_event *event, -- GitLab From e7dadc0089da730a1ba2638a1a03533be0c67f11 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@redhat.com> Date: Thu, 3 Jun 2010 18:35:55 -0300 Subject: [PATCH 597/842] perf symbols: Set the DSO long name when using symbol_conf.vmlinux_name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to set the long name to the name specified via, for instance, 'perf annotate --vmlinux /path/to/vmlinux', if not it will remain as '[kernel.kallsyms]' and that will make annotate fail when passing this as the vmlinux name in the call to objdump. The way this is setup grew unwieldly and dso__load_vmlinux is the function that should allocate space for the long name, with callers not assuming that filenames should be allocated somehow by then (strdup, dso__build_id_filename, etc). For now this is the minimalistic patch, a proper fix for .36 will be made. Reported-by: Stephane Eranian <eranian@google.com> Tested-by: Stephane Eranian <eranian@google.com> Cc: David S. Miller <davem@davemloft.net> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <20100604003900.GD10469@ghostprotocols.net> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/symbol.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 7fd6b151feb5..b63e5713849f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1745,7 +1745,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, if (symbol_conf.vmlinux_name != NULL) { err = dso__load_vmlinux(self, map, symbol_conf.vmlinux_name, filter); - goto out_try_fixup; + if (err > 0) { + dso__set_long_name(self, + strdup(symbol_conf.vmlinux_name)); + goto out_fixup; + } + return err; } if (vmlinux_path != NULL) { @@ -1806,7 +1811,6 @@ do_kallsyms: pr_debug("Using %s for symbols\n", kallsyms_filename); free(kallsyms_allocated_filename); -out_try_fixup: if (err > 0) { out_fixup: if (kallsyms_filename != NULL) -- GitLab From c86d1b8ae622e1ea5d20e98bd72fbd7d9dd69016 Mon Sep 17 00:00:00 2001 From: Mike Snitzer <snitzer@redhat.com> Date: Thu, 3 Jun 2010 11:34:52 -0600 Subject: [PATCH 598/842] block: avoid unconditionally freeing previously allocated request_queue On blk_init_allocated_queue_node failure, only free the request_queue if it is wasn't previously allocated outside the block layer (e.g. blk_init_queue_node was blk_init_allocated_queue_node caller). This addresses an interface bug introduced by the following commit: 01effb0 block: allow initialization of previously allocated request_queue Otherwise the request_queue may be free'd out from underneath a caller that is managing the request_queue directly (e.g. caller uses blk_alloc_queue + blk_init_allocated_queue_node). Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- block/blk-core.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 3bc5579d6f54..826d07078902 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -570,9 +570,17 @@ EXPORT_SYMBOL(blk_init_queue); struct request_queue * blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) { - struct request_queue *q = blk_alloc_queue_node(GFP_KERNEL, node_id); + struct request_queue *uninit_q, *q; - return blk_init_allocated_queue_node(q, rfn, lock, node_id); + uninit_q = blk_alloc_queue_node(GFP_KERNEL, node_id); + if (!uninit_q) + return NULL; + + q = blk_init_allocated_queue_node(uninit_q, rfn, lock, node_id); + if (!q) + blk_cleanup_queue(uninit_q); + + return q; } EXPORT_SYMBOL(blk_init_queue_node); @@ -592,10 +600,8 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn, return NULL; q->node = node_id; - if (blk_init_free_list(q)) { - kmem_cache_free(blk_requestq_cachep, q); + if (blk_init_free_list(q)) return NULL; - } q->request_fn = rfn; q->prep_rq_fn = NULL; @@ -618,7 +624,6 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn, return q; } - blk_put_queue(q); return NULL; } EXPORT_SYMBOL(blk_init_allocated_queue_node); -- GitLab From 1abec4fdbb142e3ccb6ce99832fae42129134a96 Mon Sep 17 00:00:00 2001 From: Mike Snitzer <snitzer@redhat.com> Date: Tue, 25 May 2010 13:15:15 -0400 Subject: [PATCH 599/842] block: make blk_init_free_list and elevator_init idempotent blk_init_allocated_queue_node may fail and the caller _could_ retry. Accommodate the unlikely event that blk_init_allocated_queue_node is called on an already initialized (possibly partially) request_queue. Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- block/blk-core.c | 3 +++ block/elevator.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 826d07078902..f84cce42fc58 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -467,6 +467,9 @@ static int blk_init_free_list(struct request_queue *q) { struct request_list *rl = &q->rq; + if (unlikely(rl->rq_pool)) + return 0; + rl->count[BLK_RW_SYNC] = rl->count[BLK_RW_ASYNC] = 0; rl->starved[BLK_RW_SYNC] = rl->starved[BLK_RW_ASYNC] = 0; rl->elvpriv = 0; diff --git a/block/elevator.c b/block/elevator.c index 0abce473d606..923a9139106c 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -242,9 +242,11 @@ int elevator_init(struct request_queue *q, char *name) { struct elevator_type *e = NULL; struct elevator_queue *eq; - int ret = 0; void *data; + if (unlikely(q->elevator)) + return 0; + INIT_LIST_HEAD(&q->queue_head); q->last_merge = NULL; q->end_sector = 0; @@ -284,7 +286,7 @@ int elevator_init(struct request_queue *q, char *name) } elevator_attach(q, eq, data); - return ret; + return 0; } EXPORT_SYMBOL(elevator_init); -- GitLab From 1e5ea23df11c7c90c7e7268dd3a6603bfa5aadf7 Mon Sep 17 00:00:00 2001 From: Sage Weil <sage@newdream.net> Date: Fri, 4 Jun 2010 10:05:40 -0700 Subject: [PATCH 600/842] ceph: fix lease revocation when seq doesn't match If the client revokes a lease with a higher seq than what we have, keep the mds's seq, so that it honors our release. Otherwise, we can hang indefinitely. Signed-off-by: Sage Weil <sage@newdream.net> --- fs/ceph/mds_client.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index b49f12822cbc..29b4485cf1ca 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2433,6 +2433,7 @@ static void handle_lease(struct ceph_mds_client *mdsc, struct ceph_dentry_info *di; int mds = session->s_mds; struct ceph_mds_lease *h = msg->front.iov_base; + u32 seq; struct ceph_vino vino; int mask; struct qstr dname; @@ -2446,6 +2447,7 @@ static void handle_lease(struct ceph_mds_client *mdsc, vino.ino = le64_to_cpu(h->ino); vino.snap = CEPH_NOSNAP; mask = le16_to_cpu(h->mask); + seq = le32_to_cpu(h->seq); dname.name = (void *)h + sizeof(*h) + sizeof(u32); dname.len = msg->front.iov_len - sizeof(*h) - sizeof(u32); if (dname.len != get_unaligned_le32(h+1)) @@ -2456,8 +2458,9 @@ static void handle_lease(struct ceph_mds_client *mdsc, /* lookup inode */ inode = ceph_find_inode(sb, vino); - dout("handle_lease '%s', mask %d, ino %llx %p\n", - ceph_lease_op_name(h->action), mask, vino.ino, inode); + dout("handle_lease %s, mask %d, ino %llx %p %.*s\n", + ceph_lease_op_name(h->action), mask, vino.ino, inode, + dname.len, dname.name); if (inode == NULL) { dout("handle_lease no inode %llx\n", vino.ino); goto release; @@ -2482,7 +2485,8 @@ static void handle_lease(struct ceph_mds_client *mdsc, switch (h->action) { case CEPH_MDS_LEASE_REVOKE: if (di && di->lease_session == session) { - h->seq = cpu_to_le32(di->lease_seq); + if (ceph_seq_cmp(di->lease_seq, seq) > 0) + h->seq = cpu_to_le32(di->lease_seq); __ceph_mdsc_drop_dentry_lease(dentry); } release = 1; @@ -2496,7 +2500,7 @@ static void handle_lease(struct ceph_mds_client *mdsc, unsigned long duration = le32_to_cpu(h->duration_ms) * HZ / 1000; - di->lease_seq = le32_to_cpu(h->seq); + di->lease_seq = seq; dentry->d_time = di->lease_renew_from + duration; di->lease_renew_after = di->lease_renew_from + (duration >> 1); -- GitLab From 157317ba3ec3e5a4d9683b8d24ba40b4f8f3296b Mon Sep 17 00:00:00 2001 From: Zhao Yakui <yakui.zhao@intel.com> Date: Wed, 2 Jun 2010 11:04:09 +0800 Subject: [PATCH 601/842] ACPI: Fix the incorrect calculation about C-state idle time The C-state idle time is not calculated correctly, which will return the wrong residency time in C-state. It will have the following effects: 1. The system can't choose the deeper C-state when it is idle next time. Of course the system power is increased. E.g. On one server machine about 40W idle power is increased. 2. The powertop shows that it will stay in C0 running state about 95% time although the system is idle at most time. 2.6.35-rc1 regression caused-by: 2da513f582a96c053aacc2c92873978d2ea7abff (ACPI: Minor cleanup eliminating redundant PMTIMER_TICKS to NS conversion) Signed-off-by: Zhao Yakui <yakui.zhao@intel.com> Reported-by: Yu Zhidong <zhidong.yu@intel.com> Tested-by: Yu Zhidong <zhidong.yu@intel.com> Acked-by: Venkatesh Pallipadi <venki@google.com> Signed-off-by: Len Brown <len.brown@intel.com> --- drivers/acpi/processor_idle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 2e8c27d48f2b..6b38a6b43ce8 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1022,7 +1022,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, spin_unlock(&c3_lock); } kt2 = ktime_get_real(); - idle_time_ns = ktime_to_us(ktime_sub(kt2, kt1)); + idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1)); idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); -- GitLab From bceefad59ab66d1b1a815a1738744ea013da966e Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi <venki@google.com> Date: Wed, 2 Jun 2010 10:01:09 -0700 Subject: [PATCH 602/842] ACPI: Eliminate us to pm ticks conversion in common path acpi_enter_[simple|bm] routines does us to pm tick conversion on every idle wakeup and the value is only used in /proc/acpi display. We can store the time in us and convert it into pm ticks before printing instead and avoid the conversion in the common path. Signed-off-by: Venkatesh Pallipadi <venki@google.com> Signed-off-by: Len Brown <len.brown@intel.com> --- drivers/acpi/processor_idle.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 6b38a6b43ce8..b1b385692f46 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -80,7 +80,7 @@ module_param(nocst, uint, 0000); static unsigned int latency_factor __read_mostly = 2; module_param(latency_factor, uint, 0644); -static s64 us_to_pm_timer_ticks(s64 t) +static u64 us_to_pm_timer_ticks(s64 t) { return div64_u64(t * PM_TIMER_FREQUENCY, 1000000); } @@ -731,10 +731,10 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset) seq_puts(seq, "demotion[--] "); - seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n", + seq_printf(seq, "latency[%03d] usage[%08d] duration[%020Lu]\n", pr->power.states[i].latency, pr->power.states[i].usage, - (unsigned long long)pr->power.states[i].time); + us_to_pm_timer_ticks(pr->power.states[i].time)); } end: @@ -861,7 +861,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; - s64 sleep_ticks = 0; pr = __get_cpu_var(processors); @@ -906,8 +905,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); - sleep_ticks = us_to_pm_timer_ticks(idle_time); - /* Tell the scheduler how much we idled: */ sched_clock_idle_wakeup_event(idle_time_ns); @@ -918,7 +915,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, cx->usage++; lapic_timer_state_broadcast(pr, cx, 0); - cx->time += sleep_ticks; + cx->time += idle_time; return idle_time; } @@ -940,7 +937,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; - s64 sleep_ticks = 0; pr = __get_cpu_var(processors); @@ -1026,7 +1022,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); - sleep_ticks = us_to_pm_timer_ticks(idle_time); /* Tell the scheduler how much we idled: */ sched_clock_idle_wakeup_event(idle_time_ns); @@ -1037,7 +1032,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, cx->usage++; lapic_timer_state_broadcast(pr, cx, 0); - cx->time += sleep_ticks; + cx->time += idle_time; return idle_time; } -- GitLab From 56bf882230d2266a2e07b7f404dc96d157a65daa Mon Sep 17 00:00:00 2001 From: "John W. Linville" <linville@tuxdriver.com> Date: Fri, 4 Jun 2010 14:47:35 -0400 Subject: [PATCH 603/842] Revert "wireless: hostap, fix oops due to early probing interrupt" This reverts commit 15920d8afc87861672e16fa95ae2764b065d6dd3. This patch was discovered to cause some hostap devices to fail to initialized. https://bugzilla.kernel.org/show_bug.cgi?id=16111 Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/hostap/hostap_hw.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index d70732819423..ff9b5c882184 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -2618,15 +2618,6 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id) int events = 0; u16 ev; - /* Detect early interrupt before driver is fully configued */ - if (!dev->base_addr) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n", - dev->name); - } - return IRQ_HANDLED; - } - iface = netdev_priv(dev); local = iface->local; -- GitLab From 8b9a4e6e442756f670ef507f09bbc6c11dc0fca6 Mon Sep 17 00:00:00 2001 From: Johannes Berg <johannes.berg@intel.com> Date: Fri, 28 May 2010 15:22:58 +0200 Subject: [PATCH 604/842] mac80211: process station blockack action frames from work Processing an association response could take a bit of time while we set up the hardware etc. During that time, the AP might already send a blockack request. If this happens very quickly on a fairly slow machine, we can end up processing the blockack request before the association processing has finished. Since the blockack processing cannot sleep right now, we also cannot make it wait in the driver. As a result, sometimes on slow machines the iwlagn driver gets totally confused, and no traffic can pass when the aggregation setup was done before the assoc setup completed. I'm working on a proper fix for this, which involves queuing all blockack category action frames from a work struct, and also allowing the ampdu_action driver callback to sleep, which will generally clean up the code and make things easier. However, this is a very involved and complex change. To fix the problem at hand in a way that can also be backported to stable, I've come up with this patch. Here, I simply process all aggregation action frames from the managed interface skb queue, which means their processing will be serialized with processing the association response, thereby fixing the problem. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Cc: stable@kernel.org Signed-off-by: John W. Linville <linville@tuxdriver.com> --- net/mac80211/mlme.c | 52 +++++++++++++++++++++++++++++++++++++++------ net/mac80211/rx.c | 3 +++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0839c4e8fd2e..3310e70aa52f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1692,14 +1692,52 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); break; case IEEE80211_STYPE_ACTION: - if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT) + switch (mgmt->u.action.category) { + case WLAN_CATEGORY_BACK: { + struct ieee80211_local *local = sdata->local; + int len = skb->len; + struct sta_info *sta; + + rcu_read_lock(); + sta = sta_info_get(sdata, mgmt->sa); + if (!sta) { + rcu_read_unlock(); + break; + } + + local_bh_disable(); + + switch (mgmt->u.action.u.addba_req.action_code) { + case WLAN_ACTION_ADDBA_REQ: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.addba_req))) + break; + ieee80211_process_addba_request(local, sta, mgmt, len); + break; + case WLAN_ACTION_ADDBA_RESP: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.addba_resp))) + break; + ieee80211_process_addba_resp(local, sta, mgmt, len); + break; + case WLAN_ACTION_DELBA: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.delba))) + break; + ieee80211_process_delba(sdata, sta, mgmt, len); + break; + } + local_bh_enable(); + rcu_read_unlock(); break; - - ieee80211_sta_process_chanswitch(sdata, - &mgmt->u.action.u.chan_switch.sw_elem, - (void *)ifmgd->associated->priv, - rx_status->mactime); - break; + } + case WLAN_CATEGORY_SPECTRUM_MGMT: + ieee80211_sta_process_chanswitch(sdata, + &mgmt->u.action.u.chan_switch.sw_elem, + (void *)ifmgd->associated->priv, + rx_status->mactime); + break; + } } mutex_unlock(&ifmgd->mtx); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5e0b65406c44..be9abc2e6348 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1944,6 +1944,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (len < IEEE80211_MIN_ACTION_SIZE + 1) break; + if (sdata->vif.type == NL80211_IFTYPE_STATION) + return ieee80211_sta_rx_mgmt(sdata, rx->skb); + switch (mgmt->u.action.u.addba_req.action_code) { case WLAN_ACTION_ADDBA_REQ: if (len < (IEEE80211_MIN_ACTION_SIZE + -- GitLab From e307139d7ad532761cdbf2a665f3c53c509a2d0e Mon Sep 17 00:00:00 2001 From: Tobias Doerffel <tobias.doerffel@gmail.com> Date: Sun, 30 May 2010 00:02:18 +0200 Subject: [PATCH 605/842] ath5k: depend on CONFIG_PM_SLEEP for suspend/resume functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building a kernel with CONFIG_PM=y but neither suspend nor hibernate support, the compiler complains about the static functions ath5k_pci_suspend() and ath5k_pci_resume() not being used: drivers/net/wireless/ath/ath5k/base.c:713:12: warning: ‘ath5k_pci_suspend’ defined but not used drivers/net/wireless/ath/ath5k/base.c:722:12: warning: ‘ath5k_pci_resume’ defined but not used Depending on CONFIG_PM_SLEEP rather than CONFIG_PM fixes the issue. Signed-off-by: Tobias Doerffel <tobias.doerffel@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/ath/ath5k/base.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 2978359c4366..53d95c83b11a 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -195,7 +195,7 @@ static const struct ieee80211_rate ath5k_rates[] = { static int __devinit ath5k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void __devexit ath5k_pci_remove(struct pci_dev *pdev); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ath5k_pci_suspend(struct device *dev); static int ath5k_pci_resume(struct device *dev); @@ -203,7 +203,7 @@ static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume); #define ATH5K_PM_OPS (&ath5k_pm_ops) #else #define ATH5K_PM_OPS NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ static struct pci_driver ath5k_pci_driver = { .name = KBUILD_MODNAME, @@ -708,7 +708,7 @@ ath5k_pci_remove(struct pci_dev *pdev) ieee80211_free_hw(hw); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ath5k_pci_suspend(struct device *dev) { struct ieee80211_hw *hw = pci_get_drvdata(to_pci_dev(dev)); @@ -734,7 +734,7 @@ static int ath5k_pci_resume(struct device *dev) ath5k_led_enable(sc); return 0; } -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ /***********************\ -- GitLab From 6b5dcccb495b66b3b0b9581cdccfed038e5d68a2 Mon Sep 17 00:00:00 2001 From: Bob Copeland <me@bobcopeland.com> Date: Fri, 4 Jun 2010 08:14:14 -0400 Subject: [PATCH 606/842] ath5k: retain promiscuous setting Commit 56d1de0a21db28e41741cfa0a66e18bc8d920554, "ath5k: clean up filter flags setting" introduced a regression in monitor mode such that the promisc filter flag would get lost. Although we set the promisc flag when it changed, we did not preserve it across subsequent calls to configure_filter. This patch restores the original functionality. Cc: stable@kernel.org Bisected-by: weedy2887@gmail.com Tested-by: weedy2887@gmail.com Tested-by: Rick Farina <sidhayn@gmail.com> Signed-off-by: Bob Copeland <me@bobcopeland.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/ath/ath5k/base.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 53d95c83b11a..648972df369d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -3140,13 +3140,15 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { if (*new_flags & FIF_PROMISC_IN_BSS) { - rfilt |= AR5K_RX_FILTER_PROM; __set_bit(ATH_STAT_PROMISC, sc->status); } else { __clear_bit(ATH_STAT_PROMISC, sc->status); } } + if (test_bit(ATH_STAT_PROMISC, sc->status)) + rfilt |= AR5K_RX_FILTER_PROM; + /* Note, AR5K_RX_FILTER_MCAST is already enabled */ if (*new_flags & FIF_ALLMULTI) { mfilt[0] = ~0; -- GitLab From b41709f1263bb1ad37efc43fea0bb0b670c12e78 Mon Sep 17 00:00:00 2001 From: Johan Hovold <jhovold@gmail.com> Date: Wed, 19 May 2010 22:13:17 +0200 Subject: [PATCH 607/842] USB: mos7840: fix null-pointer dereference Fix null-pointer dereference on error path. Cc: stable <stable@kernel.org> Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/serial/mos7840.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index f8424d1bfc1b..585b7e663740 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -730,7 +730,6 @@ static void mos7840_bulk_in_callback(struct urb *urb) mos7840_port = urb->context; if (!mos7840_port) { dbg("%s", "NULL mos7840_port pointer"); - mos7840_port->read_urb_busy = false; return; } -- GitLab From 0c8a32dff4f9ebed3e067e52e12842d7d7e047a0 Mon Sep 17 00:00:00 2001 From: Mike Frysinger <vapier@gentoo.org> Date: Fri, 21 May 2010 04:37:42 -0400 Subject: [PATCH 608/842] USB: isp1362: fix inw warning on Blackfin systems The Blackfin code is incorrectly casting the argument to inw() to a pointer. Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/host/isp1362.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h index 5151516ea1de..d995351f9bed 100644 --- a/drivers/usb/host/isp1362.h +++ b/drivers/usb/host/isp1362.h @@ -65,7 +65,7 @@ static inline void delayed_insw(unsigned int addr, void *buf, int len) unsigned short *bp = (unsigned short *)buf; while (len--) { DUMMY_DELAY_ACCESS; - *bp++ = inw((void *)addr); + *bp++ = inw(addr); } } -- GitLab From 2d62f3eea98354d61f90d6b115eecf9be5f4bdfe Mon Sep 17 00:00:00 2001 From: Sarah Sharp <sarah.a.sharp@linux.intel.com> Date: Mon, 24 May 2010 13:25:15 -0700 Subject: [PATCH 609/842] USB: xhci: Wait for controller to be ready after reset. After software resets an xHCI host controller, it must wait for the "Controller Not Ready" (CNR) bit in the status register to be cleared. Software is not supposed to ring any doorbells or write to any registers except the status register until this bit is cleared. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/host/xhci.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 40e0a0c221b8..79ccfe5f8ad0 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -116,6 +116,7 @@ int xhci_reset(struct xhci_hcd *xhci) { u32 command; u32 state; + int ret; state = xhci_readl(xhci, &xhci->op_regs->status); if ((state & STS_HALT) == 0) { @@ -130,7 +131,17 @@ int xhci_reset(struct xhci_hcd *xhci) /* XXX: Why does EHCI set this here? Shouldn't other code do this? */ xhci_to_hcd(xhci)->state = HC_STATE_HALT; - return handshake(xhci, &xhci->op_regs->command, CMD_RESET, 0, 250 * 1000); + ret = handshake(xhci, &xhci->op_regs->command, + CMD_RESET, 0, 250 * 1000); + if (ret) + return ret; + + xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n"); + /* + * xHCI cannot write to any doorbells or operational registers other + * than status until the "Controller Not Ready" flag is cleared. + */ + return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); } -- GitLab From ed07453fd356025cc25272629e982f5e4607632c Mon Sep 17 00:00:00 2001 From: Sarah Sharp <sarah.a.sharp@linux.intel.com> Date: Mon, 24 May 2010 13:25:21 -0700 Subject: [PATCH 610/842] USB: xhci: Wait for host to start running. When the run bit is set in the xHCI command register, it may take a few microseconds for the host to start running. We cannot ring any doorbells until the host is actually running, so wait until the status register says the host is running. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Reported-by: Shinya Saito <shinya.saito.sx@renesas.com> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/host/xhci.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 79ccfe5f8ad0..8a49c6716b69 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -105,6 +105,33 @@ int xhci_halt(struct xhci_hcd *xhci) STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); } +/* + * Set the run bit and wait for the host to be running. + */ +int xhci_start(struct xhci_hcd *xhci) +{ + u32 temp; + int ret; + + temp = xhci_readl(xhci, &xhci->op_regs->command); + temp |= (CMD_RUN); + xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", + temp); + xhci_writel(xhci, temp, &xhci->op_regs->command); + + /* + * Wait for the HCHalted Status bit to be 0 to indicate the host is + * running. + */ + ret = handshake(xhci, &xhci->op_regs->status, + STS_HALT, 0, XHCI_MAX_HALT_USEC); + if (ret == -ETIMEDOUT) + xhci_err(xhci, "Host took too long to start, " + "waited %u microseconds.\n", + XHCI_MAX_HALT_USEC); + return ret; +} + /* * Reset a halted HC, and set the internal HC state to HC_STATE_HALT. * @@ -460,13 +487,11 @@ int xhci_run(struct usb_hcd *hcd) if (NUM_TEST_NOOPS > 0) doorbell = xhci_setup_one_noop(xhci); - temp = xhci_readl(xhci, &xhci->op_regs->command); - temp |= (CMD_RUN); - xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", - temp); - xhci_writel(xhci, temp, &xhci->op_regs->command); - /* Flush PCI posted writes */ - temp = xhci_readl(xhci, &xhci->op_regs->command); + if (xhci_start(xhci)) { + xhci_halt(xhci); + return -ENODEV; + } + xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp); if (doorbell) (*doorbell)(xhci); -- GitLab From 0238634d02dd10b678ebe9ea5d8803483277ee93 Mon Sep 17 00:00:00 2001 From: Sarah Sharp <sarah.a.sharp@linux.intel.com> Date: Mon, 24 May 2010 13:25:28 -0700 Subject: [PATCH 611/842] USB: xhci: Print NEC firmware version. The NEC xHCI host controller firmware version can be found by putting a vendor-specific command on the command ring and extracting the BCD encoded-version out of the vendor-specific event TRB. The firmware version debug line in dmesg will look like: xhci_hcd 0000:05:00.0: NEC firmware version 30.21 (NEC merged with Renesas Technologies and became Renesas Electronics on April 1, 2010. I have their OK to merge this vendor-specific code.) Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: Satoshi Otani <satoshi.otani.xm@renesas.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/host/xhci-pci.c | 2 ++ drivers/usb/host/xhci-ring.c | 31 ++++++++++++++++++++++++++++++- drivers/usb/host/xhci.c | 5 +++++ drivers/usb/host/xhci.h | 12 ++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index edffd81fc253..11482b6b9381 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -78,6 +78,8 @@ static int xhci_pci_setup(struct usb_hcd *hcd) xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" " endpoint cmd after reset endpoint\n"); } + if (pdev->vendor == PCI_VENDOR_ID_NEC) + xhci->quirks |= XHCI_NEC_HOST; /* Make sure the HC is halted. */ retval = xhci_halt(xhci); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 36c858e5b529..9012098add6b 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1071,6 +1071,15 @@ bandwidth_change: xhci_warn(xhci, "Reset device command completion " "for disabled slot %u\n", slot_id); break; + case TRB_TYPE(TRB_NEC_GET_FW): + if (!(xhci->quirks & XHCI_NEC_HOST)) { + xhci->error_bitmask |= 1 << 6; + break; + } + xhci_dbg(xhci, "NEC firmware version %2x.%02x\n", + NEC_FW_MAJOR(event->status), + NEC_FW_MINOR(event->status)); + break; default: /* Skip over unknown commands on the event ring */ xhci->error_bitmask |= 1 << 6; @@ -1079,6 +1088,17 @@ bandwidth_change: inc_deq(xhci, xhci->cmd_ring, false); } +static void handle_vendor_event(struct xhci_hcd *xhci, + union xhci_trb *event) +{ + u32 trb_type; + + trb_type = TRB_FIELD_TO_TYPE(event->generic.field[3]); + xhci_dbg(xhci, "Vendor specific event TRB type = %u\n", trb_type); + if (trb_type == TRB_NEC_CMD_COMP && (xhci->quirks & XHCI_NEC_HOST)) + handle_cmd_completion(xhci, &event->event_cmd); +} + static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event) { @@ -1659,7 +1679,10 @@ void xhci_handle_event(struct xhci_hcd *xhci) update_ptrs = 0; break; default: - xhci->error_bitmask |= 1 << 3; + if ((event->event_cmd.flags & TRB_TYPE_BITMASK) >= TRB_TYPE(48)) + handle_vendor_event(xhci, event); + else + xhci->error_bitmask |= 1 << 3; } /* Any of the above functions may drop and re-acquire the lock, so check * to make sure a watchdog timer didn't mark the host as non-responsive. @@ -2378,6 +2401,12 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, false); } +int xhci_queue_vendor_command(struct xhci_hcd *xhci, + u32 field1, u32 field2, u32 field3, u32 field4) +{ + return queue_command(xhci, field1, field2, field3, field4, false); +} + /* Queue a reset device command TRB */ int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8a49c6716b69..27345cd04da0 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -486,6 +486,9 @@ int xhci_run(struct usb_hcd *hcd) if (NUM_TEST_NOOPS > 0) doorbell = xhci_setup_one_noop(xhci); + if (xhci->quirks & XHCI_NEC_HOST) + xhci_queue_vendor_command(xhci, 0, 0, 0, + TRB_TYPE(TRB_NEC_GET_FW)); if (xhci_start(xhci)) { xhci_halt(xhci); @@ -495,6 +498,8 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp); if (doorbell) (*doorbell)(xhci); + if (xhci->quirks & XHCI_NEC_HOST) + xhci_ring_cmd_db(xhci); xhci_dbg(xhci, "Finished xhci_run\n"); return 0; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index dada2fb59261..8b4b7d39f79c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -925,6 +925,7 @@ union xhci_trb { /* TRB bit mask */ #define TRB_TYPE_BITMASK (0xfc00) #define TRB_TYPE(p) ((p) << 10) +#define TRB_FIELD_TO_TYPE(p) (((p) & TRB_TYPE_BITMASK) >> 10) /* TRB type IDs */ /* bulk, interrupt, isoc scatter/gather, and control data stage */ #define TRB_NORMAL 1 @@ -992,6 +993,14 @@ union xhci_trb { #define TRB_MFINDEX_WRAP 39 /* TRB IDs 40-47 reserved, 48-63 is vendor-defined */ +/* Nec vendor-specific command completion event. */ +#define TRB_NEC_CMD_COMP 48 +/* Get NEC firmware revision. */ +#define TRB_NEC_GET_FW 49 + +#define NEC_FW_MINOR(p) (((p) >> 0) & 0xff) +#define NEC_FW_MAJOR(p) (((p) >> 8) & 0xff) + /* * TRBS_PER_SEGMENT must be a multiple of 4, * since the command ring is 64-byte aligned. @@ -1172,6 +1181,7 @@ struct xhci_hcd { unsigned int quirks; #define XHCI_LINK_TRB_QUIRK (1 << 0) #define XHCI_RESET_EP_QUIRK (1 << 1) +#define XHCI_NEC_HOST (1 << 2) }; /* For testing purposes */ @@ -1379,6 +1389,8 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci); int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id); +int xhci_queue_vendor_command(struct xhci_hcd *xhci, + u32 field1, u32 field2, u32 field3, u32 field4); int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, unsigned int ep_index); int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, -- GitLab From 390b166138e95a47bdfde6582a1935f65e5c6547 Mon Sep 17 00:00:00 2001 From: Thomas Abraham <thomas.ab@samsung.com> Date: Mon, 24 May 2010 17:48:56 +0900 Subject: [PATCH 612/842] USB: s3c: Enable soft disconnect during initialization Enable soft disconnect bit the OTG core during initialization. Without this, the host sees that a gadget is connected and tries to enumerate. The soft disconnect should be enabled until the USB gadget driver is registered with this otg driver. Signed-off-by: Thomas Abraham <thomas.ab@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/gadget/s3c-hsotg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 1f73b485732d..a6d725dd7335 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2730,6 +2730,9 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg) writel(0, hsotg->regs + S3C_DAINTMSK); + /* Be in disconnected state until gadget is registered */ + __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); + if (0) { /* post global nak until we're ready */ writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak, -- GitLab From 0287e43dda1a425da662f879dd27352021b0ca63 Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere <mcuelenaere@gmail.com> Date: Tue, 25 May 2010 05:36:49 +0100 Subject: [PATCH 613/842] USB: s3c_hsotg: define USB_GADGET_DUALSPEED in Kconfig The s3c_hsotg driver sets usb_gadget->is_dualspeed to 1, yet it doesn't define USB_GADGET_DUALSPEED in Kconfig. This triggers a NULL pointer dereference in the composite driver (which is fixed in another patch). Signed-off-by: Maurus Cuelenaere <mcuelenaere@gmail.com> Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/gadget/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 649c0c5f7158..591ae9fde199 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -295,6 +295,7 @@ config USB_GADGET_S3C_HSOTG boolean "S3C HS/OtG USB Device controller" depends on S3C_DEV_USB_HSOTG select USB_GADGET_S3C_HSOTG_PIO + select USB_GADGET_DUALSPEED help The Samsung S3C64XX USB2.0 high-speed gadget controller integrated into the S3C64XX series SoC. -- GitLab From 0f002d200598918f5058dfcfda3da46f29019765 Mon Sep 17 00:00:00 2001 From: Ben Dooks <ben-linux@fluff.org> Date: Tue, 25 May 2010 05:36:50 +0100 Subject: [PATCH 614/842] USB: s3c-hsotg: Ensure TX FIFO addresses setup when initialising FIFOs Some versions of the S3C HS OtG block startup with overlapping TX FIFO information, so change the fifo_init code to ensure that known values are set into the FIFO registers at initialisation/reset time. This also ensures that the FIFO RAM pointers are in a known state before use. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/gadget/s3c-hsotg.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index a6d725dd7335..9abf96c5715d 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -297,6 +297,11 @@ static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, */ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) { + unsigned int ep; + unsigned int addr; + unsigned int size; + u32 val; + /* the ryu 2.6.24 release ahs writel(0x1C0, hsotg->regs + S3C_GRXFSIZ); writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) | @@ -310,6 +315,26 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) | S3C_GNPTXFSIZ_NPTxFDep(0x1C0), hsotg->regs + S3C_GNPTXFSIZ); + + /* arange all the rest of the TX FIFOs, as some versions of this + * block have overlapping default addresses. This also ensures + * that if the settings have been changed, then they are set to + * known values. */ + + /* start at the end of the GNPTXFSIZ, rounded up */ + addr = 2048 + 1024; + size = 768; + + /* currently we allocate TX FIFOs for all possible endpoints, + * and assume that they are all the same size. */ + + for (ep = 0; ep <= 15; ep++) { + val = addr; + val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT; + addr += size; + + writel(val, hsotg->regs + S3C_DPTXFSIZn(ep)); + } } /** -- GitLab From 2e0e0777ec2ea1cb5461bded2c09573a9d778622 Mon Sep 17 00:00:00 2001 From: Ben Dooks <ben-linux@fluff.org> Date: Tue, 25 May 2010 05:36:51 +0100 Subject: [PATCH 615/842] USB: s3c-hsotg: SoftDisconnect minimum 3ms The shortest period SoftDisconnect can be asserted for is 3 milliseconds according to the V210 datasheet, so ensure that we add an msleep() to the registration code to enforce this. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/gadget/s3c-hsotg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 9abf96c5715d..31d19e1f261d 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2599,6 +2599,9 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL); + /* must be at-least 3ms to allow bus to see disconnect */ + msleep(3); + /* remove the soft-disconnect and let's go */ __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); -- GitLab From 1703a6d3c38944731ba23594843a704d828266f3 Mon Sep 17 00:00:00 2001 From: Ben Dooks <ben-linux@fluff.org> Date: Tue, 25 May 2010 05:36:52 +0100 Subject: [PATCH 616/842] USB: s3c-hsotg: Ensure FIFOs are fully flushed after layout According to the design guide, if the FIFO layout is changed, then the FIFOs must be flushed to ensure all FIFO pointers are correct. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/gadget/s3c-hsotg.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 31d19e1f261d..26193eceb323 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -300,6 +300,7 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) unsigned int ep; unsigned int addr; unsigned int size; + int timeout; u32 val; /* the ryu 2.6.24 release ahs @@ -335,6 +336,31 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) writel(val, hsotg->regs + S3C_DPTXFSIZn(ep)); } + + /* according to p428 of the design guide, we need to ensure that + * all fifos are flushed before continuing */ + + writel(S3C_GRSTCTL_TxFNum(0x10) | S3C_GRSTCTL_TxFFlsh | + S3C_GRSTCTL_RxFFlsh, hsotg->regs + S3C_GRSTCTL); + + /* wait until the fifos are both flushed */ + timeout = 100; + while (1) { + val = readl(hsotg->regs + S3C_GRSTCTL); + + if ((val & (S3C_GRSTCTL_TxFFlsh | S3C_GRSTCTL_RxFFlsh)) == 0) + break; + + if (--timeout == 0) { + dev_err(hsotg->dev, + "%s: timeout flushing fifos (GRSTCTL=%08x)\n", + __func__, val); + } + + udelay(1); + } + + dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); } /** -- GitLab From 6a1a82df91fa0eb1cc76069a9efe5714d087eccd Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@caiaq.de> Date: Thu, 3 Jun 2010 13:55:02 +0200 Subject: [PATCH 617/842] USB: ftdi_sio: fix DTR/RTS line modes Call set_mctrl() and clear_mctrl() according to the flow control mode selected. This makes serial communication for FT232 connected devices work when CRTSCTS is not set. This fixes a regression introduced by 4175f3e31 ("tty_port: If we are opened non blocking we still need to raise the carrier"). This patch calls the low-level driver's dtr_rts() function which consequently sets TIOCM_DTR | TIOCM_RTS. A later call to set_termios() without CRTSCTS in cflags, however, does not reset these bits, and so data is not actually sent out on the serial wire. Signed-off-by: Daniel Mack <daniel@caiaq.de> Cc: Johan Hovold <jhovold@gmail.com> Cc: Alan Cox <alan@linux.intel.com> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/serial/ftdi_sio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 050211afc07e..79dd1ae195e5 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2005,6 +2005,8 @@ static void ftdi_set_termios(struct tty_struct *tty, "urb failed to set to rts/cts flow control\n"); } + /* raise DTR/RTS */ + set_mctrl(port, TIOCM_DTR | TIOCM_RTS); } else { /* * Xon/Xoff code @@ -2052,6 +2054,8 @@ static void ftdi_set_termios(struct tty_struct *tty, } } + /* lower DTR/RTS */ + clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } return; } -- GitLab From c2572b78aa0447244a38e555ebb1b3b48a0088a5 Mon Sep 17 00:00:00 2001 From: Axel Lin <axel.lin@gmail.com> Date: Mon, 31 May 2010 08:04:47 +0800 Subject: [PATCH 618/842] USB: cdc-acm: fix resource reclaim in error path of acm_probe This patch fixes resource reclaim in error path of acm_probe: 1. In the case of "out of memory (read urbs usb_alloc_urb)\n")", there is no need to call acm_read_buffers_free(acm) here. Fix it by goto alloc_fail6 instead of alloc_fail7. 2. In the case of "out of memory (write urbs usb_alloc_urb)", usb_alloc_urb may fail in any iteration of the for loop. Current implementation does not properly free allocated snd->urb. Fix it by goto alloc_fail8 instead of alloc_fail7. 3. In the case of device_create_file(&intf->dev,&dev_attr_iCountryCodeRelDate) fail, acm->country_codes is kfreed. As a result, device_remove_file for dev_attr_wCountryCodes will not be executed in acm_disconnect. Fix it by calling device_remove_file for dev_attr_wCountryCodes before goto skip_countries. Signed-off-by: Axel Lin <axel.lin@gmail.com> Acked-by: Oliver Neukum <oneukum@suse.de> Cc: stable <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/class/cdc-acm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 0c2f14ff9696..61d75507d5d0 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1201,7 +1201,7 @@ made_compressed_probe: if (rcv->urb == NULL) { dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); - goto alloc_fail7; + goto alloc_fail6; } rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -1225,7 +1225,7 @@ made_compressed_probe: if (snd->urb == NULL) { dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)"); - goto alloc_fail7; + goto alloc_fail8; } if (usb_endpoint_xfer_int(epwrite)) @@ -1264,6 +1264,7 @@ made_compressed_probe: i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); if (i < 0) { + device_remove_file(&intf->dev, &dev_attr_wCountryCodes); kfree(acm->country_codes); goto skip_countries; } @@ -1300,6 +1301,7 @@ alloc_fail8: usb_free_urb(acm->wb[i].urb); alloc_fail7: acm_read_buffers_free(acm); +alloc_fail6: for (i = 0; i < num_rx_buf; i++) usb_free_urb(acm->ru[i].urb); usb_free_urb(acm->ctrlurb); -- GitLab From 1f23b2d98c11fed43c552a5dbd00c793f81a8736 Mon Sep 17 00:00:00 2001 From: Grant Likely <grant.likely@secretlab.ca> Date: Wed, 2 Jun 2010 13:53:17 -0600 Subject: [PATCH 619/842] usb: fix ehci_hcd build failure when both generic-OF and xilinx is selected This patch fixes the driver to allow both CONFIG_USB_EHCI_HCD_PPC_OF and CONFIG_USB_ECHI_HCD_XILINX to be selected. Signed-off-by: Grant Likely <grant.likely@secretlab.ca> CC: John Linn <john.linn@xilinx.com> CC: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/host/ehci-hcd.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index ef3e88f0b3c3..a3ef2a9d9dc2 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1135,7 +1135,7 @@ MODULE_LICENSE ("GPL"); #ifdef CONFIG_XPS_USB_HCD_XILINX #include "ehci-xilinx-of.c" -#define OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver +#define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver #endif #ifdef CONFIG_PLAT_ORION @@ -1159,7 +1159,8 @@ MODULE_LICENSE ("GPL"); #endif #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) + !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ + !defined(XILINX_OF_PLATFORM_DRIVER) #error "missing bus glue for ehci-hcd" #endif @@ -1213,10 +1214,20 @@ static int __init ehci_hcd_init(void) if (retval < 0) goto clean3; #endif + +#ifdef XILINX_OF_PLATFORM_DRIVER + retval = of_register_platform_driver(&XILINX_OF_PLATFORM_DRIVER); + if (retval < 0) + goto clean4; +#endif return retval; +#ifdef XILINX_OF_PLATFORM_DRIVER + /* of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER); */ +clean4: +#endif #ifdef OF_PLATFORM_DRIVER - /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */ + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); clean3: #endif #ifdef PS3_SYSTEM_BUS_DRIVER @@ -1243,6 +1254,9 @@ module_init(ehci_hcd_init); static void __exit ehci_hcd_cleanup(void) { +#ifdef XILINX_OF_PLATFORM_DRIVER + of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER); +#endif #ifdef OF_PLATFORM_DRIVER of_unregister_platform_driver(&OF_PLATFORM_DRIVER); #endif -- GitLab From 109f34e71b9049a57f6cdf3f1da6bee2b722b259 Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Thu, 27 May 2010 14:32:09 +0200 Subject: [PATCH 620/842] USB: serial: digi_acceleport: Eliminate a NULL pointer dereference If port is NULL, then the call to dev_err will dereference a value that is a small offset from NULL. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @r exists@ expression E,E1; identifier f; statement S1,S2,S3; @@ if ((E == NULL && ...) || ...) { ... when != if (...) S1 else S2 when != E = E1 * E->f ... when any return ...; } else S3 // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/serial/digi_acceleport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 3edda3ed822a..fd35f73b5721 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1239,8 +1239,7 @@ static void digi_write_bulk_callback(struct urb *urb) /* port and serial sanity check */ if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { - dev_err(&port->dev, - "%s: port or port->private is NULL, status=%d\n", + pr_err("%s: port or port->private is NULL, status=%d\n", __func__, status); return; } -- GitLab From c043f1245654a726925529007210e9f786426448 Mon Sep 17 00:00:00 2001 From: Alan Stern <stern@rowland.harvard.edu> Date: Fri, 4 Jun 2010 14:02:42 -0400 Subject: [PATCH 621/842] USB: unbind all interfaces before rebinding them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch (as1387) fixes a bug introduced during the changeover to the runtime PM framework. When a driver doesn't support resume or reset-resume, and consequently its interfaces need to be unbound and rebound, we have to unbind all the interfaces before trying to rebind any of them. Otherwise the driver's probe method for one interface could try to claim a different interface and fail, because that other interface hasn't been unbound yet. This fixes Bugzilla #15788. The symptom is that some USB sound cards don't work after hibernation. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: François Valenduc <francois.valenduc@tvcablenet.be> Cc: stable <stable@kernel.org> [.34] Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/usb/core/driver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index ded550eda5d9..de98a94d1853 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1328,6 +1328,7 @@ int usb_resume(struct device *dev, pm_message_t msg) /* For all other calls, take the device back to full power and * tell the PM core in case it was autosuspended previously. + * Unbind the interfaces that will need rebinding later. */ } else { status = usb_resume_both(udev, msg); @@ -1336,6 +1337,7 @@ int usb_resume(struct device *dev, pm_message_t msg) pm_runtime_set_active(dev); pm_runtime_enable(dev); udev->last_busy = jiffies; + do_unbind_rebind(udev, DO_REBIND); } } -- GitLab From c842128607a50a670df5f9c75261db2e21db3c45 Mon Sep 17 00:00:00 2001 From: Andrew Morton <akpm@linux-foundation.org> Date: Fri, 21 May 2010 15:05:21 -0700 Subject: [PATCH 622/842] lib/kobject_uevent.c: fix CONIG_NET=n warning lib/kobject_uevent.c:87: warning: 'kobj_bcast_filter' defined but not used Repairs "hotplug: netns aware uevent_helper" Cc: Eric W. Biederman <ebiederm@xmission.com> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- lib/kobject_uevent.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 59c15511d58a..e2eb989d3223 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -83,6 +83,7 @@ out: return ret; } +#ifdef CONFIG_NET static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data) { struct kobject *kobj = data; @@ -98,6 +99,7 @@ static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data) return 0; } +#endif static int kobj_usermode_filter(struct kobject *kobj) { -- GitLab From 743db2d903bc4e963a31496328d847d69f75047c Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Tue, 25 May 2010 11:51:10 +0200 Subject: [PATCH 623/842] kobject: free memory if netlink_kernel_create() fails There is a kfree(ue_sk) missing on the error path if netlink_kernel_create() fails. Signed-off-by: Dan Carpenter <error27@gmail.com> Reviewed-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- lib/kobject_uevent.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index e2eb989d3223..b93579504dfa 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -380,6 +380,7 @@ static int uevent_net_init(struct net *net) if (!ue_sk->sk) { printk(KERN_ERR "kobject_uevent: unable to create netlink socket!\n"); + kfree(ue_sk); return -ENODEV; } mutex_lock(&uevent_sock_mutex); -- GitLab From 75de46b98dda624397ccb17c106e51f478a79c15 Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Mon, 31 May 2010 17:58:02 +1000 Subject: [PATCH 624/842] fix setattr error handling in sysfs, configfs sysfs and configfs setattr functions have error cases after the generic inode's attributes have been changed. Fix consistency by changing the generic inode attributes only when it is guaranteed to succeed. Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: Joel Becker <joel.becker@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- fs/configfs/inode.c | 9 ++++----- fs/sysfs/inode.c | 6 ++++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 41645142b88b..cf78d44a8d6a 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -72,10 +72,6 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr) if (!sd) return -EINVAL; - error = simple_setattr(dentry, iattr); - if (error) - return error; - sd_iattr = sd->s_iattr; if (!sd_iattr) { /* setting attributes for the first time, allocate now */ @@ -89,9 +85,12 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr) sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; sd->s_iattr = sd_iattr; } - /* attributes were changed atleast once in past */ + error = simple_setattr(dentry, iattr); + if (error) + return error; + if (ia_valid & ATTR_UID) sd_iattr->ia_uid = iattr->ia_uid; if (ia_valid & ATTR_GID) diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index bde1a4c3679a..0835a3b70e03 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -117,11 +117,13 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) if (error) goto out; + error = sysfs_sd_setattr(sd, iattr); + if (error) + goto out; + /* this ignores size changes */ generic_setattr(inode, iattr); - error = sysfs_sd_setattr(sd, iattr); - out: mutex_unlock(&sysfs_mutex); return error; -- GitLab From 18c79d76ece432a48c985ea404800f8ee154ada2 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar <adharmap@codeaurora.org> Date: Thu, 20 May 2010 15:20:23 -0700 Subject: [PATCH 625/842] msm_serial: fix serial on trout Set the mnd counter based on uartclk. This fixes a problem on 7x30 where the uartclk is 19.2Mhz rather than the usual 4.8Mhz. Trout incorrectly reports uartclk to be running at 19.2Mhz It is actually running at 4.8Mhz. For trout force mnd counter values as if uartclk was fed by tcxo/4. Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org> [dwalker@codeaurora.org: inlined, moved into header, added comments.] Signed-off-by: Daniel Walker <dwalker@codeaurora.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/serial/msm_serial.c | 21 ++------------ drivers/serial/msm_serial.h | 56 +++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c index ecdc0facf7ee..f8c816e7725d 100644 --- a/drivers/serial/msm_serial.c +++ b/drivers/serial/msm_serial.c @@ -41,19 +41,6 @@ struct msm_port { unsigned int imr; }; -#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) - -static inline void msm_write(struct uart_port *port, unsigned int val, - unsigned int off) -{ - __raw_writel(val, port->membase + off); -} - -static inline unsigned int msm_read(struct uart_port *port, unsigned int off) -{ - return __raw_readl(port->membase + off); -} - static void msm_stop_tx(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); @@ -320,11 +307,7 @@ static void msm_init_clock(struct uart_port *port) struct msm_port *msm_port = UART_TO_MSM(port); clk_enable(msm_port->clk); - - msm_write(port, 0xC0, UART_MREG); - msm_write(port, 0xB2, UART_NREG); - msm_write(port, 0x7D, UART_DREG); - msm_write(port, 0x1C, UART_MNDREG); + msm_serial_set_mnd_regs(port); } static int msm_startup(struct uart_port *port) @@ -706,6 +689,8 @@ static int __init msm_serial_probe(struct platform_device *pdev) if (unlikely(IS_ERR(msm_port->clk))) return PTR_ERR(msm_port->clk); port->uartclk = clk_get_rate(msm_port->clk); + printk(KERN_INFO "uartclk = %d\n", port->uartclk); + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(!resource)) diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h index 689f1fa0e84e..f6ca9ca79e98 100644 --- a/drivers/serial/msm_serial.h +++ b/drivers/serial/msm_serial.h @@ -114,4 +114,60 @@ #define UART_MISR 0x0010 #define UART_ISR 0x0014 +#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) + +static inline +void msm_write(struct uart_port *port, unsigned int val, unsigned int off) +{ + __raw_writel(val, port->membase + off); +} + +static inline +unsigned int msm_read(struct uart_port *port, unsigned int off) +{ + return __raw_readl(port->membase + off); +} + +/* + * Setup the MND registers to use the TCXO clock. + */ +static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) +{ + msm_write(port, 0x06, UART_MREG); + msm_write(port, 0xF1, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x1A, UART_MNDREG); +} + +/* + * Setup the MND registers to use the TCXO clock divided by 4. + */ +static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) +{ + msm_write(port, 0x18, UART_MREG); + msm_write(port, 0xF6, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x0A, UART_MNDREG); +} + +static inline +void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port) +{ + if (port->uartclk == 19200000) + msm_serial_set_mnd_regs_tcxo(port); + else + msm_serial_set_mnd_regs_tcxoby4(port); +} + +/* + * TROUT has a specific defect that makes it report it's uartclk + * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special + * cases TROUT to use the right clock. + */ +#ifdef CONFIG_MACH_TROUT +#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4 +#else +#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk +#endif + #endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */ -- GitLab From 99ec88f345945208c650b54279dddc8dfd705571 Mon Sep 17 00:00:00 2001 From: Alexander Kurz <linux@kbdbabel.org> Date: Thu, 20 May 2010 00:40:08 +0400 Subject: [PATCH 626/842] serial_cs: add and sort IDs for serial and modem cards Signed-off-by: Alexander Kurz <linux@kbdbabel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/serial/serial_cs.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index dadd686c9801..526307368f8b 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -715,6 +715,8 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a), + PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a), @@ -724,8 +726,6 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101), PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a), - PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a), PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63), PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63), PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef), @@ -768,17 +768,26 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276), PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039), PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006), + PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0101), /* TDK DF2814 */ + PCMCIA_DEVICE_MANF_CARD(0x0105, 0x100a), /* Xircom CM-56G */ + PCMCIA_DEVICE_MANF_CARD(0x0105, 0x3e0a), /* TDK DF5660 */ PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a), + PCMCIA_DEVICE_MANF_CARD(0x0107, 0x0002), /* USRobotics 14,400 */ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50), PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51), PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52), PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53), PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180), + PCMCIA_DEVICE_MANF_CARD(0x0115, 0x3330), /* USRobotics/SUN 14,400 */ + PCMCIA_DEVICE_MANF_CARD(0x0124, 0x0100), /* Nokia DTP-2 ver II */ + PCMCIA_DEVICE_MANF_CARD(0x0134, 0x5600), /* LASAT COMMUNICATIONS A/S */ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e), PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b), PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025), PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045), PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052), + PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */ + PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */ PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae), PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef), PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef), @@ -792,16 +801,21 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95), PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed), PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65), + PCMCIA_DEVICE_PROD_ID12("IBM", "ISDN/56K/GSM", 0xb569a6e5, 0xfee5297b), PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6), PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb), + PCMCIA_DEVICE_PROD_ID12("Intertex", "IX34-PCMCIA", 0xf8a097e3, 0x97880447), PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f), PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f), PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383), PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e), PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a), + PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41), PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab), PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f), PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d), + PCMCIA_DEVICE_PROD_ID12("Telia", "SurfinBird 560P/A+", 0xe2cdd5e, 0xc9314b38), + PCMCIA_DEVICE_PROD_ID1("Smart Serial Port", 0x2d8ce292), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"), PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"), -- GitLab From ca3e442e8dbbe2551473f36f0e7797b1d3205f5a Mon Sep 17 00:00:00 2001 From: Graf Yang <graf.yang@analog.com> Date: Sun, 23 May 2010 04:40:13 -0400 Subject: [PATCH 627/842] serial: bfin_5xx: IRDA is not affected by anomaly 05000230 Anomaly 05000230 (over sampling of the UART STOP bit) applies only when the peripheral is operating in UART mode. So drop the anomaly handling when the UART is in IRDA mode. Signed-off-by: Graf Yang <graf.yang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/serial/bfin_5xx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 96f7e7484fee..a78652b21e40 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -869,7 +869,12 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, } baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud) - ANOMALY_05000230; + quot = uart_get_divisor(port, baud); + + /* If discipline is not IRDA, apply ANOMALY_05000230 */ + if (termios->c_line != N_IRDA) + quot -= ANOMALY_05000230; + spin_lock_irqsave(&uart->port.lock, flags); UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15); -- GitLab From e59e2bd9e85604ad601ec7dd056baffcd6ad56a0 Mon Sep 17 00:00:00 2001 From: Sonic Zhang <sonic.zhang@analog.com> Date: Sun, 23 May 2010 04:40:14 -0400 Subject: [PATCH 628/842] serial: bfin_5xx: fix typo in IER check This most likely won't cause problems on systems as people don't typically enable GPIO RTS/CTS if they don't actually use it. Signed-off-by: Sonic Zhang <sonic.zhang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/serial/bfin_5xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index a78652b21e40..511cbf687877 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -797,7 +797,7 @@ static void bfin_serial_shutdown(struct uart_port *port) gpio_free(uart->rts_pin); #endif #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS - if (UART_GET_IER(uart) && EDSSI) + if (UART_GET_IER(uart) & EDSSI) free_irq(uart->status_irq, uart); #endif } -- GitLab From 328be395a396b1333b56e04571365dc614c96e46 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Tue, 25 May 2010 11:37:17 +0200 Subject: [PATCH 629/842] TTY/n_gsm: potential double lock In gsm_dlci_data_kick() we call gsm_dlci_data_sweep() with the "gsm->tx_lock" held so we can't lock it again inside gsm_dlci_data_sweep(). I removed that lock from and added one to gsmld_write_wakeup() instead. The sweep function is only called from those two places. Signed-off-by: Dan Carpenter <error27@gmail.com> Acked-by: Alan Cox <alan@linux.intel.com> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/char/n_gsm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/char/n_gsm.c b/drivers/char/n_gsm.c index c4161d5e053d..e4089c432f15 100644 --- a/drivers/char/n_gsm.c +++ b/drivers/char/n_gsm.c @@ -904,9 +904,7 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) int len; /* Priority ordering: We should do priority with RR of the groups */ int i = 1; - unsigned long flags; - spin_lock_irqsave(&gsm->tx_lock, flags); while (i < NUM_DLCI) { struct gsm_dlci *dlci; @@ -927,7 +925,6 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) if (len == 0) i++; } - spin_unlock_irqrestore(&gsm->tx_lock, flags); } /** @@ -2230,12 +2227,16 @@ static int gsmld_open(struct tty_struct *tty) static void gsmld_write_wakeup(struct tty_struct *tty) { struct gsm_mux *gsm = tty->disc_data; + unsigned long flags; /* Queue poll */ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); gsm_data_kick(gsm); - if (gsm->tx_bytes < TX_THRESH_LO) + if (gsm->tx_bytes < TX_THRESH_LO) { + spin_lock_irqsave(&gsm->tx_lock, flags); gsm_dlci_data_sweep(gsm); + spin_unlock_irqrestore(&gsm->tx_lock, flags); + } } /** -- GitLab From d8d721f4c005f9a69bd1b5d5c6ba99b7e1d464de Mon Sep 17 00:00:00 2001 From: Tobias Klauser <tklauser@distanz.ch> Date: Tue, 25 May 2010 16:59:55 +0200 Subject: [PATCH 630/842] altera_uart: Don't take spinlock in already protected functions Don't take the port spinlock in uart functions where the serial core already takes care of locking/unlocking them. The code would actually lock up on architectures where spinlocks are implemented (not the case on nios2 where this driver is primarily used for now, thus this bug didn't trigger). Also protect calling altera_uart_rx_chars/altera_uart_tx_chars in the interrupt handler by the port spinlock. Thanks to Ian Abbott for pointing these issues out. Cc: Ian Abbott <abbotti@mev.co.uk> Cc: Thomas Chou <thomas@wytron.com.tw> Signed-off-by: Tobias Klauser <tklauser@distanz.ch> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/serial/altera_uart.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c index bcee156d2f2e..b1609cca0ec4 100644 --- a/drivers/serial/altera_uart.c +++ b/drivers/serial/altera_uart.c @@ -89,15 +89,12 @@ static unsigned int altera_uart_tx_empty(struct uart_port *port) static unsigned int altera_uart_get_mctrl(struct uart_port *port) { struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; unsigned int sigs; - spin_lock_irqsave(&port->lock, flags); sigs = (readl(port->membase + ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0; sigs |= (pp->sigs & TIOCM_RTS); - spin_unlock_irqrestore(&port->lock, flags); return sigs; } @@ -105,49 +102,37 @@ static unsigned int altera_uart_get_mctrl(struct uart_port *port) static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs) { struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); pp->sigs = sigs; if (sigs & TIOCM_RTS) pp->imr |= ALTERA_UART_CONTROL_RTS_MSK; else pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK; writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); } static void altera_uart_start_tx(struct uart_port *port) { struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK; writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); } static void altera_uart_stop_tx(struct uart_port *port) { struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); } static void altera_uart_stop_rx(struct uart_port *port) { struct altera_uart *pp = container_of(port, struct altera_uart, port); - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK; writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); - spin_unlock_irqrestore(&port->lock, flags); } static void altera_uart_break_ctl(struct uart_port *port, int break_state) @@ -272,10 +257,14 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data) unsigned int isr; isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr; + + spin_lock(&port->lock); if (isr & ALTERA_UART_STATUS_RRDY_MSK) altera_uart_rx_chars(pp); if (isr & ALTERA_UART_STATUS_TRDY_MSK) altera_uart_tx_chars(pp); + spin_unlock(&port->lock); + return IRQ_RETVAL(isr); } -- GitLab From fadf34f0f05ca5ea02ffcd89544cd372bbdb739b Mon Sep 17 00:00:00 2001 From: Tobias Klauser <tklauser@distanz.ch> Date: Tue, 25 May 2010 17:00:08 +0200 Subject: [PATCH 631/842] altera_uart: Simplify altera_uart_console_putc The check for the TRDY flag after writing the character is not needed. Also do a cpu_relax() inside the loop. Pass a struct uart_port to altera_uart_console_putc, so we do not need to get it (and dereference pointers) for every character. Cc: Thomas Chou <thomas@wytron.com.tw> Signed-off-by: Tobias Klauser <tklauser@distanz.ch> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/serial/altera_uart.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c index b1609cca0ec4..7d6afc9755d5 100644 --- a/drivers/serial/altera_uart.c +++ b/drivers/serial/altera_uart.c @@ -391,31 +391,24 @@ int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp) return 0; } -static void altera_uart_console_putc(struct console *co, const char c) +static void altera_uart_console_putc(struct uart_port *port, const char c) { - struct uart_port *port = &(altera_uart_ports + co->index)->port; - int i; + while (!(readl(port->membase + ALTERA_UART_STATUS_REG) & + ALTERA_UART_STATUS_TRDY_MSK)) + cpu_relax(); - for (i = 0; i < 0x10000; i++) { - if (readl(port->membase + ALTERA_UART_STATUS_REG) & - ALTERA_UART_STATUS_TRDY_MSK) - break; - } writel(c, port->membase + ALTERA_UART_TXDATA_REG); - for (i = 0; i < 0x10000; i++) { - if (readl(port->membase + ALTERA_UART_STATUS_REG) & - ALTERA_UART_STATUS_TRDY_MSK) - break; - } } static void altera_uart_console_write(struct console *co, const char *s, unsigned int count) { + struct uart_port *port = &(altera_uart_ports + co->index)->port; + for (; count; count--, s++) { - altera_uart_console_putc(co, *s); + altera_uart_console_putc(port, *s); if (*s == '\n') - altera_uart_console_putc(co, '\r'); + altera_uart_console_putc(port, '\r'); } } -- GitLab From 962400e8fd29981a7b166e463dd143b6ac6a3e76 Mon Sep 17 00:00:00 2001 From: Frank Pan <frankpzh@gmail.com> Date: Wed, 26 May 2010 15:37:43 +0800 Subject: [PATCH 632/842] tty: fix a little bug in scrup, vt.c The code uses vc->vc_cols instead of vc->vc_size_row by mistake, it will cause half of the region which is going to clear remain uncleared. The issue happens in background consoles, so it's hard to observe. Frank Pan Signed-off-by: Frank Pan <frankpzh@gmail.com> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/char/vt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7cdb6ee569cd..1296c42ed5c6 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -304,7 +304,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, + scr_memsetw(d + (b - t - nr) * vc->vc_size_row, vc->vc_video_erase_char, vc->vc_size_row * nr); } -- GitLab From c1bfffa94e0ca951ed450788991c9310adb8e823 Mon Sep 17 00:00:00 2001 From: Tobias Klauser <tklauser@distanz.ch> Date: Mon, 31 May 2010 15:01:08 +0200 Subject: [PATCH 633/842] serial: altera_uart: Proper section for altera_uart_remove altera_uart_remove should be in .devexit.text Signed-off-by: Tobias Klauser <tklauser@distanz.ch> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/serial/altera_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c index 7d6afc9755d5..0f1189605d21 100644 --- a/drivers/serial/altera_uart.c +++ b/drivers/serial/altera_uart.c @@ -498,7 +498,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) return 0; } -static int altera_uart_remove(struct platform_device *pdev) +static int __devexit altera_uart_remove(struct platform_device *pdev) { struct uart_port *port; int i; -- GitLab From 3fde85df5421eb01f563fef6f111ba73ab0d120e Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Fri, 4 Jun 2010 12:20:46 +0200 Subject: [PATCH 634/842] vt_ioctl: return -EFAULT on copy_from_user errors copy_from_user() returns the number of bytes remaining but we want to return a negative error code here. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/char/vt_ioctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 6aa10284104a..cb19dbc52136 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -1303,7 +1303,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (!perm) goto eperm; ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); - if (!ret) + if (ret) + ret = -EFAULT; + else con_clear_unimap(vc, &ui); break; } -- GitLab From 66169ad17d9c67a33608830dd83dcef55c85a756 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov <yegor_sub1@visionsystems.de> Date: Fri, 4 Jun 2010 09:58:18 +0200 Subject: [PATCH 635/842] serial: add support for various Titan PCI cards serial: add support for various Titan PCI cards Models: 200I, 400I, 800I, 400EH, 800EH, 800EHB, 100E, 200E, 400E, 800E, 200EI, 200EISI Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/serial/8250_pci.c | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 01c012da4e26..746a44621d91 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -982,6 +982,18 @@ static int skip_tx_en_setup(struct serial_private *priv, #define PCI_SUBDEVICE_ID_POCTAL422 0x0408 #define PCI_VENDOR_ID_ADVANTECH 0x13fe #define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620 +#define PCI_DEVICE_ID_TITAN_200I 0x8028 +#define PCI_DEVICE_ID_TITAN_400I 0x8048 +#define PCI_DEVICE_ID_TITAN_800I 0x8088 +#define PCI_DEVICE_ID_TITAN_800EH 0xA007 +#define PCI_DEVICE_ID_TITAN_800EHB 0xA008 +#define PCI_DEVICE_ID_TITAN_400EH 0xA009 +#define PCI_DEVICE_ID_TITAN_100E 0xA010 +#define PCI_DEVICE_ID_TITAN_200E 0xA012 +#define PCI_DEVICE_ID_TITAN_400E 0xA013 +#define PCI_DEVICE_ID_TITAN_800E 0xA014 +#define PCI_DEVICE_ID_TITAN_200EI 0xA016 +#define PCI_DEVICE_ID_TITAN_200EISI 0xA017 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -1541,6 +1553,10 @@ enum pci_board_num_t { pbn_b3_4_115200, pbn_b3_8_115200, + pbn_b4_bt_2_921600, + pbn_b4_bt_4_921600, + pbn_b4_bt_8_921600, + /* * Board-specific versions. */ @@ -1995,6 +2011,25 @@ static struct pciserial_board pci_boards[] __devinitdata = { .uart_offset = 8, }, + [pbn_b4_bt_2_921600] = { + .flags = FL_BASE4, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b4_bt_4_921600] = { + .flags = FL_BASE4, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 8, + }, + [pbn_b4_bt_8_921600] = { + .flags = FL_BASE4, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 8, + }, + /* * Entries following this are board-specific. */ @@ -3043,6 +3078,42 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_8_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b4_bt_2_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b4_bt_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b4_bt_8_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_1_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_4_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_8_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_4000000 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, -- GitLab From d7636e0b0769e0f4f437ff33168d723f86e7c080 Mon Sep 17 00:00:00 2001 From: "apatard@mandriva.com" <apatard@mandriva.com> Date: Wed, 19 May 2010 10:44:14 +0200 Subject: [PATCH 636/842] staging: Add framebuffer driver for XGI chipsets This driver handles XG20, XG21, XG40, XG42 chipsets from XGI. They're also known as Z7,Z9,Z11 chipsets. It's based on the SiS fb driver but has been heavily modified by XGI to support their newer chipsets. Signed-off-by: Arnaud Patard <apatard@mandriva.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/xgifb/Kconfig | 11 + drivers/staging/xgifb/Makefile | 4 + drivers/staging/xgifb/TODO | 15 + drivers/staging/xgifb/XGI.h | 10 + drivers/staging/xgifb/XGI_accel.c | 596 ++ drivers/staging/xgifb/XGI_accel.h | 511 ++ drivers/staging/xgifb/XGI_main.h | 1023 +++ drivers/staging/xgifb/XGI_main_26.c | 3773 +++++++++ drivers/staging/xgifb/XGIfb.h | 215 + drivers/staging/xgifb/osdef.h | 153 + drivers/staging/xgifb/vb_def.h | 1017 +++ drivers/staging/xgifb/vb_ext.c | 1370 ++++ drivers/staging/xgifb/vb_ext.h | 32 + drivers/staging/xgifb/vb_init.c | 3444 +++++++++ drivers/staging/xgifb/vb_init.h | 7 + drivers/staging/xgifb/vb_setmode.c | 10736 ++++++++++++++++++++++++++ drivers/staging/xgifb/vb_setmode.h | 40 + drivers/staging/xgifb/vb_struct.h | 534 ++ drivers/staging/xgifb/vb_table.h | 4406 +++++++++++ drivers/staging/xgifb/vb_util.c | 263 + drivers/staging/xgifb/vb_util.h | 15 + drivers/staging/xgifb/vgatypes.h | 325 + 24 files changed, 28503 insertions(+) create mode 100644 drivers/staging/xgifb/Kconfig create mode 100644 drivers/staging/xgifb/Makefile create mode 100644 drivers/staging/xgifb/TODO create mode 100644 drivers/staging/xgifb/XGI.h create mode 100644 drivers/staging/xgifb/XGI_accel.c create mode 100644 drivers/staging/xgifb/XGI_accel.h create mode 100644 drivers/staging/xgifb/XGI_main.h create mode 100644 drivers/staging/xgifb/XGI_main_26.c create mode 100644 drivers/staging/xgifb/XGIfb.h create mode 100644 drivers/staging/xgifb/osdef.h create mode 100644 drivers/staging/xgifb/vb_def.h create mode 100644 drivers/staging/xgifb/vb_ext.c create mode 100644 drivers/staging/xgifb/vb_ext.h create mode 100644 drivers/staging/xgifb/vb_init.c create mode 100644 drivers/staging/xgifb/vb_init.h create mode 100644 drivers/staging/xgifb/vb_setmode.c create mode 100644 drivers/staging/xgifb/vb_setmode.h create mode 100644 drivers/staging/xgifb/vb_struct.h create mode 100644 drivers/staging/xgifb/vb_table.h create mode 100644 drivers/staging/xgifb/vb_util.c create mode 100644 drivers/staging/xgifb/vb_util.h create mode 100644 drivers/staging/xgifb/vgatypes.h diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index b5c3b3013037..2a1a7c296429 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -141,5 +141,7 @@ source "drivers/staging/ti-st/Kconfig" source "drivers/staging/adis16255/Kconfig" +source "drivers/staging/xgifb/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index e330dd5e843d..4a02c0df9ced 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -51,3 +51,4 @@ obj-$(CONFIG_CRYSTALHD) += crystalhd/ obj-$(CONFIG_CXT1E1) += cxt1e1/ obj-$(CONFIG_TI_ST) += ti-st/ obj-$(CONFIG_ADIS16255) += adis16255/ +obj-$(CONFIG_FB_XGI) += xgifb/ diff --git a/drivers/staging/xgifb/Kconfig b/drivers/staging/xgifb/Kconfig new file mode 100644 index 000000000000..bb0ca5974ea0 --- /dev/null +++ b/drivers/staging/xgifb/Kconfig @@ -0,0 +1,11 @@ +config FB_XGI + tristate "XGI display support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + This driver supports notebooks with XGI Z7,Z9,Z11 PCI chips. + Say Y if you have such a graphics card. + To compile this driver as a module, choose M here: the + module will be called xgifb.ko diff --git a/drivers/staging/xgifb/Makefile b/drivers/staging/xgifb/Makefile new file mode 100644 index 000000000000..2a317707de0f --- /dev/null +++ b/drivers/staging/xgifb/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_FB_XGI) += xgifb.o + +xgifb-objs := XGI_main_26.o XGI_accel.o vb_init.o vb_setmode.o vb_util.o vb_ext.o + diff --git a/drivers/staging/xgifb/TODO b/drivers/staging/xgifb/TODO new file mode 100644 index 000000000000..7d71019b84c2 --- /dev/null +++ b/drivers/staging/xgifb/TODO @@ -0,0 +1,15 @@ +This drivers still need a lot of work. I can list all cleanups to do but it's +going to be long. So, I'm writing "cleanups" and not the list. + +Arnaud + +TODO: +- clean ups +- fix build warnings when module +- sort out dup ids with SiS driver +- remove useless/wrong/unused #ifdef/code/... +- fix printk usages +- get rid of non-linux related stuff + +Please send patches to: +Arnaud Patard <apatard@mandriva.com> diff --git a/drivers/staging/xgifb/XGI.h b/drivers/staging/xgifb/XGI.h new file mode 100644 index 000000000000..87803dd032de --- /dev/null +++ b/drivers/staging/xgifb/XGI.h @@ -0,0 +1,10 @@ +#ifndef _XGI_H +#define _XGI_H + +#if 1 +#define TWDEBUG(x) +#else +#define TWDEBUG(x) printk(KERN_INFO x "\n"); +#endif + +#endif diff --git a/drivers/staging/xgifb/XGI_accel.c b/drivers/staging/xgifb/XGI_accel.c new file mode 100644 index 000000000000..86ec3421942f --- /dev/null +++ b/drivers/staging/xgifb/XGI_accel.c @@ -0,0 +1,596 @@ +/* + * XGI 300/630/730/540/315/550/650/740 frame buffer driver + * for Linux kernels 2.4.x and 2.5.x + * + * 2D acceleration part + * + * Based on the X driver's XGI300_accel.c which is + * Copyright Xavier Ducoin <x.ducoin@lectra.com> + * Copyright 2002 by Thomas Winischhofer, Vienna, Austria + * and XGI310_accel.c which is + * Copyright 2002 by Thomas Winischhofer, Vienna, Austria + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * (see http://www.winischhofer.net/ + * for more information and updates) + */ + +//#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/vt_kern.h> +#include <linux/capability.h> +#include <linux/fs.h> +#include <linux/agp_backend.h> + +#include <linux/types.h> +/* +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include <linux/XGIfb.h> +#else +#include <video/XGIfb.h> +#endif +*/ +#include <asm/io.h> + +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> +#endif + +#include "osdef.h" +#include "vgatypes.h" +#include "vb_struct.h" +#include "XGIfb.h" +#include "XGI_accel.h" + + +extern struct video_info xgi_video_info; +extern int XGIfb_accel; + +static const int XGIALUConv[] = +{ + 0x00, /* dest = 0; 0, GXclear, 0 */ + 0x88, /* dest &= src; DSa, GXand, 0x1 */ + 0x44, /* dest = src & ~dest; SDna, GXandReverse, 0x2 */ + 0xCC, /* dest = src; S, GXcopy, 0x3 */ + 0x22, /* dest &= ~src; DSna, GXandInverted, 0x4 */ + 0xAA, /* dest = dest; D, GXnoop, 0x5 */ + 0x66, /* dest = ^src; DSx, GXxor, 0x6 */ + 0xEE, /* dest |= src; DSo, GXor, 0x7 */ + 0x11, /* dest = ~src & ~dest; DSon, GXnor, 0x8 */ + 0x99, /* dest ^= ~src ; DSxn, GXequiv, 0x9 */ + 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */ + 0xDD, /* dest = src|~dest ; SDno, GXorReverse, 0xB */ + 0x33, /* dest = ~src; Sn, GXcopyInverted, 0xC */ + 0xBB, /* dest |= ~src; DSno, GXorInverted, 0xD */ + 0x77, /* dest = ~src|~dest; DSan, GXnand, 0xE */ + 0xFF, /* dest = 0xFF; 1, GXset, 0xF */ +}; +/* same ROP but with Pattern as Source */ +static const int XGIPatALUConv[] = +{ + 0x00, /* dest = 0; 0, GXclear, 0 */ + 0xA0, /* dest &= src; DPa, GXand, 0x1 */ + 0x50, /* dest = src & ~dest; PDna, GXandReverse, 0x2 */ + 0xF0, /* dest = src; P, GXcopy, 0x3 */ + 0x0A, /* dest &= ~src; DPna, GXandInverted, 0x4 */ + 0xAA, /* dest = dest; D, GXnoop, 0x5 */ + 0x5A, /* dest = ^src; DPx, GXxor, 0x6 */ + 0xFA, /* dest |= src; DPo, GXor, 0x7 */ + 0x05, /* dest = ~src & ~dest; DPon, GXnor, 0x8 */ + 0xA5, /* dest ^= ~src ; DPxn, GXequiv, 0x9 */ + 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */ + 0xF5, /* dest = src|~dest ; PDno, GXorReverse, 0xB */ + 0x0F, /* dest = ~src; Pn, GXcopyInverted, 0xC */ + 0xAF, /* dest |= ~src; DPno, GXorInverted, 0xD */ + 0x5F, /* dest = ~src|~dest; DPan, GXnand, 0xE */ + 0xFF, /* dest = 0xFF; 1, GXset, 0xF */ +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) +static const unsigned char myrops[] = { + 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 + }; +#endif + +/* 300 series */ +#if 0 +static void +XGI300Sync(void) +{ + XGI300Idle +} +#endif +static void +XGI310Sync(void) +{ + XGI310Idle +} +#if 0 +static void +XGI300SetupForScreenToScreenCopy(int xdir, int ydir, int rop, + unsigned int planemask, int trans_color) +{ + XGI300SetupDSTColorDepth(xgi_video_info.DstColor); + XGI300SetupSRCPitch(xgi_video_info.video_linelength) + XGI300SetupDSTRect(xgi_video_info.video_linelength, 0xFFF) + + if(trans_color != -1) { + XGI300SetupROP(0x0A) + XGI300SetupSRCTrans(trans_color) + XGI300SetupCMDFlag(TRANSPARENT_BITBLT) + } else { + XGI300SetupROP(XGIALUConv[rop]) + } + if(xdir > 0) { + XGI300SetupCMDFlag(X_INC) + } + if(ydir > 0) { + XGI300SetupCMDFlag(Y_INC) + } +} + +static void +XGI300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y, + int width, int height) +{ + long srcbase, dstbase; + + srcbase = dstbase = 0; + if (src_y >= 2048) { + srcbase = xgi_video_info.video_linelength * src_y; + src_y = 0; + } + if (dst_y >= 2048) { + dstbase = xgi_video_info.video_linelength * dst_y; + dst_y = 0; + } + + XGI300SetupSRCBase(srcbase); + XGI300SetupDSTBase(dstbase); + + if(!(xgi_video_info.CommandReg & X_INC)) { + src_x += width-1; + dst_x += width-1; + } + if(!(xgi_video_info.CommandReg & Y_INC)) { + src_y += height-1; + dst_y += height-1; + } + XGI300SetupRect(width, height) + XGI300SetupSRCXY(src_x, src_y) + XGI300SetupDSTXY(dst_x, dst_y) + XGI300DoCMD +} + +static void +XGI300SetupForSolidFill(int color, int rop, unsigned int planemask) +{ + XGI300SetupPATFG(color) + XGI300SetupDSTRect(xgi_video_info.video_linelength, 0xFFF) + XGI300SetupDSTColorDepth(xgi_video_info.DstColor); + XGI300SetupROP(XGIPatALUConv[rop]) + XGI300SetupCMDFlag(PATFG) +} + +static void +XGI300SubsequentSolidFillRect(int x, int y, int w, int h) +{ + long dstbase; + + dstbase = 0; + if(y >= 2048) { + dstbase = xgi_video_info.video_linelength * y; + y = 0; + } + XGI300SetupDSTBase(dstbase) + XGI300SetupDSTXY(x,y) + XGI300SetupRect(w,h) + XGI300SetupCMDFlag(X_INC | Y_INC | BITBLT) + XGI300DoCMD +} +#endif +/* 310/325 series ------------------------------------------------ */ + +static void +XGI310SetupForScreenToScreenCopy(int xdir, int ydir, int rop, + unsigned int planemask, int trans_color) +{ + XGI310SetupDSTColorDepth(xgi_video_info.DstColor); + XGI310SetupSRCPitch(xgi_video_info.video_linelength) + XGI310SetupDSTRect(xgi_video_info.video_linelength, 0xFFF) + if (trans_color != -1) { + XGI310SetupROP(0x0A) + XGI310SetupSRCTrans(trans_color) + XGI310SetupCMDFlag(TRANSPARENT_BITBLT) + } else { + XGI310SetupROP(XGIALUConv[rop]) + /* Set command - not needed, both 0 */ + /* XGISetupCMDFlag(BITBLT | SRCVIDEO) */ + } + XGI310SetupCMDFlag(xgi_video_info.XGI310_AccelDepth) + /* TW: The 310/325 series is smart enough to know the direction */ +} + +static void +XGI310SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y, + int width, int height) +{ + long srcbase, dstbase; + int mymin, mymax; + + srcbase = dstbase = 0; + mymin = min(src_y, dst_y); + mymax = max(src_y, dst_y); + + /* Although the chip knows the direction to use + * if the source and destination areas overlap, + * that logic fails if we fiddle with the bitmap + * addresses. Therefore, we check if the source + * and destination blitting areas overlap and + * adapt the bitmap addresses synchronously + * if the coordinates exceed the valid range. + * The the areas do not overlap, we do our + * normal check. + */ + if((mymax - mymin) < height) { + if((src_y >= 2048) || (dst_y >= 2048)) { + srcbase = xgi_video_info.video_linelength * mymin; + dstbase = xgi_video_info.video_linelength * mymin; + src_y -= mymin; + dst_y -= mymin; + } + } else { + if(src_y >= 2048) { + srcbase = xgi_video_info.video_linelength * src_y; + src_y = 0; + } + if(dst_y >= 2048) { + dstbase = xgi_video_info.video_linelength * dst_y; + dst_y = 0; + } + } + + XGI310SetupSRCBase(srcbase); + XGI310SetupDSTBase(dstbase); + XGI310SetupRect(width, height) + XGI310SetupSRCXY(src_x, src_y) + XGI310SetupDSTXY(dst_x, dst_y) + XGI310DoCMD +} + +static void +XGI310SetupForSolidFill(int color, int rop, unsigned int planemask) +{ + XGI310SetupPATFG(color) + XGI310SetupDSTRect(xgi_video_info.video_linelength, 0xFFF) + XGI310SetupDSTColorDepth(xgi_video_info.DstColor); + XGI310SetupROP(XGIPatALUConv[rop]) + XGI310SetupCMDFlag(PATFG | xgi_video_info.XGI310_AccelDepth) +} + +static void +XGI310SubsequentSolidFillRect(int x, int y, int w, int h) +{ + long dstbase; + + dstbase = 0; + if(y >= 2048) { + dstbase = xgi_video_info.video_linelength * y; + y = 0; + } + XGI310SetupDSTBase(dstbase) + XGI310SetupDSTXY(x,y) + XGI310SetupRect(w,h) + XGI310SetupCMDFlag(BITBLT) + XGI310DoCMD +} + +/* --------------------------------------------------------------------- */ + +/* The exported routines */ + +int XGIfb_initaccel(void) +{ +#ifdef XGIFB_USE_SPINLOCKS + spin_lock_init(&xgi_video_info.lockaccel); +#endif + return(0); +} + +void XGIfb_syncaccel(void) +{ + + XGI310Sync(); + +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) /* --- KERNEL 2.5.34 and later --- */ + +int fbcon_XGI_sync(struct fb_info *info) +{ + if(!XGIfb_accel) return 0; + CRITFLAGS + + XGI310Sync(); + + CRITEND + return 0; +} + +void fbcon_XGI_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + int col=0; + CRITFLAGS + + + if(!rect->width || !rect->height) + return; + + if(!XGIfb_accel) { + cfb_fillrect(info, rect); + return; + } + + switch(info->var.bits_per_pixel) { + case 8: col = rect->color; + break; + case 16: col = ((u32 *)(info->pseudo_palette))[rect->color]; + break; + case 32: col = ((u32 *)(info->pseudo_palette))[rect->color]; + break; + } + + + CRITBEGIN + XGI310SetupForSolidFill(col, myrops[rect->rop], 0); + XGI310SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height); + CRITEND + XGI310Sync(); + + +} + +void fbcon_XGI_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + int xdir, ydir; + CRITFLAGS + + + if(!XGIfb_accel) { + cfb_copyarea(info, area); + return; + } + + if(!area->width || !area->height) + return; + + if(area->sx < area->dx) xdir = 0; + else xdir = 1; + if(area->sy < area->dy) ydir = 0; + else ydir = 1; + + CRITBEGIN + XGI310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1); + XGI310SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height); + CRITEND + XGI310Sync(); + +} + +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33) /* ------ KERNEL <2.5.34 ------ */ + +void fbcon_XGI_bmove(struct display *p, int srcy, int srcx, + int dsty, int dstx, int height, int width) +{ + int xdir, ydir; + CRITFLAGS + + if(!xgi_video_info.accel) { + switch(xgi_video_info.video_bpp) { + case 8: +#ifdef FBCON_HAS_CFB8 + fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width); +#endif + break; + case 16: +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_bmove(p, srcy, srcx, dsty, dstx, height, width); +#endif + break; + case 32: +#ifdef FBCON_HAS_CFB32 + fbcon_cfb32_bmove(p, srcy, srcx, dsty, dstx, height, width); +#endif + break; + } + return; + } + + srcx *= fontwidth(p); + srcy *= fontheight(p); + dstx *= fontwidth(p); + dsty *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); + + if(srcx < dstx) xdir = 0; + else xdir = 1; + if(srcy < dsty) ydir = 0; + else ydir = 1; + + + CRITBEGIN + XGI310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1); + XGI310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height); + CRITEND + XGI310Sync(); +#if 0 + printk(KERN_INFO "XGI_bmove sx %d sy %d dx %d dy %d w %d h %d\n", + srcx, srcy, dstx, dsty, width, height); +#endif + +} + + +static void fbcon_XGI_clear(struct vc_data *conp, struct display *p, + int srcy, int srcx, int height, int width, int color) +{ + CRITFLAGS + + srcx *= fontwidth(p); + srcy *= fontheight(p); + width *= fontwidth(p); + height *= fontheight(p); + + + CRITBEGIN + XGI310SetupForSolidFill(color, 3, 0); + XGI310SubsequentSolidFillRect(srcx, srcy, width, height); + CRITEND + XGI310Sync(); + +} + +void fbcon_XGI_clear8(struct vc_data *conp, struct display *p, + int srcy, int srcx, int height, int width) +{ + u32 bgx; + + if(!xgi_video_info.accel) { +#ifdef FBCON_HAS_CFB8 + fbcon_cfb8_clear(conp, p, srcy, srcx, height, width); +#endif + return; + } + + bgx = attr_bgcol_ec(p, conp); + fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx); +} + +void fbcon_XGI_clear16(struct vc_data *conp, struct display *p, + int srcy, int srcx, int height, int width) +{ + u32 bgx; + if(!xgi_video_info.accel) { +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_clear(conp, p, srcy, srcx, height, width); +#endif + return; + } + + bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; + fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx); +} + +void fbcon_XGI_clear32(struct vc_data *conp, struct display *p, + int srcy, int srcx, int height, int width) +{ + u32 bgx; + + if(!xgi_video_info.accel) { +#ifdef FBCON_HAS_CFB32 + fbcon_cfb32_clear(conp, p, srcy, srcx, height, width); +#endif + return; + } + + bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; + fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx); +} + +void fbcon_XGI_revc(struct display *p, int srcx, int srcy) +{ + CRITFLAGS + + if(!xgi_video_info.accel) { + switch(xgi_video_info.video_bpp) { + case 16: +#ifdef FBCON_HAS_CFB16 + fbcon_cfb16_revc(p, srcx, srcy); +#endif + break; + case 32: +#ifdef FBCON_HAS_CFB32 + fbcon_cfb32_revc(p, srcx, srcy); +#endif + break; + } + return; + } + + srcx *= fontwidth(p); + srcy *= fontheight(p); + + + CRITBEGIN + XGI310SetupForSolidFill(0, 0x0a, 0); + XGI310SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p)); + CRITEND + XGI310Sync(); + +} + +#ifdef FBCON_HAS_CFB8 +struct display_switch fbcon_XGI8 = { + setup: fbcon_cfb8_setup, + bmove: fbcon_XGI_bmove, + clear: fbcon_XGI_clear8, + putc: fbcon_cfb8_putc, + putcs: fbcon_cfb8_putcs, + revc: fbcon_cfb8_revc, + clear_margins: fbcon_cfb8_clear_margins, + fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif +#ifdef FBCON_HAS_CFB16 +struct display_switch fbcon_XGI16 = { + setup: fbcon_cfb16_setup, + bmove: fbcon_XGI_bmove, + clear: fbcon_XGI_clear16, + putc: fbcon_cfb16_putc, + putcs: fbcon_cfb16_putcs, + revc: fbcon_XGI_revc, + clear_margins: fbcon_cfb16_clear_margins, + fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif +#ifdef FBCON_HAS_CFB32 +struct display_switch fbcon_XGI32 = { + setup: fbcon_cfb32_setup, + bmove: fbcon_XGI_bmove, + clear: fbcon_XGI_clear32, + putc: fbcon_cfb32_putc, + putcs: fbcon_cfb32_putcs, + revc: fbcon_XGI_revc, + clear_margins: fbcon_cfb32_clear_margins, + fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) +}; +#endif + +#endif /* KERNEL VERSION */ + + diff --git a/drivers/staging/xgifb/XGI_accel.h b/drivers/staging/xgifb/XGI_accel.h new file mode 100644 index 000000000000..04e126772bb8 --- /dev/null +++ b/drivers/staging/xgifb/XGI_accel.h @@ -0,0 +1,511 @@ +/* + * XGI 300/630/730/540/315/550/650/740 frame buffer driver + * for Linux kernels 2.4.x and 2.5.x + * + * 2D acceleration part + * + * Based on the X driver's XGI300_accel.h which is + * Copyright Xavier Ducoin <x.ducoin@lectra.com> + * Copyright 2002 by Thomas Winischhofer, Vienna, Austria + * and XGI310_accel.h which is + * Copyright 2002 by Thomas Winischhofer, Vienna, Austria + * + * Author: Thomas Winischhofer <thomas@winischhofer.net>: + * (see http://www.winischhofer.net/ + * for more information and updates) + */ + +#ifndef _XGIFB_ACCEL_H +#define _XGIFB_ACCEL_H + +/* Guard accelerator accesses with spin_lock_irqsave? Works well without. */ +#undef XGIFB_USE_SPINLOCKS + +#ifdef XGIFB_USE_SPINLOCKS +#include <linux/spinlock.h> +#define CRITBEGIN spin_lock_irqsave(&xgi_video_info.lockaccel), critflags); +#define CRITEND spin_unlock_irqrestore(&xgi_video_info.lockaccel), critflags); +#define CRITFLAGS unsigned long critflags; +#else +#define CRITBEGIN +#define CRITEND +#define CRITFLAGS +#endif + +/* Definitions for the XGI engine communication. */ + +#define PATREGSIZE 384 /* Pattern register size. 384 bytes @ 0x8300 */ +#define BR(x) (0x8200 | (x) << 2) +#define PBR(x) (0x8300 | (x) << 2) + +/* XGI300 engine commands */ +#define BITBLT 0x00000000 /* Blit */ +#define COLOREXP 0x00000001 /* Color expand */ +#define ENCOLOREXP 0x00000002 /* Enhanced color expand */ +#define MULTIPLE_SCANLINE 0x00000003 /* ? */ +#define LINE 0x00000004 /* Draw line */ +#define TRAPAZOID_FILL 0x00000005 /* Fill trapezoid */ +#define TRANSPARENT_BITBLT 0x00000006 /* Transparent Blit */ + +/* Additional engine commands for 310/325 */ +#define ALPHA_BLEND 0x00000007 /* Alpha blend ? */ +#define A3D_FUNCTION 0x00000008 /* 3D command ? */ +#define CLEAR_Z_BUFFER 0x00000009 /* ? */ +#define GRADIENT_FILL 0x0000000A /* Gradient fill */ +#define STRETCH_BITBLT 0x0000000B /* Stretched Blit */ + +/* source select */ +#define SRCVIDEO 0x00000000 /* source is video RAM */ +#define SRCSYSTEM 0x00000010 /* source is system memory */ +#define SRCCPUBLITBUF SRCSYSTEM /* source is CPU-driven BitBuffer (for color expand) */ +#define SRCAGP 0x00000020 /* source is AGP memory (?) */ + +/* Pattern flags */ +#define PATFG 0x00000000 /* foreground color */ +#define PATPATREG 0x00000040 /* pattern in pattern buffer (0x8300) */ +#define PATMONO 0x00000080 /* mono pattern */ + +/* blitting direction (300 series only) */ +#define X_INC 0x00010000 +#define X_DEC 0x00000000 +#define Y_INC 0x00020000 +#define Y_DEC 0x00000000 + +/* Clipping flags */ +#define NOCLIP 0x00000000 +#define NOMERGECLIP 0x04000000 +#define CLIPENABLE 0x00040000 +#define CLIPWITHOUTMERGE 0x04040000 + +/* Transparency */ +#define OPAQUE 0x00000000 +#define TRANSPARENT 0x00100000 + +/* ? */ +#define DSTAGP 0x02000000 +#define DSTVIDEO 0x02000000 + +/* Line */ +#define LINE_STYLE 0x00800000 +#define NO_RESET_COUNTER 0x00400000 +#define NO_LAST_PIXEL 0x00200000 + +/* Subfunctions for Color/Enhanced Color Expansion (310/325 only) */ +#define COLOR_TO_MONO 0x00100000 +#define AA_TEXT 0x00200000 + +/* Some general registers for 310/325 series */ +#define SRC_ADDR 0x8200 +#define SRC_PITCH 0x8204 +#define AGP_BASE 0x8206 /* color-depth dependent value */ +#define SRC_Y 0x8208 +#define SRC_X 0x820A +#define DST_Y 0x820C +#define DST_X 0x820E +#define DST_ADDR 0x8210 +#define DST_PITCH 0x8214 +#define DST_HEIGHT 0x8216 +#define RECT_WIDTH 0x8218 +#define RECT_HEIGHT 0x821A +#define PAT_FGCOLOR 0x821C +#define PAT_BGCOLOR 0x8220 +#define SRC_FGCOLOR 0x8224 +#define SRC_BGCOLOR 0x8228 +#define MONO_MASK 0x822C +#define LEFT_CLIP 0x8234 +#define TOP_CLIP 0x8236 +#define RIGHT_CLIP 0x8238 +#define BOTTOM_CLIP 0x823A +#define COMMAND_READY 0x823C +#define FIRE_TRIGGER 0x8240 + +#define PATTERN_REG 0x8300 /* 384 bytes pattern buffer */ + +/* Line registers */ +#define LINE_X0 SRC_Y +#define LINE_X1 DST_Y +#define LINE_Y0 SRC_X +#define LINE_Y1 DST_X +#define LINE_COUNT RECT_WIDTH +#define LINE_STYLE_PERIOD RECT_HEIGHT +#define LINE_STYLE_0 MONO_MASK +#define LINE_STYLE_1 0x8230 +#define LINE_XN PATTERN_REG +#define LINE_YN PATTERN_REG+2 + +/* Transparent bitblit registers */ +#define TRANS_DST_KEY_HIGH PAT_FGCOLOR +#define TRANS_DST_KEY_LOW PAT_BGCOLOR +#define TRANS_SRC_KEY_HIGH SRC_FGCOLOR +#define TRANS_SRC_KEY_LOW SRC_BGCOLOR + +/* Queue */ +#define Q_BASE_ADDR 0x85C0 /* Base address of software queue (?) */ +#define Q_WRITE_PTR 0x85C4 /* Current write pointer (?) */ +#define Q_READ_PTR 0x85C8 /* Current read pointer (?) */ +#define Q_STATUS 0x85CC /* queue status */ + + +#define MMIO_IN8(base, offset) \ + *(volatile u8 *)(((u8*)(base)) + (offset)) +#define MMIO_IN16(base, offset) \ + *(volatile u16 *)(void *)(((u8*)(base)) + (offset)) +#define MMIO_IN32(base, offset) \ + *(volatile u32 *)(void *)(((u8*)(base)) + (offset)) +#define MMIO_OUT8(base, offset, val) \ + *(volatile u8 *)(((u8*)(base)) + (offset)) = (val) +#define MMIO_OUT16(base, offset, val) \ + *(volatile u16 *)(void *)(((u8*)(base)) + (offset)) = (val) +#define MMIO_OUT32(base, offset, val) \ + *(volatile u32 *)(void *)(((u8*)(base)) + (offset)) = (val) + + + +/* ------------- XGI 300 series -------------- */ + +/* Macros to do useful things with the XGI BitBLT engine */ + +/* BR(16) (0x8420): + + bit 31 2D engine: 1 is idle, + bit 30 3D engine: 1 is idle, + bit 29 Command queue: 1 is empty + + bits 28:24: Current CPU driven BitBlt buffer stage bit[4:0] + + bits 15:0: Current command queue length + +*/ + +/* TW: BR(16)+2 = 0x8242 */ + +int xgiCmdQueLen; + +#define XGI300Idle \ + { \ + while( (MMIO_IN16(xgi_video_info.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \ + while( (MMIO_IN16(xgi_video_info.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \ + while( (MMIO_IN16(xgi_video_info.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \ + xgiCmdQueLen=MMIO_IN16(xgi_video_info.mmio_vbase, 0x8240); \ + } +/* TW: (do three times, because 2D engine seems quite unsure about whether or not it's idle) */ + +#define XGI300SetupSRCBase(base) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(0), base);\ + xgiCmdQueLen --; + +#define XGI300SetupSRCPitch(pitch) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT16(xgi_video_info.mmio_vbase, BR(1), pitch);\ + xgiCmdQueLen --; + +#define XGI300SetupSRCXY(x,y) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(2), (x)<<16 | (y) );\ + xgiCmdQueLen --; + +#define XGI300SetupDSTBase(base) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(4), base);\ + xgiCmdQueLen --; + +#define XGI300SetupDSTXY(x,y) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(3), (x)<<16 | (y) );\ + xgiCmdQueLen --; + +#define XGI300SetupDSTRect(x,y) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(5), (y)<<16 | (x) );\ + xgiCmdQueLen --; + +#define XGI300SetupDSTColorDepth(bpp) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT16(xgi_video_info.mmio_vbase, BR(1)+2, bpp);\ + xgiCmdQueLen --; + +#define XGI300SetupRect(w,h) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(6), (h)<<16 | (w) );\ + xgiCmdQueLen --; + +#define XGI300SetupPATFG(color) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(7), color);\ + xgiCmdQueLen --; + +#define XGI300SetupPATBG(color) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(8), color);\ + xgiCmdQueLen --; + +#define XGI300SetupSRCFG(color) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(9), color);\ + xgiCmdQueLen --; + +#define XGI300SetupSRCBG(color) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(10), color);\ + xgiCmdQueLen --; + +/* 0x8224 src colorkey high */ +/* 0x8228 src colorkey low */ +/* 0x821c dest colorkey high */ +/* 0x8220 dest colorkey low */ +#define XGI300SetupSRCTrans(color) \ + if (xgiCmdQueLen <= 1) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, 0x8224, color);\ + MMIO_OUT32(xgi_video_info.mmio_vbase, 0x8228, color);\ + xgiCmdQueLen -= 2; + +#define XGI300SetupDSTTrans(color) \ + if (xgiCmdQueLen <= 1) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, 0x821C, color); \ + MMIO_OUT32(xgi_video_info.mmio_vbase, 0x8220, color); \ + xgiCmdQueLen -= 2; + +#define XGI300SetupMONOPAT(p0,p1) \ + if (xgiCmdQueLen <= 1) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(11), p0);\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(12), p1);\ + xgiCmdQueLen -= 2; + +#define XGI300SetupClipLT(left,top) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(13), ((left) & 0xFFFF) | (top)<<16 );\ + xgiCmdQueLen--; + +#define XGI300SetupClipRB(right,bottom) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(14), ((right) & 0xFFFF) | (bottom)<<16 );\ + xgiCmdQueLen--; + +/* General */ +#define XGI300SetupROP(rop) \ + xgi_video_info.CommandReg = (rop) << 8; + +#define XGI300SetupCMDFlag(flags) \ + xgi_video_info.CommandReg |= (flags); + +#define XGI300DoCMD \ + if (xgiCmdQueLen <= 1) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(15), xgi_video_info.CommandReg); \ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(16), 0);\ + xgiCmdQueLen -= 2; + +/* Line */ +#define XGI300SetupX0Y0(x,y) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(2), (y)<<16 | (x) );\ + xgiCmdQueLen--; + +#define XGI300SetupX1Y1(x,y) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(3), (y)<<16 | (x) );\ + xgiCmdQueLen--; + +#define XGI300SetupLineCount(c) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT16(xgi_video_info.mmio_vbase, BR(6), c);\ + xgiCmdQueLen--; + +#define XGI300SetupStylePeriod(p) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT16(xgi_video_info.mmio_vbase, BR(6)+2, p);\ + xgiCmdQueLen--; + +#define XGI300SetupStyleLow(ls) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(11), ls);\ + xgiCmdQueLen--; + +#define XGI300SetupStyleHigh(ls) \ + if (xgiCmdQueLen <= 0) XGI300Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, BR(12), ls);\ + xgiCmdQueLen--; + + + +/* ----------- XGI 310/325 series --------------- */ + +/* Q_STATUS: + bit 31 = 1: All engines idle and all queues empty + bit 30 = 1: Hardware Queue (=HW CQ, 2D queue, 3D queue) empty + bit 29 = 1: 2D engine is idle + bit 28 = 1: 3D engine is idle + bit 27 = 1: HW command queue empty + bit 26 = 1: 2D queue empty + bit 25 = 1: 3D queue empty + bit 24 = 1: SW command queue empty + bits 23:16: 2D counter 3 + bits 15:8: 2D counter 2 + bits 7:0: 2D counter 1 + + Where is the command queue length (current amount of commands the queue + can accept) on the 310/325 series? (The current implementation is taken + from 300 series and certainly wrong...) +*/ + +/* TW: FIXME: xgiCmdQueLen is... where....? */ +#define XGI310Idle \ + { \ + while( (MMIO_IN16(xgi_video_info.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ + while( (MMIO_IN16(xgi_video_info.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ + xgiCmdQueLen=MMIO_IN16(xgi_video_info.mmio_vbase, Q_STATUS); \ + } + +#define XGI310SetupSRCBase(base) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, SRC_ADDR, base);\ + xgiCmdQueLen--; + +#define XGI310SetupSRCPitch(pitch) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT16(xgi_video_info.mmio_vbase, SRC_PITCH, pitch);\ + xgiCmdQueLen--; + +#define XGI310SetupSRCXY(x,y) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, SRC_Y, (x)<<16 | (y) );\ + xgiCmdQueLen--; + +#define XGI310SetupDSTBase(base) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, DST_ADDR, base);\ + xgiCmdQueLen--; + +#define XGI310SetupDSTXY(x,y) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, DST_Y, (x)<<16 | (y) );\ + xgiCmdQueLen--; + +#define XGI310SetupDSTRect(x,y) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, DST_PITCH, (y)<<16 | (x) );\ + xgiCmdQueLen--; + +#define XGI310SetupDSTColorDepth(bpp) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT16(xgi_video_info.mmio_vbase, AGP_BASE, bpp);\ + xgiCmdQueLen--; + +#define XGI310SetupRect(w,h) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, RECT_WIDTH, (h)<<16 | (w) );\ + xgiCmdQueLen--; + +#define XGI310SetupPATFG(color) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, PAT_FGCOLOR, color);\ + xgiCmdQueLen--; + +#define XGI310SetupPATBG(color) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, PAT_BGCOLOR, color);\ + xgiCmdQueLen--; + +#define XGI310SetupSRCFG(color) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, SRC_FGCOLOR, color);\ + xgiCmdQueLen--; + +#define XGI310SetupSRCBG(color) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, SRC_BGCOLOR, color);\ + xgiCmdQueLen--; + +#define XGI310SetupSRCTrans(color) \ + if (xgiCmdQueLen <= 1) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, TRANS_SRC_KEY_HIGH, color);\ + MMIO_OUT32(xgi_video_info.mmio_vbase, TRANS_SRC_KEY_LOW, color);\ + xgiCmdQueLen -= 2; + +#define XGI310SetupDSTTrans(color) \ + if (xgiCmdQueLen <= 1) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, TRANS_DST_KEY_HIGH, color); \ + MMIO_OUT32(xgi_video_info.mmio_vbase, TRANS_DST_KEY_LOW, color); \ + xgiCmdQueLen -= 2; + +#define XGI310SetupMONOPAT(p0,p1) \ + if (xgiCmdQueLen <= 1) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, MONO_MASK, p0);\ + MMIO_OUT32(xgi_video_info.mmio_vbase, MONO_MASK+4, p1);\ + xgiCmdQueLen -= 2; + +#define XGI310SetupClipLT(left,top) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, LEFT_CLIP, ((left) & 0xFFFF) | (top)<<16 );\ + xgiCmdQueLen--; + +#define XGI310SetupClipRB(right,bottom) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, RIGHT_CLIP, ((right) & 0xFFFF) | (bottom)<<16 );\ + xgiCmdQueLen--; + +#define XGI310SetupROP(rop) \ + xgi_video_info.CommandReg = (rop) << 8; + +#define XGI310SetupCMDFlag(flags) \ + xgi_video_info.CommandReg |= (flags); + +#define XGI310DoCMD \ + if (xgiCmdQueLen <= 1) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, COMMAND_READY, xgi_video_info.CommandReg); \ + MMIO_OUT32(xgi_video_info.mmio_vbase, FIRE_TRIGGER, 0); \ + xgiCmdQueLen -= 2; + +#define XGI310SetupX0Y0(x,y) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, LINE_X0, (y)<<16 | (x) );\ + xgiCmdQueLen--; + +#define XGI310SetupX1Y1(x,y) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, LINE_X1, (y)<<16 | (x) );\ + xgiCmdQueLen--; + +#define XGI310SetupLineCount(c) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT16(xgi_video_info.mmio_vbase, LINE_COUNT, c);\ + xgiCmdQueLen--; + +#define XGI310SetupStylePeriod(p) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT16(xgi_video_info.mmio_vbase, LINE_STYLE_PERIOD, p);\ + xgiCmdQueLen--; + +#define XGI310SetupStyleLow(ls) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, LINE_STYLE_0, ls);\ + xgiCmdQueLen--; + +#define XGI310SetupStyleHigh(ls) \ + if (xgiCmdQueLen <= 0) XGI310Idle;\ + MMIO_OUT32(xgi_video_info.mmio_vbase, LINE_STYLE_1, ls);\ + xgiCmdQueLen--; + +int XGIfb_initaccel(void); +void XGIfb_syncaccel(void); + +extern struct video_info xgi_video_info; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33) +void fbcon_XGI_bmove(struct display *p, int srcy, int srcx, int dsty, + int dstx, int height, int width); +void fbcon_XGI_revc(struct display *p, int srcy, int srcx); +void fbcon_XGI_clear8(struct vc_data *conp, struct display *p, int srcy, + int srcx, int height, int width); +void fbcon_XGI_clear16(struct vc_data *conp, struct display *p, int srcy, + int srcx, int height, int width); +void fbcon_XGI_clear32(struct vc_data *conp, struct display *p, int srcy, + int srcx, int height, int width); +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) +extern int XGIfb_accel; +void fbcon_XGI_fillrect(struct fb_info *info, const struct fb_fillrect *rect); +void fbcon_XGI_copyarea(struct fb_info *info, const struct fb_copyarea *area); +#endif + +#endif diff --git a/drivers/staging/xgifb/XGI_main.h b/drivers/staging/xgifb/XGI_main.h new file mode 100644 index 000000000000..4f4171e8a68a --- /dev/null +++ b/drivers/staging/xgifb/XGI_main.h @@ -0,0 +1,1023 @@ +#ifndef _XGIFB_MAIN +#define _XGIFB_MAIN + + +/* ------------------- Constant Definitions ------------------------- */ + + +#include "XGIfb.h" +#include "vb_struct.h" +#include "vb_def.h" + +//#define LINUXBIOS /* turn this on when compiling for LINUXBIOS */ +#define AGPOFF /* default is turn off AGP */ + +#define XGIFAIL(x) do { printk(x "\n"); return -EINVAL; } while(0) + +#define VER_MAJOR 0 +#define VER_MINOR 8 +#define VER_LEVEL 1 + +#define DRIVER_DESC "XGI Volari Frame Buffer Module Version 0.8.1" + +#ifndef PCI_VENDOR_ID_XG +#define PCI_VENDOR_ID_XG 0x18CA +#endif + +#ifndef PCI_DEVICE_ID_XG_40 +#define PCI_DEVICE_ID_XG_40 0x040 +#endif +#ifndef PCI_DEVICE_ID_XG_41 +#define PCI_DEVICE_ID_XG_41 0x041 +#endif +#ifndef PCI_DEVICE_ID_XG_42 +#define PCI_DEVICE_ID_XG_42 0x042 +#endif +#ifndef PCI_DEVICE_ID_XG_20 +#define PCI_DEVICE_ID_XG_20 0x020 +#endif +#ifndef PCI_DEVICE_ID_XG_27 +#define PCI_DEVICE_ID_XG_27 0x027 +#endif + + + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) +#define XGI_IOTYPE1 void __iomem +#define XGI_IOTYPE2 __iomem +#define XGIINITSTATIC static +#else +#define XGI_IOTYPE1 unsigned char +#define XGI_IOTYPE2 +#define XGIINITSTATIC +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static struct pci_device_id __devinitdata xgifb_pci_table[] = { + + { PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_27, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_40, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + { PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, xgifb_pci_table); +#endif +/* To be included in fb.h */ +#ifndef FB_ACCEL_XGI_GLAMOUR_2 +#define FB_ACCEL_XGI_GLAMOUR_2 40 /* XGI 315, 650, 740 */ +#endif +#ifndef FB_ACCEL_XGI_XABRE +#define FB_ACCEL_XGI_XABRE 41 /* XGI 330 ("Xabre") */ +#endif + +#define MAX_ROM_SCAN 0x10000 + +#define HW_CURSOR_CAP 0x80 +#define TURBO_QUEUE_CAP 0x40 +#define AGP_CMD_QUEUE_CAP 0x20 +#define VM_CMD_QUEUE_CAP 0x10 +#define MMIO_CMD_QUEUE_CAP 0x08 + + + +/* For 315 series */ + +#define COMMAND_QUEUE_AREA_SIZE 0x80000 /* 512K */ +#define COMMAND_QUEUE_THRESHOLD 0x1F + + +/* TW */ +#define HW_CURSOR_AREA_SIZE_315 0x4000 /* 16K */ +#define HW_CURSOR_AREA_SIZE_300 0x1000 /* 4K */ + +#define OH_ALLOC_SIZE 4000 +#define SENTINEL 0x7fffffff + +#define SEQ_ADR 0x14 +#define SEQ_DATA 0x15 +#define DAC_ADR 0x18 +#define DAC_DATA 0x19 +#define CRTC_ADR 0x24 +#define CRTC_DATA 0x25 +#define DAC2_ADR (0x16-0x30) +#define DAC2_DATA (0x17-0x30) +#define VB_PART1_ADR (0x04-0x30) +#define VB_PART1_DATA (0x05-0x30) +#define VB_PART2_ADR (0x10-0x30) +#define VB_PART2_DATA (0x11-0x30) +#define VB_PART3_ADR (0x12-0x30) +#define VB_PART3_DATA (0x13-0x30) +#define VB_PART4_ADR (0x14-0x30) +#define VB_PART4_DATA (0x15-0x30) + +#define XGISR XGI_Pr.P3c4 +#define XGICR XGI_Pr.P3d4 +#define XGIDACA XGI_Pr.P3c8 +#define XGIDACD XGI_Pr.P3c9 +#define XGIPART1 XGI_Pr.Part1Port +#define XGIPART2 XGI_Pr.Part2Port +#define XGIPART3 XGI_Pr.Part3Port +#define XGIPART4 XGI_Pr.Part4Port +#define XGIPART5 XGI_Pr.Part5Port +#define XGIDAC2A XGIPART5 +#define XGIDAC2D (XGIPART5 + 1) +#define XGIMISCR (XGI_Pr.RelIO + 0x1c) +#define XGIINPSTAT (XGI_Pr.RelIO + 0x2a) + +#define IND_XGI_PASSWORD 0x05 /* SRs */ +#define IND_XGI_COLOR_MODE 0x06 +#define IND_XGI_RAMDAC_CONTROL 0x07 +#define IND_XGI_DRAM_SIZE 0x14 +#define IND_XGI_SCRATCH_REG_16 0x16 +#define IND_XGI_SCRATCH_REG_17 0x17 +#define IND_XGI_SCRATCH_REG_1A 0x1A +#define IND_XGI_MODULE_ENABLE 0x1E +#define IND_XGI_PCI_ADDRESS_SET 0x20 +#define IND_XGI_TURBOQUEUE_ADR 0x26 +#define IND_XGI_TURBOQUEUE_SET 0x27 +#define IND_XGI_POWER_ON_TRAP 0x38 +#define IND_XGI_POWER_ON_TRAP2 0x39 +#define IND_XGI_CMDQUEUE_SET 0x26 +#define IND_XGI_CMDQUEUE_THRESHOLD 0x27 + +#define IND_XGI_SCRATCH_REG_CR30 0x30 /* CRs */ +#define IND_XGI_SCRATCH_REG_CR31 0x31 +#define IND_XGI_SCRATCH_REG_CR32 0x32 +#define IND_XGI_SCRATCH_REG_CR33 0x33 +#define IND_XGI_LCD_PANEL 0x36 +#define IND_XGI_SCRATCH_REG_CR37 0x37 +#define IND_XGI_AGP_IO_PAD 0x48 + +#define IND_BRI_DRAM_STATUS 0x63 /* PCI config memory size offset */ + +#define MMIO_QUEUE_PHYBASE 0x85C0 +#define MMIO_QUEUE_WRITEPORT 0x85C4 +#define MMIO_QUEUE_READPORT 0x85C8 + +#define IND_XGI_CRT2_WRITE_ENABLE_300 0x24 +#define IND_XGI_CRT2_WRITE_ENABLE_315 0x2F + +#define XGI_PASSWORD 0x86 /* SR05 */ +#define XGI_INTERLACED_MODE 0x20 /* SR06 */ +#define XGI_8BPP_COLOR_MODE 0x0 +#define XGI_15BPP_COLOR_MODE 0x1 +#define XGI_16BPP_COLOR_MODE 0x2 +#define XGI_32BPP_COLOR_MODE 0x4 + +#define XGI_DRAM_SIZE_MASK 0xF0 /*SR14 */ +#define XGI_DRAM_SIZE_1MB 0x00 +#define XGI_DRAM_SIZE_2MB 0x01 +#define XGI_DRAM_SIZE_4MB 0x02 +#define XGI_DRAM_SIZE_8MB 0x03 +#define XGI_DRAM_SIZE_16MB 0x04 +#define XGI_DRAM_SIZE_32MB 0x05 +#define XGI_DRAM_SIZE_64MB 0x06 +#define XGI_DRAM_SIZE_128MB 0x07 +#define XGI_DRAM_SIZE_256MB 0x08 +#define XGI_DATA_BUS_MASK 0x02 +#define XGI_DATA_BUS_64 0x00 +#define XGI_DATA_BUS_128 0x01 +#define XGI_DUAL_CHANNEL_MASK 0x0C +#define XGI_SINGLE_CHANNEL_1_RANK 0x0 +#define XGI_SINGLE_CHANNEL_2_RANK 0x1 +#define XGI_ASYM_DDR 0x02 +#define XGI_DUAL_CHANNEL_1_RANK 0x3 + +#define XGI550_DRAM_SIZE_MASK 0x3F /* 550/650/740 SR14 */ +#define XGI550_DRAM_SIZE_4MB 0x00 +#define XGI550_DRAM_SIZE_8MB 0x01 +#define XGI550_DRAM_SIZE_16MB 0x03 +#define XGI550_DRAM_SIZE_24MB 0x05 +#define XGI550_DRAM_SIZE_32MB 0x07 +#define XGI550_DRAM_SIZE_64MB 0x0F +#define XGI550_DRAM_SIZE_96MB 0x17 +#define XGI550_DRAM_SIZE_128MB 0x1F +#define XGI550_DRAM_SIZE_256MB 0x3F + +#define XGI_SCRATCH_REG_1A_MASK 0x10 + +#define XGI_ENABLE_2D 0x40 /* SR1E */ + +#define XGI_MEM_MAP_IO_ENABLE 0x01 /* SR20 */ +#define XGI_PCI_ADDR_ENABLE 0x80 + +#define XGI_AGP_CMDQUEUE_ENABLE 0x80 /* 315/650/740 SR26 */ +#define XGI_VRAM_CMDQUEUE_ENABLE 0x40 +#define XGI_MMIO_CMD_ENABLE 0x20 +#define XGI_CMD_QUEUE_SIZE_512k 0x00 +#define XGI_CMD_QUEUE_SIZE_1M 0x04 +#define XGI_CMD_QUEUE_SIZE_2M 0x08 +#define XGI_CMD_QUEUE_SIZE_4M 0x0C +#define XGI_CMD_QUEUE_RESET 0x01 +#define XGI_CMD_AUTO_CORR 0x02 + +#define XGI_SIMULTANEOUS_VIEW_ENABLE 0x01 /* CR30 */ +#define XGI_MODE_SELECT_CRT2 0x02 +#define XGI_VB_OUTPUT_COMPOSITE 0x04 +#define XGI_VB_OUTPUT_SVIDEO 0x08 +#define XGI_VB_OUTPUT_SCART 0x10 +#define XGI_VB_OUTPUT_LCD 0x20 +#define XGI_VB_OUTPUT_CRT2 0x40 +#define XGI_VB_OUTPUT_HIVISION 0x80 + +#define XGI_VB_OUTPUT_DISABLE 0x20 /* CR31 */ +#define XGI_DRIVER_MODE 0x40 + +#define XGI_VB_COMPOSITE 0x01 /* CR32 */ +#define XGI_VB_SVIDEO 0x02 +#define XGI_VB_SCART 0x04 +#define XGI_VB_LCD 0x08 +#define XGI_VB_CRT2 0x10 +#define XGI_CRT1 0x20 +#define XGI_VB_HIVISION 0x40 +#define XGI_VB_YPBPR 0x80 +#define XGI_VB_TV (XGI_VB_COMPOSITE | XGI_VB_SVIDEO | \ + XGI_VB_SCART | XGI_VB_HIVISION|XGI_VB_YPBPR) + +#define XGI_EXTERNAL_CHIP_MASK 0x0E /* CR37 */ +#define XGI_EXTERNAL_CHIP_XGI301 0x01 /* in CR37 << 1 ! */ +#define XGI_EXTERNAL_CHIP_LVDS 0x02 /* in CR37 << 1 ! */ +#define XGI_EXTERNAL_CHIP_TRUMPION 0x03 /* in CR37 << 1 ! */ +#define XGI_EXTERNAL_CHIP_LVDS_CHRONTEL 0x04 /* in CR37 << 1 ! */ +#define XGI_EXTERNAL_CHIP_CHRONTEL 0x05 /* in CR37 << 1 ! */ +#define XGI310_EXTERNAL_CHIP_LVDS 0x02 /* in CR37 << 1 ! */ +#define XGI310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03 /* in CR37 << 1 ! */ + +#define XGI_AGP_2X 0x20 /* CR48 */ + +#define BRI_DRAM_SIZE_MASK 0x70 /* PCI bridge config data */ +#define BRI_DRAM_SIZE_2MB 0x00 +#define BRI_DRAM_SIZE_4MB 0x01 +#define BRI_DRAM_SIZE_8MB 0x02 +#define BRI_DRAM_SIZE_16MB 0x03 +#define BRI_DRAM_SIZE_32MB 0x04 +#define BRI_DRAM_SIZE_64MB 0x05 + +#define HW_DEVICE_EXTENSION XGI_HW_DEVICE_INFO +#define PHW_DEVICE_EXTENSION PXGI_HW_DEVICE_INFO + +#define SR_BUFFER_SIZE 5 +#define CR_BUFFER_SIZE 5 + +/* Useful macros */ +#define inXGIREG(base) inb(base) +#define outXGIREG(base,val) outb(val,base) +#define orXGIREG(base,val) do { \ + unsigned char __Temp = inb(base); \ + outXGIREG(base, __Temp | (val)); \ + } while (0) +#define andXGIREG(base,val) do { \ + unsigned char __Temp = inb(base); \ + outXGIREG(base, __Temp & (val)); \ + } while (0) +#define inXGIIDXREG(base,idx,var) do { \ + outb(idx,base); var=inb((base)+1); \ + } while (0) +#define outXGIIDXREG(base,idx,val) do { \ + outb(idx,base); outb((val),(base)+1); \ + } while (0) +#define orXGIIDXREG(base,idx,val) do { \ + unsigned char __Temp; \ + outb(idx,base); \ + __Temp = inb((base)+1)|(val); \ + outXGIIDXREG(base,idx,__Temp); \ + } while (0) +#define andXGIIDXREG(base,idx,and) do { \ + unsigned char __Temp; \ + outb(idx,base); \ + __Temp = inb((base)+1)&(and); \ + outXGIIDXREG(base,idx,__Temp); \ + } while (0) +#define setXGIIDXREG(base,idx,and,or) do { \ + unsigned char __Temp; \ + outb(idx,base); \ + __Temp = (inb((base)+1)&(and))|(or); \ + outXGIIDXREG(base,idx,__Temp); \ + } while (0) + +/* ------------------- Global Variables ----------------------------- */ + +/* Fbcon variables */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static struct fb_info* fb_info; +#else +static struct fb_info XGI_fb_info; +#endif + + +static int video_type = FB_TYPE_PACKED_PIXELS; + +static struct fb_var_screeninfo default_var = { + .xres = 0, + .yres = 0, + .xres_virtual = 0, + .yres_virtual = 0, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = 0, + .grayscale = 0, + .red = {0, 8, 0}, + .green = {0, 8, 0}, + .blue = {0, 8, 0}, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = 0, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 0, + .vsync_len = 0, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + .reserved = {0, 0, 0, 0, 0, 0} +#endif +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static struct fb_fix_screeninfo XGIfb_fix = { + .id = "XGI", + .type = FB_TYPE_PACKED_PIXELS, + .xpanstep = 1, + .ypanstep = 1, +}; +static char myid[20]; +static u32 pseudo_palette[17]; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static struct display XGI_disp; + +static struct display_switch XGIfb_sw; + +static struct { + u16 blue, green, red, pad; +} XGI_palette[256]; + +static union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif +} XGI_fbcon_cmap; + +static int XGIfb_inverse = 0; +#endif + +/* display status */ +static int XGIfb_off = 0; +static int XGIfb_crt1off = 0; +static int XGIfb_forcecrt1 = -1; +static int XGIvga_enabled = 0; +static int XGIfb_userom = 0; +//static int XGIfb_useoem = -1; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static int currcon = 0; +#endif + +/* global flags */ +static int XGIfb_registered; +static int XGIfb_tvmode = 0; +static int XGIfb_mem = 0; +static int XGIfb_pdc = 0; +static int enable_dstn = 0; +static int XGIfb_ypan = -1; + + +int XGIfb_accel = 0; + + +static int XGIfb_hwcursor_size = 0; +static int XGIfb_CRT2_write_enable = 0; + +int XGIfb_crt2type = -1; /* TW: CRT2 type (for overriding autodetection) */ +int XGIfb_tvplug = -1; /* PR: Tv plug type (for overriding autodetection) */ + +int XGIfb_queuemode = -1; /* TW: Use MMIO queue mode by default (310/325 series only) */ + +unsigned char XGIfb_detectedpdc = 0; + +unsigned char XGIfb_detectedlcda = 0xff; + + + + +/* TW: For ioctl XGIFB_GET_INFO */ +/* XGIfb_info XGIfbinfo; */ + +/* TW: Hardware extension; contains data on hardware */ +HW_DEVICE_EXTENSION XGIhw_ext; + +/* TW: XGI private structure */ +VB_DEVICE_INFO XGI_Pr; + +/* card parameters */ +static unsigned long XGIfb_mmio_size = 0; +static u8 XGIfb_caps = 0; + +typedef enum _XGI_CMDTYPE { + MMIO_CMD = 0, + AGP_CMD_QUEUE, + VM_CMD_QUEUE, +} XGI_CMDTYPE; + +#define MD_XGI300 1 +#define MD_XGI315 2 + +/* mode table */ +/* NOT const - will be patched for 1280x960 mode number chaos reasons */ +struct _XGIbios_mode { + char name[15]; + u8 mode_no; + u16 vesa_mode_no_1; /* "XGI defined" VESA mode number */ + u16 vesa_mode_no_2; /* Real VESA mode numbers */ + u16 xres; + u16 yres; + u16 bpp; + u16 rate_idx; + u16 cols; + u16 rows; + u8 chipset; +} XGIbios_mode[] = { +#define MODE_INDEX_NONE 0 /* TW: index for mode=none */ + {"none", 0xFF, 0x0000, 0x0000, 0, 0, 0, 0, 0, 0, MD_XGI300|MD_XGI315}, /* TW: for mode "none" */ + {"320x240x16", 0x56, 0x0000, 0x0000, 320, 240, 16, 1, 40, 15, MD_XGI315}, + {"320x480x8", 0x5A, 0x0000, 0x0000, 320, 480, 8, 1, 40, 30, MD_XGI315}, /* TW: FSTN */ + {"320x480x16", 0x5B, 0x0000, 0x0000, 320, 480, 16, 1, 40, 30, MD_XGI315}, /* TW: FSTN */ + {"640x480x8", 0x2E, 0x0101, 0x0101, 640, 480, 8, 1, 80, 30, MD_XGI300|MD_XGI315}, + {"640x480x16", 0x44, 0x0111, 0x0111, 640, 480, 16, 1, 80, 30, MD_XGI300|MD_XGI315}, + {"640x480x24", 0x62, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30, MD_XGI300|MD_XGI315}, /* TW: That's for people who mix up color- and fb depth */ + {"640x480x32", 0x62, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30, MD_XGI300|MD_XGI315}, + {"720x480x8", 0x31, 0x0000, 0x0000, 720, 480, 8, 1, 90, 30, MD_XGI300|MD_XGI315}, + {"720x480x16", 0x33, 0x0000, 0x0000, 720, 480, 16, 1, 90, 30, MD_XGI300|MD_XGI315}, + {"720x480x24", 0x35, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30, MD_XGI300|MD_XGI315}, + {"720x480x32", 0x35, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30, MD_XGI300|MD_XGI315}, + {"720x576x8", 0x32, 0x0000, 0x0000, 720, 576, 8, 1, 90, 36, MD_XGI300|MD_XGI315}, + {"720x576x16", 0x34, 0x0000, 0x0000, 720, 576, 16, 1, 90, 36, MD_XGI300|MD_XGI315}, + {"720x576x24", 0x36, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36, MD_XGI300|MD_XGI315}, + {"720x576x32", 0x36, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36, MD_XGI300|MD_XGI315}, + {"800x480x8", 0x70, 0x0000, 0x0000, 800, 480, 8, 1, 100, 30, MD_XGI300|MD_XGI315}, + {"800x480x16", 0x7a, 0x0000, 0x0000, 800, 480, 16, 1, 100, 30, MD_XGI300|MD_XGI315}, + {"800x480x24", 0x76, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, MD_XGI300|MD_XGI315}, + {"800x480x32", 0x76, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, MD_XGI300|MD_XGI315}, +#define DEFAULT_MODE 21 /* TW: index for 800x600x8 */ +#define DEFAULT_LCDMODE 21 /* TW: index for 800x600x8 */ +#define DEFAULT_TVMODE 21 /* TW: index for 800x600x8 */ + {"800x600x8", 0x30, 0x0103, 0x0103, 800, 600, 8, 1, 100, 37, MD_XGI300|MD_XGI315}, + {"800x600x16", 0x47, 0x0114, 0x0114, 800, 600, 16, 1, 100, 37, MD_XGI300|MD_XGI315}, + {"800x600x24", 0x63, 0x013b, 0x0115, 800, 600, 32, 1, 100, 37, MD_XGI300|MD_XGI315}, + {"800x600x32", 0x63, 0x013b, 0x0115, 800, 600, 32, 1, 100, 37, MD_XGI300|MD_XGI315}, + {"1024x576x8", 0x71, 0x0000, 0x0000, 1024, 576, 8, 1, 128, 36, MD_XGI300|MD_XGI315}, + {"1024x576x16", 0x74, 0x0000, 0x0000, 1024, 576, 16, 1, 128, 36, MD_XGI300|MD_XGI315}, + {"1024x576x24", 0x77, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36, MD_XGI300|MD_XGI315}, + {"1024x576x32", 0x77, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36, MD_XGI300|MD_XGI315}, + {"1024x600x8", 0x20, 0x0000, 0x0000, 1024, 600, 8, 1, 128, 37, MD_XGI300 }, /* TW: 300 series only */ + {"1024x600x16", 0x21, 0x0000, 0x0000, 1024, 600, 16, 1, 128, 37, MD_XGI300 }, + {"1024x600x24", 0x22, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37, MD_XGI300 }, + {"1024x600x32", 0x22, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37, MD_XGI300 }, + {"1024x768x8", 0x38, 0x0105, 0x0105, 1024, 768, 8, 1, 128, 48, MD_XGI300|MD_XGI315}, + {"1024x768x16", 0x4A, 0x0117, 0x0117, 1024, 768, 16, 1, 128, 48, MD_XGI300|MD_XGI315}, + {"1024x768x24", 0x64, 0x013c, 0x0118, 1024, 768, 32, 1, 128, 48, MD_XGI300|MD_XGI315}, + {"1024x768x32", 0x64, 0x013c, 0x0118, 1024, 768, 32, 1, 128, 48, MD_XGI300|MD_XGI315}, + {"1152x768x8", 0x23, 0x0000, 0x0000, 1152, 768, 8, 1, 144, 48, MD_XGI300 }, /* TW: 300 series only */ + {"1152x768x16", 0x24, 0x0000, 0x0000, 1152, 768, 16, 1, 144, 48, MD_XGI300 }, + {"1152x768x24", 0x25, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48, MD_XGI300 }, + {"1152x768x32", 0x25, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48, MD_XGI300 }, + {"1280x720x8", 0x79, 0x0000, 0x0000, 1280, 720, 8, 1, 160, 45, MD_XGI300|MD_XGI315}, + {"1280x720x16", 0x75, 0x0000, 0x0000, 1280, 720, 16, 1, 160, 45, MD_XGI300|MD_XGI315}, + {"1280x720x24", 0x78, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45, MD_XGI300|MD_XGI315}, + {"1280x720x32", 0x78, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45, MD_XGI300|MD_XGI315}, + {"1280x768x8", 0x23, 0x0000, 0x0000, 1280, 768, 8, 1, 160, 48, MD_XGI315}, /* TW: 310/325 series only */ + {"1280x768x16", 0x24, 0x0000, 0x0000, 1280, 768, 16, 1, 160, 48, MD_XGI315}, + {"1280x768x24", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, MD_XGI315}, + {"1280x768x32", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, MD_XGI315}, +#define MODEINDEX_1280x960 48 + {"1280x960x8", 0x7C, 0x0000, 0x0000, 1280, 960, 8, 1, 160, 60, MD_XGI300|MD_XGI315}, /* TW: Modenumbers being patched */ + {"1280x960x16", 0x7D, 0x0000, 0x0000, 1280, 960, 16, 1, 160, 60, MD_XGI300|MD_XGI315}, + {"1280x960x24", 0x7E, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_XGI300|MD_XGI315}, + {"1280x960x32", 0x7E, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_XGI300|MD_XGI315}, + {"1280x1024x8", 0x3A, 0x0107, 0x0107, 1280, 1024, 8, 1, 160, 64, MD_XGI300|MD_XGI315}, + {"1280x1024x16", 0x4D, 0x011a, 0x011a, 1280, 1024, 16, 1, 160, 64, MD_XGI300|MD_XGI315}, + {"1280x1024x24", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64, MD_XGI300|MD_XGI315}, + {"1280x1024x32", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64, MD_XGI300|MD_XGI315}, + {"1400x1050x8", 0x26, 0x0000, 0x0000, 1400, 1050, 8, 1, 175, 65, MD_XGI315}, /* TW: 310/325 series only */ + {"1400x1050x16", 0x27, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65, MD_XGI315}, + {"1400x1050x24", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, MD_XGI315}, + {"1400x1050x32", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, MD_XGI315}, + {"1600x1200x8", 0x3C, 0x0130, 0x011c, 1600, 1200, 8, 1, 200, 75, MD_XGI300|MD_XGI315}, + {"1600x1200x16", 0x3D, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_XGI300|MD_XGI315}, + {"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_XGI300|MD_XGI315}, + {"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_XGI300|MD_XGI315}, + {"1920x1440x8", 0x68, 0x013f, 0x0000, 1920, 1440, 8, 1, 240, 75, MD_XGI300|MD_XGI315}, + {"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_XGI300|MD_XGI315}, + {"1920x1440x24", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_XGI300|MD_XGI315}, + {"1920x1440x32", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_XGI300|MD_XGI315}, + {"2048x1536x8", 0x6c, 0x0000, 0x0000, 2048, 1536, 8, 1, 256, 96, MD_XGI315}, /* TW: 310/325 series only */ + {"2048x1536x16", 0x6d, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96, MD_XGI315}, + {"2048x1536x24", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, MD_XGI315}, + {"2048x1536x32", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, MD_XGI315}, + {"\0", 0x00, 0, 0, 0, 0, 0, 0, 0} +}; + +/* mode-related variables */ +#ifdef MODULE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static int xgifb_mode_idx = 1; +#else +static int XGIfb_mode_idx = MODE_INDEX_NONE; /* Don't use a mode by default if we are a module */ +#endif +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static int xgifb_mode_idx = -1; /* Use a default mode if we are inside the kernel */ +#else +static int XGIfb_mode_idx = -1; +#endif +#endif +u8 XGIfb_mode_no = 0; +u8 XGIfb_rate_idx = 0; + +/* TW: CR36 evaluation */ +const USHORT XGI300paneltype[] = + { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_1280x960, LCD_640x480, LCD_1024x600, LCD_1152x768, + LCD_1024x768, LCD_1024x768, LCD_1024x768, + LCD_1024x768, LCD_1024x768, LCD_1024x768, LCD_1024x768 }; + +const USHORT XGI310paneltype[] = + { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, + LCD_1152x768, LCD_1400x1050,LCD_1280x768, LCD_1600x1200, + LCD_1024x768, LCD_1024x768, LCD_1024x768 }; + +static const struct _XGI_crt2type { + char name[10]; + int type_no; + int tvplug_no; +} XGI_crt2type[] = { + {"NONE", 0, -1}, + {"LCD", DISPTYPE_LCD, -1}, + {"TV", DISPTYPE_TV, -1}, + {"VGA", DISPTYPE_CRT2, -1}, + {"SVIDEO", DISPTYPE_TV, TVPLUG_SVIDEO}, + {"COMPOSITE", DISPTYPE_TV, TVPLUG_COMPOSITE}, + {"SCART", DISPTYPE_TV, TVPLUG_SCART}, + {"none", 0, -1}, + {"lcd", DISPTYPE_LCD, -1}, + {"tv", DISPTYPE_TV, -1}, + {"vga", DISPTYPE_CRT2, -1}, + {"svideo", DISPTYPE_TV, TVPLUG_SVIDEO}, + {"composite", DISPTYPE_TV, TVPLUG_COMPOSITE}, + {"scart", DISPTYPE_TV, TVPLUG_SCART}, + {"\0", -1, -1} +}; + +/* Queue mode selection for 310 series */ +static const struct _XGI_queuemode { + char name[6]; + int type_no; +} XGI_queuemode[] = { + {"AGP", AGP_CMD_QUEUE}, + {"VRAM", VM_CMD_QUEUE}, + {"MMIO", MMIO_CMD}, + {"agp", AGP_CMD_QUEUE}, + {"vram", VM_CMD_QUEUE}, + {"mmio", MMIO_CMD}, + {"\0", -1} +}; + +/* TV standard */ +static const struct _XGI_tvtype { + char name[6]; + int type_no; +} XGI_tvtype[] = { + {"PAL", 1}, + {"NTSC", 2}, + {"pal", 1}, + {"ntsc", 2}, + {"\0", -1} +}; + +static const struct _XGI_vrate { + u16 idx; + u16 xres; + u16 yres; + u16 refresh; +} XGIfb_vrate[] = { + {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85}, + {5, 640, 480,100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200}, + {1, 720, 480, 60}, + {1, 720, 576, 58}, + {1, 800, 480, 60}, {2, 800, 480, 75}, {3, 800, 480, 85}, + {1, 800, 600, 60}, {2, 800, 600, 72}, {3, 800, 600, 75}, + {4, 800, 600, 85}, {5, 800, 600, 100}, {6, 800, 600, 120}, {7, 800, 600, 160}, + {1, 1024, 768, 60}, {2, 1024, 768, 70}, {3, 1024, 768, 75}, + {4, 1024, 768, 85}, {5, 1024, 768, 100}, {6, 1024, 768, 120}, + {1, 1024, 576, 60}, {2, 1024, 576, 75}, {3, 1024, 576, 85}, + {1, 1024, 600, 60}, + {1, 1152, 768, 60}, + {1, 1280, 720, 60}, {2, 1280, 720, 75}, {3, 1280, 720, 85}, + {1, 1280, 768, 60}, + {1, 1280, 1024, 60}, {2, 1280, 1024, 75}, {3, 1280, 1024, 85}, + {1, 1280, 960, 70}, + {1, 1400, 1050, 60}, + {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75}, + {5, 1600, 1200, 85}, {6, 1600, 1200, 100}, {7, 1600, 1200, 120}, + {1, 1920, 1440, 60}, {2, 1920, 1440, 65}, {3, 1920, 1440, 70}, {4, 1920, 1440, 75}, + {5, 1920, 1440, 85}, {6, 1920, 1440, 100}, + {1, 2048, 1536, 60}, {2, 2048, 1536, 65}, {3, 2048, 1536, 70}, {4, 2048, 1536, 75}, + {5, 2048, 1536, 85}, + {0, 0, 0, 0} +}; + +static const struct _chswtable { + int subsysVendor; + int subsysCard; + char *vendorName; + char *cardName; +} mychswtable[] = { + { 0x1631, 0x1002, "Mitachi", "0x1002" }, + { 0, 0, "" , "" } +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +/* Offscreen layout */ +typedef struct _XGI_GLYINFO { + unsigned char ch; + int fontwidth; + int fontheight; + u8 gmask[72]; + int ngmask; +} XGI_GLYINFO; +#endif + +typedef struct _XGI_OH { + struct _XGI_OH *poh_next; + struct _XGI_OH *poh_prev; + unsigned long offset; + unsigned long size; +} XGI_OH; + +typedef struct _XGI_OHALLOC { + struct _XGI_OHALLOC *poha_next; + XGI_OH aoh[1]; +} XGI_OHALLOC; + +typedef struct _XGI_HEAP { + XGI_OH oh_free; + XGI_OH oh_used; + XGI_OH *poh_freelist; + XGI_OHALLOC *poha_chain; + unsigned long max_freesize; +} XGI_HEAP; + +static unsigned long XGIfb_hwcursor_vbase; + +static unsigned long XGIfb_heap_start; +static unsigned long XGIfb_heap_end; +static unsigned long XGIfb_heap_size; +static XGI_HEAP XGIfb_heap; + +// Eden Chen +static const struct _XGI_TV_filter { + u8 filter[9][4]; +} XGI_TV_filter[] = { + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_0 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_1 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_2 */ + {0xF5,0xEE,0x1B,0x44}, + {0xF8,0xF4,0x18,0x38}, + {0xEB,0x04,0x25,0x18}, + {0xF1,0x05,0x1F,0x16}, + {0xF6,0x06,0x1A,0x14}, + {0xFA,0x06,0x16,0x14}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_3 */ + {0xF1,0x04,0x1F,0x18}, + {0xEE,0x0D,0x22,0x06}, + {0xF7,0x06,0x19,0x14}, + {0xF4,0x0B,0x1C,0x0A}, + {0xFA,0x07,0x16,0x12}, + {0xF9,0x0A,0x17,0x0C}, + {0x00,0x07,0x10,0x12}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_4 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_5 */ + {0xF5,0xEE,0x1B,0x44}, + {0xF8,0xF4,0x18,0x38}, + {0xEB,0x04,0x25,0x18}, + {0xF1,0x05,0x1F,0x16}, + {0xF6,0x06,0x1A,0x14}, + {0xFA,0x06,0x16,0x14}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_6 */ + {0xEB,0x04,0x25,0x18}, + {0xE7,0x0E,0x29,0x04}, + {0xEE,0x0C,0x22,0x08}, + {0xF6,0x0B,0x1A,0x0A}, + {0xF9,0x0A,0x17,0x0C}, + {0xFC,0x0A,0x14,0x0C}, + {0x00,0x08,0x10,0x10}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_7 */ + {0xEC,0x02,0x24,0x1C}, + {0xF2,0x04,0x1E,0x18}, + {0xEB,0x15,0x25,0xF6}, + {0xF4,0x10,0x1C,0x00}, + {0xF8,0x0F,0x18,0x02}, + {0x00,0x04,0x10,0x18}, + {0x01,0x06,0x0F,0x14}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_0 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_1 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_2 */ + {0xF5,0xEE,0x1B,0x44}, + {0xF8,0xF4,0x18,0x38}, + {0xF1,0xF7,0x01,0x32}, + {0xF5,0xFB,0x1B,0x2A}, + {0xF9,0xFF,0x17,0x22}, + {0xFB,0x01,0x15,0x1E}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_3 */ + {0xF5,0xFB,0x1B,0x2A}, + {0xEE,0xFE,0x22,0x24}, + {0xF3,0x00,0x1D,0x20}, + {0xF9,0x03,0x17,0x1A}, + {0xFB,0x02,0x14,0x1E}, + {0xFB,0x04,0x15,0x18}, + {0x00,0x06,0x10,0x14}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_4 */ + {0x00,0xE0,0x10,0x60}, + {0x00,0xEE,0x10,0x44}, + {0x00,0xF4,0x10,0x38}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0x00,0x00,0x10,0x20}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_5 */ + {0xF5,0xEE,0x1B,0x44}, + {0xF8,0xF4,0x18,0x38}, + {0xF1,0xF7,0x1F,0x32}, + {0xF5,0xFB,0x1B,0x2A}, + {0xF9,0xFF,0x17,0x22}, + {0xFB,0x01,0x15,0x1E}, + {0x00,0x04,0x10,0x18}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_6 */ + {0xF5,0xEE,0x1B,0x2A}, + {0xEE,0xFE,0x22,0x24}, + {0xF3,0x00,0x1D,0x20}, + {0xF9,0x03,0x17,0x1A}, + {0xFB,0x02,0x14,0x1E}, + {0xFB,0x04,0x15,0x18}, + {0x00,0x06,0x10,0x14}, + {0xFF,0xFF,0xFF,0xFF} }}, + { {{0x00,0x00,0x00,0x40}, /* PALFilter_7 */ + {0xF5,0xEE,0x1B,0x44}, + {0xF8,0xF4,0x18,0x38}, + {0xFC,0xFB,0x14,0x2A}, + {0xEB,0x05,0x25,0x16}, + {0xF1,0x05,0x1F,0x16}, + {0xFA,0x07,0x16,0x12}, + {0x00,0x07,0x10,0x12}, + {0xFF,0xFF,0xFF,0xFF} }} +}; + +static int filter = -1; +static unsigned char filter_tb; + + +/* ---------------------- Routine prototypes ------------------------- */ + +/* Interface used by the world */ +#ifndef MODULE +XGIINITSTATIC int __init XGIfb_setup(char *options); +#endif + +/* Interface to the low level console driver */ + + + +/* fbdev routines */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + int XGIfb_init(void); +static int XGIfb_get_fix(struct fb_fix_screeninfo *fix, + int con, + struct fb_info *info); +static int XGIfb_get_var(struct fb_var_screeninfo *var, + int con, + struct fb_info *info); +static int XGIfb_set_var(struct fb_var_screeninfo *var, + int con, + struct fb_info *info); +static void XGIfb_crtc_to_var(struct fb_var_screeninfo *var); +static int XGIfb_get_cmap(struct fb_cmap *cmap, + int kspc, + int con, + struct fb_info *info); +static int XGIfb_set_cmap(struct fb_cmap *cmap, + int kspc, + int con, + struct fb_info *info); +static int XGIfb_update_var(int con, + struct fb_info *info); +static int XGIfb_switch(int con, + struct fb_info *info); +static void XGIfb_blank(int blank, + struct fb_info *info); +static void XGIfb_set_disp(int con, + struct fb_var_screeninfo *var, + struct fb_info *info); +static int XGI_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *fb_info); +static void XGIfb_do_install_cmap(int con, + struct fb_info *info); +static void XGI_get_glyph(struct fb_info *info, + XGI_GLYINFO *gly); +static int XGIfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); +static int XGIfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +XGIINITSTATIC int __init xgifb_init(void); +static int XGIfb_set_par(struct fb_info *info); +static int XGIfb_blank(int blank, + struct fb_info *info); +/*static int XGIfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); +*/ +extern void fbcon_XGI_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +extern void fbcon_XGI_copyarea(struct fb_info *info, + const struct fb_copyarea *area); +#if 0 +extern void cfb_imageblit(struct fb_info *info, + const struct fb_image *image); +#endif +extern int fbcon_XGI_sync(struct fb_info *info); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +static int XGIfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg); +#else +static int XGIfb_ioctl(struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg, + struct fb_info *info); +#endif + +/* +extern int XGIfb_mode_rate_to_dclock(VB_DEVICE_INFO *XGI_Pr, + PXGI_HW_DEVICE_INFO HwDeviceExtension, + unsigned char modeno, unsigned char rateindex); +extern int XGIfb_mode_rate_to_ddata(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceExtension, + unsigned char modeno, unsigned char rateindex, + unsigned int *left_margin, unsigned int *right_margin, + unsigned int *upper_margin, unsigned int *lower_margin, + unsigned int *hsync_len, unsigned int *vsync_len, + unsigned int *sync, unsigned int *vmode); +*/ +#endif + extern BOOLEAN XGI_SearchModeID( USHORT ModeNo,USHORT *ModeIdIndex, PVB_DEVICE_INFO ); +static int XGIfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); + +/* Internal 2D accelerator functions */ +extern int XGIfb_initaccel(void); +extern void XGIfb_syncaccel(void); + +/* Internal general routines */ +static void XGIfb_search_mode(const char *name); +static int XGIfb_validate_mode(int modeindex); +static u8 XGIfb_search_refresh_rate(unsigned int rate); +static int XGIfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info); +static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive, + struct fb_info *info); +static void XGIfb_pre_setmode(void); +static void XGIfb_post_setmode(void); + +static BOOLEAN XGIfb_CheckVBRetrace(void); +static BOOLEAN XGIfbcheckvretracecrt2(void); +static BOOLEAN XGIfbcheckvretracecrt1(void); +static BOOLEAN XGIfb_bridgeisslave(void); + +struct XGI_memreq { + unsigned long offset; + unsigned long size; +}; + +/* XGI-specific Export functions */ +void XGI_dispinfo(struct ap_data *rec); +void XGI_malloc(struct XGI_memreq *req); +void XGI_free(unsigned long base); + +/* Internal hardware access routines */ +void XGIfb_set_reg4(u16 port, unsigned long data); +u32 XGIfb_get_reg3(u16 port); + +/* Chipset-dependent internal routines */ + + +static int XGIfb_get_dram_size(void); +static void XGIfb_detect_VB(void); +static void XGIfb_get_VB_type(void); +static int XGIfb_has_VB(void); + + +/* Internal heap routines */ +static int XGIfb_heap_init(void); +static XGI_OH *XGIfb_poh_new_node(void); +static XGI_OH *XGIfb_poh_allocate(unsigned long size); +static void XGIfb_delete_node(XGI_OH *poh); +static void XGIfb_insert_node(XGI_OH *pohList, XGI_OH *poh); +static XGI_OH *XGIfb_poh_free(unsigned long base); +static void XGIfb_free_node(XGI_OH *poh); + +/* Internal routines to access PCI configuration space */ +BOOLEAN XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext, + unsigned long offset, unsigned long set, unsigned long *value); +//BOOLEAN XGIfb_query_north_bridge_space(PXGI_HW_DEVICE_INFO pXGIhw_ext, +// unsigned long offset, unsigned long set, unsigned long *value); + + +/* Routines from init.c/init301.c */ +extern void InitTo330Pointer(UCHAR,PVB_DEVICE_INFO pVBInfo); +extern BOOLEAN XGIInitNew(PXGI_HW_DEVICE_INFO HwDeviceExtension); +extern BOOLEAN XGISetModeNew(PXGI_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo); +//extern void XGI_SetEnableDstn(VB_DEVICE_INFO *XGI_Pr); +extern void XGI_LongWait(VB_DEVICE_INFO *XGI_Pr); +extern USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo ); +/* TW: Chrontel TV functions */ +extern USHORT XGI_GetCH700x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx); +extern void XGI_SetCH700x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx); +extern USHORT XGI_GetCH701x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx); +extern void XGI_SetCH701x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx); +extern void XGI_SetCH70xxANDOR(VB_DEVICE_INFO *XGI_Pr, USHORT tempax,USHORT tempbh); +extern void XGI_DDC2Delay(VB_DEVICE_INFO *XGI_Pr, USHORT delaytime); + +/* TW: Sensing routines */ +void XGI_Sense30x(void); +int XGIDoSense(int tempbl, int tempbh, int tempcl, int tempch); + +extern XGI21_LVDSCapStruct XGI21_LCDCapList[13]; +#endif diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c new file mode 100644 index 000000000000..867012b48a01 --- /dev/null +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -0,0 +1,3773 @@ +/* + * XG20, XG21, XG40, XG42 frame buffer device + * for Linux kernels 2.5.x, 2.6.x + * Base on TW's sis fbdev code. + */ + +//#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/console.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> +#include <linux/vt_kern.h> +#include <linux/capability.h> +#include <linux/fs.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/kernel.h> + +#include "osdef.h" + + +#ifndef XGIFB_PAN +#define XGIFB_PAN +#endif + +#include <asm/io.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include "XGIfb.h" +#include "vgatypes.h" +#include "XGI_main.h" +#include "vb_util.h" + + +#define Index_CR_GPIO_Reg1 0x48 +#define Index_CR_GPIO_Reg2 0x49 +#define Index_CR_GPIO_Reg3 0x4a + +#define GPIOG_EN (1<<6) +#define GPIOG_WRITE (1<<6) +#define GPIOG_READ (1<<1) +int XGIfb_GetXG21DefaultLVDSModeIdx(void); + +/* -------------------- Macro definitions ---------------------------- */ + +#undef XGIFBDEBUG + +#ifdef XGIFBDEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#ifdef XGIFBDEBUG +static void dumpVGAReg(void) +{ + u8 i,reg; + +outXGIIDXREG(XGISR, 0x05, 0x86); +/* +outXGIIDXREG(XGISR, 0x08, 0x4f); +outXGIIDXREG(XGISR, 0x0f, 0x20); +outXGIIDXREG(XGISR, 0x11, 0x4f); +outXGIIDXREG(XGISR, 0x13, 0x45); +outXGIIDXREG(XGISR, 0x14, 0x51); +outXGIIDXREG(XGISR, 0x1e, 0x41); +outXGIIDXREG(XGISR, 0x1f, 0x0); +outXGIIDXREG(XGISR, 0x20, 0xa1); +outXGIIDXREG(XGISR, 0x22, 0xfb); +outXGIIDXREG(XGISR, 0x26, 0x22); +outXGIIDXREG(XGISR, 0x3e, 0x07); +*/ + +//outXGIIDXREG(XGICR, 0x19, 0x00); +//outXGIIDXREG(XGICR, 0x1a, 0x3C); +//outXGIIDXREG(XGICR, 0x22, 0xff); +//outXGIIDXREG(XGICR, 0x3D, 0x10); + +//outXGIIDXREG(XGICR, 0x4a, 0xf3); + +//outXGIIDXREG(XGICR, 0x57, 0x0); +//outXGIIDXREG(XGICR, 0x7a, 0x2c); + +//outXGIIDXREG(XGICR, 0x82, 0xcc); +//outXGIIDXREG(XGICR, 0x8c, 0x0); +/* +outXGIIDXREG(XGICR, 0x99, 0x1); +outXGIIDXREG(XGICR, 0x41, 0x40); +*/ + + for(i=0; i < 0x4f; i++) + { + inXGIIDXREG(XGISR, i, reg); + printk("\no 3c4 %x",i); + printk("\ni 3c5 => %x",reg); + } + + for(i=0; i < 0xF0; i++) + { + inXGIIDXREG(XGICR, i, reg); + printk("\no 3d4 %x",i); + printk("\ni 3d5 => %x",reg); + } +/* + + outXGIIDXREG(XGIPART1,0x2F,1); + for(i=1; i < 0x50; i++) + { + inXGIIDXREG(XGIPART1, i, reg); + printk("\no d004 %x",i); + printk("\ni d005 => %x",reg); + } + + for(i=0; i < 0x50; i++) + { + inXGIIDXREG(XGIPART2, i, reg); + printk("\no d010 %x",i); + printk("\ni d011 => %x",reg); + } + for(i=0; i < 0x50; i++) + { + inXGIIDXREG(XGIPART3, i, reg); + printk("\no d012 %x",i); + printk("\ni d013 => %x",reg); + } + for(i=0; i < 0x50; i++) + { + inXGIIDXREG(XGIPART4, i, reg); + printk("\no d014 %x",i); + printk("\ni d015 => %x",reg); + } +*/ +} +#else +static inline void dumpVGAReg(void) {} +#endif + +/* data for XGI components */ +struct video_info xgi_video_info; + + +#if 1 +#define DEBUGPRN(x) +#else +#define DEBUGPRN(x) printk(KERN_INFO x "\n"); +#endif + + +/* --------------- Hardware Access Routines -------------------------- */ + +#ifdef LINUX_KERNEL +int +XGIfb_mode_rate_to_dclock(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceExtension, + unsigned char modeno, unsigned char rateindex) +{ + USHORT ModeNo = modeno; + USHORT ModeIdIndex = 0, ClockIndex = 0; + USHORT RefreshRateTableIndex = 0; + + /*ULONG temp = 0;*/ + int Clock; + XGI_Pr->ROMAddr = HwDeviceExtension->pjVirtualRomBase; + InitTo330Pointer( HwDeviceExtension->jChipType, XGI_Pr ) ; + + RefreshRateTableIndex = XGI_GetRatePtrCRT2( HwDeviceExtension, ModeNo , ModeIdIndex, XGI_Pr ) ; + +/* + temp = XGI_SearchModeID( ModeNo , &ModeIdIndex, XGI_Pr ) ; + if(!temp) { + printk(KERN_ERR "Could not find mode %x\n", ModeNo); + return 65000; + } + + RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex; + RefreshRateTableIndex += (rateindex - 1); + +*/ + ClockIndex = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + if(HwDeviceExtension->jChipType < XGI_315H) { + ClockIndex &= 0x3F; + } + Clock = XGI_Pr->VCLKData[ClockIndex].CLOCK * 1000 ; + + return(Clock); +} + +int +XGIfb_mode_rate_to_ddata(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceExtension, + unsigned char modeno, unsigned char rateindex, + u32 *left_margin, u32 *right_margin, + u32 *upper_margin, u32 *lower_margin, + u32 *hsync_len, u32 *vsync_len, + u32 *sync, u32 *vmode) +{ + USHORT ModeNo = modeno; + USHORT ModeIdIndex = 0, index = 0; + USHORT RefreshRateTableIndex = 0; + + unsigned short VRE, VBE, VRS, VBS, VDE, VT; + unsigned short HRE, HBE, HRS, HBS, HDE, HT; + unsigned char sr_data, cr_data, cr_data2; + unsigned long cr_data3; + int A, B, C, D, E, F, temp, j; + XGI_Pr->ROMAddr = HwDeviceExtension->pjVirtualRomBase; + InitTo330Pointer( HwDeviceExtension->jChipType, XGI_Pr ) ; + RefreshRateTableIndex = XGI_GetRatePtrCRT2( HwDeviceExtension, ModeNo , ModeIdIndex, XGI_Pr ) ; +/* + temp = XGI_SearchModeID( ModeNo, &ModeIdIndex, XGI_Pr); + if(!temp) return 0; + + RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex; + RefreshRateTableIndex += (rateindex - 1); +*/ + index = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + + sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[5]; + + cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[0]; + + /* Horizontal total */ + HT = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x03) << 8); + A = HT + 5; + + /*cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[1]; + + Horizontal display enable end + HDE = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x0C) << 6);*/ + HDE = (XGI_Pr->RefIndex[RefreshRateTableIndex].XRes >> 3) -1; + E = HDE + 1; + + cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[3]; + + /* Horizontal retrace (=sync) start */ + HRS = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0xC0) << 2); + F = HRS - E - 3; + + cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[1]; + + /* Horizontal blank start */ + HBS = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x30) << 4); + + sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[6]; + + cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[2]; + + cr_data2 = XGI_Pr->XGINEWUB_CRT1Table[index].CR[4]; + + /* Horizontal blank end */ + HBE = (cr_data & 0x1f) | + ((unsigned short) (cr_data2 & 0x80) >> 2) | + ((unsigned short) (sr_data & 0x03) << 6); + + /* Horizontal retrace (=sync) end */ + HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3); + + temp = HBE - ((E - 1) & 255); + B = (temp > 0) ? temp : (temp + 256); + + temp = HRE - ((E + F + 3) & 63); + C = (temp > 0) ? temp : (temp + 64); + + D = B - F - C; + + *left_margin = D * 8; + *right_margin = F * 8; + *hsync_len = C * 8; + + sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[14]; + + cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[8]; + + cr_data2 = XGI_Pr->XGINEWUB_CRT1Table[index].CR[9]; + + /* Vertical total */ + VT = (cr_data & 0xFF) | + ((unsigned short) (cr_data2 & 0x01) << 8) | + ((unsigned short)(cr_data2 & 0x20) << 4) | + ((unsigned short) (sr_data & 0x01) << 10); + A = VT + 2; + + //cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[10]; + + /* Vertical display enable end */ +/* VDE = (cr_data & 0xff) | + ((unsigned short) (cr_data2 & 0x02) << 7) | + ((unsigned short) (cr_data2 & 0x40) << 3) | + ((unsigned short) (sr_data & 0x02) << 9); */ + VDE = XGI_Pr->RefIndex[RefreshRateTableIndex].YRes -1; + E = VDE + 1; + + cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[10]; + + /* Vertical retrace (=sync) start */ + VRS = (cr_data & 0xff) | + ((unsigned short) (cr_data2 & 0x04) << 6) | + ((unsigned short) (cr_data2 & 0x80) << 2) | + ((unsigned short) (sr_data & 0x08) << 7); + F = VRS + 1 - E; + + cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[12]; + + cr_data3 = (XGI_Pr->XGINEWUB_CRT1Table[index].CR[14] & 0x80) << 5; + + /* Vertical blank start */ + VBS = (cr_data & 0xff) | + ((unsigned short) (cr_data2 & 0x08) << 5) | + ((unsigned short) (cr_data3 & 0x20) << 4) | + ((unsigned short) (sr_data & 0x04) << 8); + + cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[13]; + + /* Vertical blank end */ + VBE = (cr_data & 0xff) | + ((unsigned short) (sr_data & 0x10) << 4); + temp = VBE - ((E - 1) & 511); + B = (temp > 0) ? temp : (temp + 512); + + cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[11]; + + /* Vertical retrace (=sync) end */ + VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); + temp = VRE - ((E + F - 1) & 31); + C = (temp > 0) ? temp : (temp + 32); + + D = B - F - C; + + *upper_margin = D; + *lower_margin = F; + *vsync_len = C; + + if(XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x8000) + *sync &= ~FB_SYNC_VERT_HIGH_ACT; + else + *sync |= FB_SYNC_VERT_HIGH_ACT; + + if(XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x4000) + *sync &= ~FB_SYNC_HOR_HIGH_ACT; + else + *sync |= FB_SYNC_HOR_HIGH_ACT; + + *vmode = FB_VMODE_NONINTERLACED; + if(XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x0080) + *vmode = FB_VMODE_INTERLACED; + else { + j = 0; + while(XGI_Pr->EModeIDTable[j].Ext_ModeID != 0xff) { + if(XGI_Pr->EModeIDTable[j].Ext_ModeID == + XGI_Pr->RefIndex[RefreshRateTableIndex].ModeID) { + if(XGI_Pr->EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) { + *vmode = FB_VMODE_DOUBLE; + } + break; + } + j++; + } + } + +#if 0 /* That's bullshit, only the resolution needs to be shifted */ + if((*vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + *upper_margin <<= 1; + *lower_margin <<= 1; + *vsync_len <<= 1; + } else if((*vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + *upper_margin >>= 1; + *lower_margin >>= 1; + *vsync_len >>= 1; + } +#endif + + return 1; +} + +#endif + + + +void XGIRegInit(VB_DEVICE_INFO *XGI_Pr, ULONG BaseAddr) +{ + XGI_Pr->RelIO = BaseAddr; + XGI_Pr->P3c4 = BaseAddr + 0x14; + XGI_Pr->P3d4 = BaseAddr + 0x24; + XGI_Pr->P3c0 = BaseAddr + 0x10; + XGI_Pr->P3ce = BaseAddr + 0x1e; + XGI_Pr->P3c2 = BaseAddr + 0x12; + XGI_Pr->P3ca = BaseAddr + 0x1a; + XGI_Pr->P3c6 = BaseAddr + 0x16; + XGI_Pr->P3c7 = BaseAddr + 0x17; + XGI_Pr->P3c8 = BaseAddr + 0x18; + XGI_Pr->P3c9 = BaseAddr + 0x19; + XGI_Pr->P3da = BaseAddr + 0x2A; + XGI_Pr->Part1Port = BaseAddr + XGI_CRT2_PORT_04; /* Digital video interface registers (LCD) */ + XGI_Pr->Part2Port = BaseAddr + XGI_CRT2_PORT_10; /* 301 TV Encoder registers */ + XGI_Pr->Part3Port = BaseAddr + XGI_CRT2_PORT_12; /* 301 Macrovision registers */ + XGI_Pr->Part4Port = BaseAddr + XGI_CRT2_PORT_14; /* 301 VGA2 (and LCD) registers */ + XGI_Pr->Part5Port = BaseAddr + XGI_CRT2_PORT_14+2; /* 301 palette address port registers */ + +} + + +void XGIfb_set_reg4(u16 port, unsigned long data) +{ + outl((u32) (data & 0xffffffff), port); +} + +u32 XGIfb_get_reg3(u16 port) +{ + u32 data; + + data = inl(port); + return (data); +} + +/* ------------ Interface for init & mode switching code ------------- */ + +BOOLEAN +XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext, + unsigned long offset, unsigned long set, unsigned long *value) +{ + static struct pci_dev *pdev = NULL; + static unsigned char init = 0, valid_pdev = 0; + + if (!set) + DPRINTK("XGIfb: Get VGA offset 0x%lx\n", offset); + else + DPRINTK("XGIfb: Set offset 0x%lx to 0x%lx\n", offset, *value); + + if (!init) { + init = TRUE; + pdev = pci_get_device(PCI_VENDOR_ID_XG, xgi_video_info.chip_id, pdev); + if (pdev) { + valid_pdev = TRUE; + pci_dev_put(pdev); + } + } + + if (!valid_pdev) { + printk(KERN_DEBUG "XGIfb: Can't find XGI %d VGA device.\n", + xgi_video_info.chip_id); + return FALSE; + } + + if (set == 0) + pci_read_config_dword(pdev, offset, (u32 *)value); + else + pci_write_config_dword(pdev, offset, (u32)(*value)); + + return TRUE; +} + +/*BOOLEAN XGIfb_query_north_bridge_space(PXGI_HW_DEVICE_INFO pXGIhw_ext, + unsigned long offset, unsigned long set, unsigned long *value) +{ + static struct pci_dev *pdev = NULL; + static unsigned char init = 0, valid_pdev = 0; + u16 nbridge_id = 0; + + if (!init) { + init = TRUE; + switch (xgi_video_info.chip) { + case XGI_540: + nbridge_id = PCI_DEVICE_ID_XG_540; + break; + case XGI_630: + nbridge_id = PCI_DEVICE_ID_XG_630; + break; + case XGI_730: + nbridge_id = PCI_DEVICE_ID_XG_730; + break; + case XGI_550: + nbridge_id = PCI_DEVICE_ID_XG_550; + break; + case XGI_650: + nbridge_id = PCI_DEVICE_ID_XG_650; + break; + case XGI_740: + nbridge_id = PCI_DEVICE_ID_XG_740; + break; + default: + nbridge_id = 0; + break; + } + + pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev); + if (pdev) + valid_pdev = TRUE; + } + + if (!valid_pdev) { + printk(KERN_DEBUG "XGIfb: Can't find XGI %d North Bridge device.\n", + nbridge_id); + return FALSE; + } + + if (set == 0) + pci_read_config_dword(pdev, offset, (u32 *)value); + else + pci_write_config_dword(pdev, offset, (u32)(*value)); + + return TRUE; +} +*/ +/* ------------------ Internal helper routines ----------------- */ + +static void XGIfb_search_mode(const char *name) +{ + int i = 0, j = 0, l; + + if(name == NULL) { + printk(KERN_ERR "XGIfb: Internal error, using default mode.\n"); + xgifb_mode_idx = DEFAULT_MODE; + if ((xgi_video_info.chip == XG21) && ((xgi_video_info.disp_state & DISPTYPE_DISP2) == DISPTYPE_LCD)) + { + xgifb_mode_idx = XGIfb_GetXG21DefaultLVDSModeIdx(); + } + return; + } + + + if (!strcmp(name, XGIbios_mode[MODE_INDEX_NONE].name)) { + printk(KERN_ERR "XGIfb: Mode 'none' not supported anymore. Using default.\n"); + xgifb_mode_idx = DEFAULT_MODE; + if ((xgi_video_info.chip == XG21) && ((xgi_video_info.disp_state & DISPTYPE_DISP2) == DISPTYPE_LCD)) + { + xgifb_mode_idx = XGIfb_GetXG21DefaultLVDSModeIdx(); + } + return; + } + + while(XGIbios_mode[i].mode_no != 0) { + l = min(strlen(name), strlen(XGIbios_mode[i].name)); + if (!strncmp(name, XGIbios_mode[i].name, l)) { + xgifb_mode_idx = i; + j = 1; + break; + } + i++; + } + if(!j) printk(KERN_INFO "XGIfb: Invalid mode '%s'\n", name); +} + +static void XGIfb_search_vesamode(unsigned int vesamode) +{ + int i = 0, j = 0; + + if(vesamode == 0) { + + printk(KERN_ERR "XGIfb: Mode 'none' not supported anymore. Using default.\n"); + xgifb_mode_idx = DEFAULT_MODE; + if ((xgi_video_info.chip == XG21) && ((xgi_video_info.disp_state & DISPTYPE_DISP2) == DISPTYPE_LCD)) + { + xgifb_mode_idx = XGIfb_GetXG21DefaultLVDSModeIdx(); + } + return; + } + + vesamode &= 0x1dff; /* Clean VESA mode number from other flags */ + + while(XGIbios_mode[i].mode_no != 0) { + if( (XGIbios_mode[i].vesa_mode_no_1 == vesamode) || + (XGIbios_mode[i].vesa_mode_no_2 == vesamode) ) { + xgifb_mode_idx = i; + j = 1; + break; + } + i++; + } + if(!j) printk(KERN_INFO "XGIfb: Invalid VESA mode 0x%x'\n", vesamode); +} + +int XGIfb_GetXG21LVDSData(void) +{ + u8 tmp; + unsigned char *pData; + int i,j,k; + + inXGIIDXREG(XGISR,0x1e,tmp); + outXGIIDXREG(XGISR, 0x1e, tmp|4); + + pData = xgi_video_info.mmio_vbase+0x20000; + if ((pData[0x0]==0x55) && (pData[0x1]==0xAA) && (pData[0x65] & 0x1)) + { + i = pData[ 0x316 ] | ( pData[ 0x317 ] << 8 ); + j = pData[ i-1 ] ; + if ( j == 0xff ) + { + j = 1; + } + k = 0; + do + { + XGI21_LCDCapList[k].LVDS_Capability = pData[ i ] | ( pData[ i + 1 ] << 8 ); + XGI21_LCDCapList[k].LVDSHT = pData[ i + 2 ] | ( pData[ i + 3 ] << 8 ) ; + XGI21_LCDCapList[k].LVDSVT = pData[ i + 4 ] | ( pData[ i + 5 ] << 8 ); + XGI21_LCDCapList[k].LVDSHDE = pData[ i + 6 ] | ( pData[ i + 7 ] << 8 ); + XGI21_LCDCapList[k].LVDSVDE = pData[ i + 8 ] | ( pData[ i + 9 ] << 8 ); + XGI21_LCDCapList[k].LVDSHFP = pData[ i + 10 ] | ( pData[ i + 11 ] << 8 ); + XGI21_LCDCapList[k].LVDSVFP = pData[ i + 12 ] | ( pData[ i + 13 ] << 8 ); + XGI21_LCDCapList[k].LVDSHSYNC = pData[ i + 14 ] | ( pData[ i + 15 ] << 8 ); + XGI21_LCDCapList[k].LVDSVSYNC = pData[ i + 16 ] | ( pData[ i + 17 ] << 8 ); + XGI21_LCDCapList[k].VCLKData1 = pData[ i + 18 ] ; + XGI21_LCDCapList[k].VCLKData2 = pData[ i + 19 ] ; + XGI21_LCDCapList[k].PSC_S1 = pData[ i + 20 ] ; + XGI21_LCDCapList[k].PSC_S2 = pData[ i + 21 ] ; + XGI21_LCDCapList[k].PSC_S3 = pData[ i + 22 ] ; + XGI21_LCDCapList[k].PSC_S4 = pData[ i + 23 ] ; + XGI21_LCDCapList[k].PSC_S5 = pData[ i + 24 ] ; + i += 25; + j--; + k++; + } while ( (j>0) && ( k < (sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct)) ) ); + return 1; + } + return 0; +} + +int XGIfb_GetXG21DefaultLVDSModeIdx(void) +{ + + int found_mode = 0; + int XGIfb_mode_idx = 0; + + found_mode = 0; + while( (XGIbios_mode[XGIfb_mode_idx].mode_no != 0) && + (XGIbios_mode[XGIfb_mode_idx].xres <= XGI21_LCDCapList[0].LVDSHDE) ) + { + if( (XGIbios_mode[XGIfb_mode_idx].xres == XGI21_LCDCapList[0].LVDSHDE) && + (XGIbios_mode[XGIfb_mode_idx].yres == XGI21_LCDCapList[0].LVDSVDE) && + (XGIbios_mode[XGIfb_mode_idx].bpp == 8)) + { + XGIfb_mode_no = XGIbios_mode[XGIfb_mode_idx].mode_no; + found_mode = 1; + break; + } + XGIfb_mode_idx++; + } + if (!found_mode) + XGIfb_mode_idx = 0; + + return (XGIfb_mode_idx); +} + + +static int XGIfb_validate_mode(int myindex) +{ + u16 xres, yres; + + if (xgi_video_info.chip == XG21) + { + if ((xgi_video_info.disp_state & DISPTYPE_DISP2) == DISPTYPE_LCD) + { + xres = XGI21_LCDCapList[0].LVDSHDE; + yres = XGI21_LCDCapList[0].LVDSVDE; + if(XGIbios_mode[myindex].xres > xres) + return(-1); + if(XGIbios_mode[myindex].yres > yres) + return(-1); + if ((XGIbios_mode[myindex].xres < xres) && (XGIbios_mode[myindex].yres < yres) ) + { + if (XGIbios_mode[myindex].bpp > 8) + return(-1); + } + + } + return(myindex); + + } + + /* FIXME: for now, all is valid on XG27 */ + if (xgi_video_info.chip == XG27) + return(myindex); + + if(!(XGIbios_mode[myindex].chipset & MD_XGI315)) + return(-1); + + switch (xgi_video_info.disp_state & DISPTYPE_DISP2) { + case DISPTYPE_LCD: + switch (XGIhw_ext.ulCRT2LCDType) { + case LCD_640x480: + xres = 640; yres = 480; break; + case LCD_800x600: + xres = 800; yres = 600; break; + case LCD_1024x600: + xres = 1024; yres = 600; break; + case LCD_1024x768: + xres = 1024; yres = 768; break; + case LCD_1152x768: + xres = 1152; yres = 768; break; + case LCD_1280x960: + xres = 1280; yres = 960; break; + case LCD_1280x768: + xres = 1280; yres = 768; break; + case LCD_1280x1024: + xres = 1280; yres = 1024; break; + case LCD_1400x1050: + xres = 1400; yres = 1050; break; + case LCD_1600x1200: + xres = 1600; yres = 1200; break; +// case LCD_320x480: // TW: FSTN +// xres = 320; yres = 480; break; + default: + xres = 0; yres = 0; break; + } + if(XGIbios_mode[myindex].xres > xres) { + return(-1); + } + if(XGIbios_mode[myindex].yres > yres) { + return(-1); + } + if((XGIhw_ext.ulExternalChip == 0x01) || // LVDS + (XGIhw_ext.ulExternalChip == 0x05)) // LVDS+Chrontel + { + switch (XGIbios_mode[myindex].xres) { + case 512: + if(XGIbios_mode[myindex].yres != 512) return -1; + if(XGIhw_ext.ulCRT2LCDType == LCD_1024x600) return -1; + break; + case 640: + if((XGIbios_mode[myindex].yres != 400) && + (XGIbios_mode[myindex].yres != 480)) + return -1; + break; + case 800: + if(XGIbios_mode[myindex].yres != 600) return -1; + break; + case 1024: + if((XGIbios_mode[myindex].yres != 600) && + (XGIbios_mode[myindex].yres != 768)) + return -1; + if((XGIbios_mode[myindex].yres == 600) && + (XGIhw_ext.ulCRT2LCDType != LCD_1024x600)) + return -1; + break; + case 1152: + if((XGIbios_mode[myindex].yres) != 768) return -1; + if(XGIhw_ext.ulCRT2LCDType != LCD_1152x768) return -1; + break; + case 1280: + if((XGIbios_mode[myindex].yres != 768) && + (XGIbios_mode[myindex].yres != 1024)) + return -1; + if((XGIbios_mode[myindex].yres == 768) && + (XGIhw_ext.ulCRT2LCDType != LCD_1280x768)) + return -1; + break; + case 1400: + if(XGIbios_mode[myindex].yres != 1050) return -1; + break; + case 1600: + if(XGIbios_mode[myindex].yres != 1200) return -1; + break; + default: + return -1; + } + } else { + switch (XGIbios_mode[myindex].xres) { + case 512: + if(XGIbios_mode[myindex].yres != 512) return -1; + break; + case 640: + if((XGIbios_mode[myindex].yres != 400) && + (XGIbios_mode[myindex].yres != 480)) + return -1; + break; + case 800: + if(XGIbios_mode[myindex].yres != 600) return -1; + break; + case 1024: + if(XGIbios_mode[myindex].yres != 768) return -1; + break; + case 1280: + if((XGIbios_mode[myindex].yres != 960) && + (XGIbios_mode[myindex].yres != 1024)) + return -1; + if(XGIbios_mode[myindex].yres == 960) { + if(XGIhw_ext.ulCRT2LCDType == LCD_1400x1050) + return -1; + } + break; + case 1400: + if(XGIbios_mode[myindex].yres != 1050) return -1; + break; + case 1600: + if(XGIbios_mode[myindex].yres != 1200) return -1; + break; + default: + return -1; + } + } + break; + case DISPTYPE_TV: + switch (XGIbios_mode[myindex].xres) { + case 512: + case 640: + case 800: + break; + case 720: + if (xgi_video_info.TV_type == TVMODE_NTSC) { + if (XGIbios_mode[myindex].yres != 480) { + return(-1); + } + } else if (xgi_video_info.TV_type == TVMODE_PAL) { + if (XGIbios_mode[myindex].yres != 576) { + return(-1); + } + } + // TW: LVDS/CHRONTEL does not support 720 + if (xgi_video_info.hasVB == HASVB_LVDS_CHRONTEL || + xgi_video_info.hasVB == HASVB_CHRONTEL) { + return(-1); + } + break; + case 1024: + if (xgi_video_info.TV_type == TVMODE_NTSC) { + if(XGIbios_mode[myindex].bpp == 32) { + return(-1); + } + } + // TW: LVDS/CHRONTEL only supports < 800 (1024 on 650/Ch7019) + if (xgi_video_info.hasVB == HASVB_LVDS_CHRONTEL || + xgi_video_info.hasVB == HASVB_CHRONTEL) { + if(xgi_video_info.chip < XGI_315H) { + return(-1); + } + } + break; + default: + return(-1); + } + break; + case DISPTYPE_CRT2: + if(XGIbios_mode[myindex].xres > 1280) return -1; + break; + } + return(myindex); + +} + +static void XGIfb_search_crt2type(const char *name) +{ + int i = 0; + + if(name == NULL) + return; + + while(XGI_crt2type[i].type_no != -1) { + if (!strcmp(name, XGI_crt2type[i].name)) { + XGIfb_crt2type = XGI_crt2type[i].type_no; + XGIfb_tvplug = XGI_crt2type[i].tvplug_no; + break; + } + i++; + } + if(XGIfb_crt2type < 0) + printk(KERN_INFO "XGIfb: Invalid CRT2 type: %s\n", name); +} + +static void XGIfb_search_queuemode(const char *name) +{ + int i = 0; + + if(name == NULL) + return; + + while (XGI_queuemode[i].type_no != -1) { + if (!strcmp(name, XGI_queuemode[i].name)) { + XGIfb_queuemode = XGI_queuemode[i].type_no; + break; + } + i++; + } + if (XGIfb_queuemode < 0) + printk(KERN_INFO "XGIfb: Invalid queuemode type: %s\n", name); +} + +static u8 XGIfb_search_refresh_rate(unsigned int rate) +{ + u16 xres, yres; + int i = 0; + + xres = XGIbios_mode[xgifb_mode_idx].xres; + yres = XGIbios_mode[xgifb_mode_idx].yres; + + XGIfb_rate_idx = 0; + while ((XGIfb_vrate[i].idx != 0) && (XGIfb_vrate[i].xres <= xres)) { + if ((XGIfb_vrate[i].xres == xres) && (XGIfb_vrate[i].yres == yres)) { + if (XGIfb_vrate[i].refresh == rate) { + XGIfb_rate_idx = XGIfb_vrate[i].idx; + break; + } else if (XGIfb_vrate[i].refresh > rate) { + if ((XGIfb_vrate[i].refresh - rate) <= 3) { + DPRINTK("XGIfb: Adjusting rate from %d up to %d\n", + rate, XGIfb_vrate[i].refresh); + XGIfb_rate_idx = XGIfb_vrate[i].idx; + xgi_video_info.refresh_rate = XGIfb_vrate[i].refresh; + } else if (((rate - XGIfb_vrate[i-1].refresh) <= 2) + && (XGIfb_vrate[i].idx != 1)) { + DPRINTK("XGIfb: Adjusting rate from %d down to %d\n", + rate, XGIfb_vrate[i-1].refresh); + XGIfb_rate_idx = XGIfb_vrate[i-1].idx; + xgi_video_info.refresh_rate = XGIfb_vrate[i-1].refresh; + } + break; + } else if((rate - XGIfb_vrate[i].refresh) <= 2) { + DPRINTK("XGIfb: Adjusting rate from %d down to %d\n", + rate, XGIfb_vrate[i].refresh); + XGIfb_rate_idx = XGIfb_vrate[i].idx; + break; + } + } + i++; + } + if (XGIfb_rate_idx > 0) { + return XGIfb_rate_idx; + } else { + printk(KERN_INFO + "XGIfb: Unsupported rate %d for %dx%d\n", rate, xres, yres); + return 0; + } +} + +static void XGIfb_search_tvstd(const char *name) +{ + int i = 0; + + if(name == NULL) + return; + + while (XGI_tvtype[i].type_no != -1) { + if (!strcmp(name, XGI_tvtype[i].name)) { + XGIfb_tvmode = XGI_tvtype[i].type_no; + break; + } + i++; + } +} + +static BOOLEAN XGIfb_bridgeisslave(void) +{ + unsigned char usScratchP1_00; + + if(xgi_video_info.hasVB == HASVB_NONE) return FALSE; + + inXGIIDXREG(XGIPART1,0x00,usScratchP1_00); + if( (usScratchP1_00 & 0x50) == 0x10) { + return TRUE; + } else { + return FALSE; + } +} + +static BOOLEAN XGIfbcheckvretracecrt1(void) +{ + unsigned char temp; + + inXGIIDXREG(XGICR,0x17,temp); + if(!(temp & 0x80)) return FALSE; + + + inXGIIDXREG(XGISR,0x1f,temp); + if(temp & 0xc0) return FALSE; + + + if(inXGIREG(XGIINPSTAT) & 0x08) return TRUE; + else return FALSE; +} + +static BOOLEAN XGIfbcheckvretracecrt2(void) +{ + unsigned char temp; + if(xgi_video_info.hasVB == HASVB_NONE) return FALSE; + inXGIIDXREG(XGIPART1, 0x30, temp); + if(temp & 0x02) return FALSE; + else return TRUE; +} + +static BOOLEAN XGIfb_CheckVBRetrace(void) +{ + if(xgi_video_info.disp_state & DISPTYPE_DISP2) { + if(XGIfb_bridgeisslave()) { + return(XGIfbcheckvretracecrt1()); + } else { + return(XGIfbcheckvretracecrt2()); + } + } + return(XGIfbcheckvretracecrt1()); +} + +/* ----------- FBDev related routines for all series ----------- */ + + +static void XGIfb_bpp_to_var(struct fb_var_screeninfo *var) +{ + switch(var->bits_per_pixel) { + case 8: + var->red.offset = var->green.offset = var->blue.offset = 0; + var->red.length = var->green.length = var->blue.length = 6; + xgi_video_info.video_cmap_len = 256; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + xgi_video_info.video_cmap_len = 16; + break; + case 32: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + xgi_video_info.video_cmap_len = 16; + break; + } +} + + + +static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive, + struct fb_info *info) +{ + + unsigned int htotal = var->left_margin + var->xres + + var->right_margin + var->hsync_len; + unsigned int vtotal = var->upper_margin + var->yres + + var->lower_margin + var->vsync_len; +#if defined(__powerpc__) + u8 sr_data, cr_data; +#endif + unsigned int drate = 0, hrate = 0; + int found_mode = 0; + int old_mode; +// unsigned char reg,reg1; + + DEBUGPRN("Inside do_set_var"); +// printk(KERN_DEBUG "XGIfb:var->yres=%d, var->upper_margin=%d, var->lower_margin=%d, var->vsync_len=%d\n", var->yres,var->upper_margin,var->lower_margin,var->vsync_len); + + info->var.xres_virtual = var->xres_virtual; + info->var.yres_virtual = var->yres_virtual; + info->var.bits_per_pixel = var->bits_per_pixel; + + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) + vtotal <<= 1; + else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) + vtotal <<= 2; + else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + { +// vtotal <<= 1; +// var->yres <<= 1; + } + + if(!htotal || !vtotal) { + DPRINTK("XGIfb: Invalid 'var' information\n"); + return -EINVAL; + } + printk(KERN_DEBUG "XGIfb: var->pixclock=%d, htotal=%d, vtotal=%d\n", + var->pixclock,htotal,vtotal); + + + + if(var->pixclock && htotal && vtotal) { + drate = 1000000000 / var->pixclock; + hrate = (drate * 1000) / htotal; + xgi_video_info.refresh_rate = (unsigned int) (hrate * 2 / vtotal); + } else { + xgi_video_info.refresh_rate = 60; + } + + printk(KERN_DEBUG "XGIfb: Change mode to %dx%dx%d-%dHz\n", + var->xres,var->yres,var->bits_per_pixel,xgi_video_info.refresh_rate); + + old_mode = xgifb_mode_idx; + xgifb_mode_idx = 0; + + while( (XGIbios_mode[xgifb_mode_idx].mode_no != 0) && + (XGIbios_mode[xgifb_mode_idx].xres <= var->xres) ) { + if( (XGIbios_mode[xgifb_mode_idx].xres == var->xres) && + (XGIbios_mode[xgifb_mode_idx].yres == var->yres) && + (XGIbios_mode[xgifb_mode_idx].bpp == var->bits_per_pixel)) { + XGIfb_mode_no = XGIbios_mode[xgifb_mode_idx].mode_no; + found_mode = 1; + break; + } + xgifb_mode_idx++; + } + + if(found_mode) + xgifb_mode_idx = XGIfb_validate_mode(xgifb_mode_idx); + else + xgifb_mode_idx = -1; + + if(xgifb_mode_idx < 0) { + printk(KERN_ERR "XGIfb: Mode %dx%dx%d not supported\n", var->xres, + var->yres, var->bits_per_pixel); + xgifb_mode_idx = old_mode; + return -EINVAL; + } + + if(XGIfb_search_refresh_rate(xgi_video_info.refresh_rate) == 0) { + XGIfb_rate_idx = XGIbios_mode[xgifb_mode_idx].rate_idx; + xgi_video_info.refresh_rate = 60; + } + + if(isactive) { + + + XGIfb_pre_setmode(); + if(XGISetModeNew( &XGIhw_ext, XGIfb_mode_no) == 0) { + printk(KERN_ERR "XGIfb: Setting mode[0x%x] failed\n", XGIfb_mode_no); + return -EINVAL; + } + info->fix.line_length = ((info->var.xres_virtual * info->var.bits_per_pixel)>>6); + + outXGIIDXREG(XGISR,IND_XGI_PASSWORD,XGI_PASSWORD); + + outXGIIDXREG(XGICR,0x13,(info->fix.line_length & 0x00ff)); + outXGIIDXREG(XGISR,0x0E,(info->fix.line_length & 0xff00)>>8); + + XGIfb_post_setmode(); + + DPRINTK("XGIfb: Set new mode: %dx%dx%d-%d \n", + XGIbios_mode[xgifb_mode_idx].xres, + XGIbios_mode[xgifb_mode_idx].yres, + XGIbios_mode[xgifb_mode_idx].bpp, + xgi_video_info.refresh_rate); + + xgi_video_info.video_bpp = XGIbios_mode[xgifb_mode_idx].bpp; + xgi_video_info.video_vwidth = info->var.xres_virtual; + xgi_video_info.video_width = XGIbios_mode[xgifb_mode_idx].xres; + xgi_video_info.video_vheight = info->var.yres_virtual; + xgi_video_info.video_height = XGIbios_mode[xgifb_mode_idx].yres; + xgi_video_info.org_x = xgi_video_info.org_y = 0; + xgi_video_info.video_linelength = info->var.xres_virtual * (xgi_video_info.video_bpp >> 3); + xgi_video_info.accel = 0; + if(XGIfb_accel) { + xgi_video_info.accel = (var->accel_flags & FB_ACCELF_TEXT) ? -1 : 0; + } + switch(xgi_video_info.video_bpp) + { + case 8: + xgi_video_info.DstColor = 0x0000; + xgi_video_info.XGI310_AccelDepth = 0x00000000; + xgi_video_info.video_cmap_len = 256; +#if defined(__powerpc__) + inXGIIDXREG (XGICR, 0x4D, cr_data); + outXGIIDXREG(XGICR, 0x4D, (cr_data & 0xE0)); +#endif + break; + case 16: + xgi_video_info.DstColor = 0x8000; + xgi_video_info.XGI310_AccelDepth = 0x00010000; +#if defined(__powerpc__) + inXGIIDXREG (XGICR, 0x4D, cr_data); + outXGIIDXREG(XGICR, 0x4D, ((cr_data & 0xE0) | 0x0B)); +#endif + xgi_video_info.video_cmap_len = 16; + break; + case 32: + xgi_video_info.DstColor = 0xC000; + xgi_video_info.XGI310_AccelDepth = 0x00020000; + xgi_video_info.video_cmap_len = 16; +#if defined(__powerpc__) + inXGIIDXREG (XGICR, 0x4D, cr_data); + outXGIIDXREG(XGICR, 0x4D, ((cr_data & 0xE0) | 0x15)); +#endif + break; + default: + xgi_video_info.video_cmap_len = 16; + printk(KERN_ERR "XGIfb: Unsupported depth %d", xgi_video_info.video_bpp); + xgi_video_info.accel = 0; + break; + } + } + XGIfb_bpp_to_var(var); /*update ARGB info*/ + DEBUGPRN("End of do_set_var"); + + dumpVGAReg(); + return 0; +} + +#ifdef XGIFB_PAN +static int XGIfb_pan_var(struct fb_var_screeninfo *var) +{ + unsigned int base; + +// printk("Inside pan_var"); + + if (var->xoffset > (var->xres_virtual - var->xres)) { +// printk( "Pan: xo: %d xv %d xr %d\n", +// var->xoffset, var->xres_virtual, var->xres); + return -EINVAL; + } + if(var->yoffset > (var->yres_virtual - var->yres)) { +// printk( "Pan: yo: %d yv %d yr %d\n", +// var->yoffset, var->yres_virtual, var->yres); + return -EINVAL; + } + base = var->yoffset * var->xres_virtual + var->xoffset; + + /* calculate base bpp dep. */ + switch(var->bits_per_pixel) { + case 16: + base >>= 1; + break; + case 32: + break; + case 8: + default: + base >>= 2; + break; + } + + outXGIIDXREG(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD); + + outXGIIDXREG(XGICR, 0x0D, base & 0xFF); + outXGIIDXREG(XGICR, 0x0C, (base >> 8) & 0xFF); + outXGIIDXREG(XGISR, 0x0D, (base >> 16) & 0xFF); + outXGIIDXREG(XGISR, 0x37, (base >> 24) & 0x03); + setXGIIDXREG(XGISR, 0x37, 0xDF, (base >> 21) & 0x04); + + if(xgi_video_info.disp_state & DISPTYPE_DISP2) { + orXGIIDXREG(XGIPART1, XGIfb_CRT2_write_enable, 0x01); + outXGIIDXREG(XGIPART1, 0x06, (base & 0xFF)); + outXGIIDXREG(XGIPART1, 0x05, ((base >> 8) & 0xFF)); + outXGIIDXREG(XGIPART1, 0x04, ((base >> 16) & 0xFF)); + setXGIIDXREG(XGIPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7); + } +// printk("End of pan_var"); + return 0; +} +#endif + + +void XGI_dispinfo(struct ap_data *rec) +{ + rec->minfo.bpp = xgi_video_info.video_bpp; + rec->minfo.xres = xgi_video_info.video_width; + rec->minfo.yres = xgi_video_info.video_height; + rec->minfo.v_xres = xgi_video_info.video_vwidth; + rec->minfo.v_yres = xgi_video_info.video_vheight; + rec->minfo.org_x = xgi_video_info.org_x; + rec->minfo.org_y = xgi_video_info.org_y; + rec->minfo.vrate = xgi_video_info.refresh_rate; + rec->iobase = xgi_video_info.vga_base - 0x30; + rec->mem_size = xgi_video_info.video_size; + rec->disp_state = xgi_video_info.disp_state; + rec->version = (VER_MAJOR << 24) | (VER_MINOR << 16) | VER_LEVEL; + rec->hasVB = xgi_video_info.hasVB; + rec->TV_type = xgi_video_info.TV_type; + rec->TV_plug = xgi_video_info.TV_plug; + rec->chip = xgi_video_info.chip; +} + + + + +static int XGIfb_open(struct fb_info *info, int user) +{ + return 0; +} + +static int XGIfb_release(struct fb_info *info, int user) +{ + return 0; +} + +static int XGIfb_get_cmap_len(const struct fb_var_screeninfo *var) +{ + int rc = 16; + + switch(var->bits_per_pixel) { + case 8: + rc = 256; + break; + case 16: + rc = 16; + break; + case 32: + rc = 16; + break; + } + return rc; +} + +static int XGIfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + if (regno >= XGIfb_get_cmap_len(&info->var)) + return 1; + + switch (info->var.bits_per_pixel) { + case 8: + outXGIREG(XGIDACA, regno); + outXGIREG(XGIDACD, (red >> 10)); + outXGIREG(XGIDACD, (green >> 10)); + outXGIREG(XGIDACD, (blue >> 10)); + if (xgi_video_info.disp_state & DISPTYPE_DISP2) { + outXGIREG(XGIDAC2A, regno); + outXGIREG(XGIDAC2D, (red >> 8)); + outXGIREG(XGIDAC2D, (green >> 8)); + outXGIREG(XGIDAC2D, (blue >> 8)); + } + break; + case 16: + ((u32 *)(info->pseudo_palette))[regno] = + ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + break; + case 32: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *) (info->pseudo_palette))[regno] = + (red << 16) | (green << 8) | (blue); + break; + } + return 0; +} + +static int XGIfb_set_par(struct fb_info *info) +{ + int err; + +// printk("XGIfb: inside set_par\n"); + if((err = XGIfb_do_set_var(&info->var, 1, info))) + return err; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + XGIfb_get_fix(&info->fix, info->currcon, info); +#else + XGIfb_get_fix(&info->fix, -1, info); +#endif +// printk("XGIfb:end of set_par\n"); + return 0; +} + +static int XGIfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + unsigned int htotal = + var->left_margin + var->xres + var->right_margin + + var->hsync_len; + unsigned int vtotal = 0; + unsigned int drate = 0, hrate = 0; + int found_mode = 0; + int refresh_rate, search_idx; + + DEBUGPRN("Inside check_var"); + + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + vtotal = var->upper_margin + var->yres + var->lower_margin + + var->vsync_len; + vtotal <<= 1; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + vtotal = var->upper_margin + var->yres + var->lower_margin + + var->vsync_len; + vtotal <<= 2; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + vtotal = var->upper_margin + (var->yres/2) + var->lower_margin + + var->vsync_len; + } else vtotal = var->upper_margin + var->yres + var->lower_margin + + var->vsync_len; + + if(!(htotal) || !(vtotal)) { + XGIFAIL("XGIfb: no valid timing data"); + } + + + if(var->pixclock && htotal && vtotal) { + drate = 1000000000 / var->pixclock; + hrate = (drate * 1000) / htotal; + xgi_video_info.refresh_rate = (unsigned int) (hrate * 2 / vtotal); + printk(KERN_DEBUG \ + "%s: pixclock = %d ,htotal=%d, vtotal=%d\n" \ + "%s: drate=%d, hrate=%d, refresh_rate=%d\n", + __func__,var->pixclock, htotal, vtotal, + __func__, drate, hrate, xgi_video_info.refresh_rate); + } else { + xgi_video_info.refresh_rate = 60; + } + +/* + if((var->pixclock) && (htotal)) { + drate = 1E12 / var->pixclock; + hrate = drate / htotal; + refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5); + } else refresh_rate = 60; +*/ + /* TW: Calculation wrong for 1024x600 - force it to 60Hz */ + if((var->xres == 1024) && (var->yres == 600)) refresh_rate = 60; + + search_idx = 0; + while((XGIbios_mode[search_idx].mode_no != 0) && + (XGIbios_mode[search_idx].xres <= var->xres) ) { + if((XGIbios_mode[search_idx].xres == var->xres) && + (XGIbios_mode[search_idx].yres == var->yres) && + (XGIbios_mode[search_idx].bpp == var->bits_per_pixel)) { + if(XGIfb_validate_mode(search_idx) > 0) { + found_mode = 1; + break; + } + } + search_idx++; + } + + if(!found_mode) { + + printk(KERN_ERR "XGIfb: %dx%dx%d is no valid mode\n", + var->xres, var->yres, var->bits_per_pixel); + + search_idx = 0; + while(XGIbios_mode[search_idx].mode_no != 0) { + + if( (var->xres <= XGIbios_mode[search_idx].xres) && + (var->yres <= XGIbios_mode[search_idx].yres) && + (var->bits_per_pixel == XGIbios_mode[search_idx].bpp) ) { + if(XGIfb_validate_mode(search_idx) > 0) { + found_mode = 1; + break; + } + } + search_idx++; + } + if(found_mode) { + var->xres = XGIbios_mode[search_idx].xres; + var->yres = XGIbios_mode[search_idx].yres; + printk(KERN_DEBUG "XGIfb: Adapted to mode %dx%dx%d\n", + var->xres, var->yres, var->bits_per_pixel); + + } else { + printk(KERN_ERR "XGIfb: Failed to find similar mode to %dx%dx%d\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + } + + /* TW: TODO: Check the refresh rate */ + + /* Adapt RGB settings */ + XGIfb_bpp_to_var(var); + + /* Sanity check for offsets */ + if (var->xoffset < 0) + var->xoffset = 0; + if (var->yoffset < 0) + var->yoffset = 0; + + + if(!XGIfb_ypan) { + if(var->xres != var->xres_virtual) + var->xres_virtual = var->xres; + if(var->yres != var->yres_virtual) + var->yres_virtual = var->yres; + }/* else { + // TW: Now patch yres_virtual if we use panning + // May I do this? + var->yres_virtual = xgi_video_info.heapstart / (var->xres * (var->bits_per_pixel >> 3)); + if(var->yres_virtual <= var->yres) { + // TW: Paranoia check + var->yres_virtual = var->yres; + } + }*/ + + /* Truncate offsets to maximum if too high */ + if (var->xoffset > var->xres_virtual - var->xres) + var->xoffset = var->xres_virtual - var->xres - 1; + + if (var->yoffset > var->yres_virtual - var->yres) + var->yoffset = var->yres_virtual - var->yres - 1; + + /* Set everything else to 0 */ + var->red.msb_right = + var->green.msb_right = + var->blue.msb_right = + var->transp.offset = var->transp.length = var->transp.msb_right = 0; + + DEBUGPRN("end of check_var"); + return 0; +} + +#ifdef XGIFB_PAN +static int XGIfb_pan_display( struct fb_var_screeninfo *var, + struct fb_info* info) +{ + int err; + +// printk("\nInside pan_display:"); + + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; + if (var->yoffset > (var->yres_virtual - var->yres)) + return -EINVAL; + + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset < 0 + || var->yoffset >= info->var.yres_virtual + || var->xoffset) return -EINVAL; + } else { + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + } + + if((err = XGIfb_pan_var(var)) < 0) return err; + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + +// printk(" End of pan_display"); + return 0; +} +#endif + +#if 0 +static int XGIfb_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + unsigned long start; + unsigned long off; + u32 len, mmio_off; + + DEBUGPRN("inside mmap"); + if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; + + off = vma->vm_pgoff << PAGE_SHIFT; + + start = (unsigned long) xgi_video_info.video_base; + len = PAGE_ALIGN((start & ~PAGE_MASK) + xgi_video_info.video_size); + start &= PAGE_MASK; +#if 0 + if (off >= len) { + off -= len; +#endif + /* By Jake Page: Treat mmap request with offset beyond heapstart + * as request for mapping the mmio area + */ + #if 1 + mmio_off = PAGE_ALIGN((start & ~PAGE_MASK) + xgi_video_info.heapstart); + if(off >= mmio_off) { + off -= mmio_off; + if(info->var.accel_flags) return -EINVAL; + + start = (unsigned long) xgi_video_info.mmio_base; + len = PAGE_ALIGN((start & ~PAGE_MASK) + XGIfb_mmio_size); + } + start &= PAGE_MASK; + #endif + if((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; + + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + vma->vm_flags |= VM_IO; /* by Jake Page; is that really needed? */ + +#if defined(__i386__) || defined(__x86_64__) + if (boot_cpu_data.x86 > 3) + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; +#endif + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + DEBUGPRN("end of mmap"); + return 0; +} +#endif +static int XGIfb_blank(int blank, struct fb_info *info) +{ + u8 reg; + + inXGIIDXREG(XGICR, 0x17, reg); + + if(blank > 0) + reg &= 0x7f; + else + reg |= 0x80; + + outXGIIDXREG(XGICR, 0x17, reg); + outXGIIDXREG(XGISR, 0x00, 0x01); /* Synchronous Reset */ + outXGIIDXREG(XGISR, 0x00, 0x03); /* End Reset */ + return(0); +} + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +static int XGIfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +#else +static int XGIfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info) +#endif + +{ + DEBUGPRN("inside ioctl"); + switch (cmd) { + case FBIO_ALLOC: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + XGI_malloc((struct XGI_memreq *) arg); + break; + case FBIO_FREE: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + XGI_free(*(unsigned long *) arg); + break; + case FBIOGET_HWCINFO: + { + unsigned long *hwc_offset = (unsigned long *) arg; + + if (XGIfb_caps & HW_CURSOR_CAP) + *hwc_offset = XGIfb_hwcursor_vbase - + (unsigned long) xgi_video_info.video_vbase; + else + *hwc_offset = 0; + + break; + } + case FBIOPUT_MODEINFO: + { + struct mode_info *x = (struct mode_info *)arg; + + xgi_video_info.video_bpp = x->bpp; + xgi_video_info.video_width = x->xres; + xgi_video_info.video_height = x->yres; + xgi_video_info.video_vwidth = x->v_xres; + xgi_video_info.video_vheight = x->v_yres; + xgi_video_info.org_x = x->org_x; + xgi_video_info.org_y = x->org_y; + xgi_video_info.refresh_rate = x->vrate; + xgi_video_info.video_linelength = xgi_video_info.video_vwidth * (xgi_video_info.video_bpp >> 3); + switch(xgi_video_info.video_bpp) { + case 8: + xgi_video_info.DstColor = 0x0000; + xgi_video_info.XGI310_AccelDepth = 0x00000000; + xgi_video_info.video_cmap_len = 256; + break; + case 16: + xgi_video_info.DstColor = 0x8000; + xgi_video_info.XGI310_AccelDepth = 0x00010000; + xgi_video_info.video_cmap_len = 16; + break; + case 32: + xgi_video_info.DstColor = 0xC000; + xgi_video_info.XGI310_AccelDepth = 0x00020000; + xgi_video_info.video_cmap_len = 16; + break; + default: + xgi_video_info.video_cmap_len = 16; + printk(KERN_ERR "XGIfb: Unsupported accel depth %d", xgi_video_info.video_bpp); + xgi_video_info.accel = 0; + break; + } + + break; + } + case FBIOGET_DISPINFO: + XGI_dispinfo((struct ap_data *)arg); + break; + case XGIFB_GET_INFO: /* TW: New for communication with X driver */ + { + XGIfb_info *x = (XGIfb_info *)arg; + + //x->XGIfb_id = XGIFB_ID; + x->XGIfb_version = VER_MAJOR; + x->XGIfb_revision = VER_MINOR; + x->XGIfb_patchlevel = VER_LEVEL; + x->chip_id = xgi_video_info.chip_id; + x->memory = xgi_video_info.video_size / 1024; + x->heapstart = xgi_video_info.heapstart / 1024; + x->fbvidmode = XGIfb_mode_no; + x->XGIfb_caps = XGIfb_caps; + x->XGIfb_tqlen = 512; /* yet unused */ + x->XGIfb_pcibus = xgi_video_info.pcibus; + x->XGIfb_pcislot = xgi_video_info.pcislot; + x->XGIfb_pcifunc = xgi_video_info.pcifunc; + x->XGIfb_lcdpdc = XGIfb_detectedpdc; + x->XGIfb_lcda = XGIfb_detectedlcda; + break; + } + case XGIFB_GET_VBRSTATUS: + { + unsigned long *vbrstatus = (unsigned long *) arg; + if(XGIfb_CheckVBRetrace()) *vbrstatus = 1; + else *vbrstatus = 0; + } + default: + return -EINVAL; + } + DEBUGPRN("end of ioctl"); + return 0; + +} + + + +/* ----------- FBDev related routines for all series ---------- */ + +static int XGIfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + DEBUGPRN("inside get_fix"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + + strcpy(fix->id, myid); + + fix->smem_start = xgi_video_info.video_base; + + fix->smem_len = xgi_video_info.video_size; + + +/* if((!XGIfb_mem) || (XGIfb_mem > (xgi_video_info.video_size/1024))) { + if (xgi_video_info.video_size > 0x1000000) { + fix->smem_len = 0xD00000; + } else if (xgi_video_info.video_size > 0x800000) + fix->smem_len = 0x800000; + else + fix->smem_len = 0x400000; + } else + fix->smem_len = XGIfb_mem * 1024; +*/ + fix->type = video_type; + fix->type_aux = 0; + if(xgi_video_info.video_bpp == 8) + fix->visual = FB_VISUAL_PSEUDOCOLOR; + else + fix->visual = FB_VISUAL_DIRECTCOLOR; + fix->xpanstep = 0; +#ifdef XGIFB_PAN + if(XGIfb_ypan) fix->ypanstep = 1; +#endif + fix->ywrapstep = 0; + fix->line_length = xgi_video_info.video_linelength; + fix->mmio_start = xgi_video_info.mmio_base; + fix->mmio_len = XGIfb_mmio_size; + if(xgi_video_info.chip >= XG40) + fix->accel = FB_ACCEL_XGI_XABRE; + else + fix->accel = FB_ACCEL_XGI_GLAMOUR_2; + + + DEBUGPRN("end of get_fix"); + return 0; +} + + +static struct fb_ops XGIfb_ops = { + .owner = THIS_MODULE, + .fb_open = XGIfb_open, + .fb_release = XGIfb_release, + .fb_check_var = XGIfb_check_var, + .fb_set_par = XGIfb_set_par, + .fb_setcolreg = XGIfb_setcolreg, +#ifdef XGIFB_PAN + .fb_pan_display = XGIfb_pan_display, +#endif + .fb_blank = XGIfb_blank, + .fb_fillrect = fbcon_XGI_fillrect, + .fb_copyarea = fbcon_XGI_copyarea, + .fb_imageblit = cfb_imageblit, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) + .fb_cursor = soft_cursor, +#endif + .fb_sync = fbcon_XGI_sync, + .fb_ioctl = XGIfb_ioctl, +// .fb_mmap = XGIfb_mmap, +}; + +/* ---------------- Chip generation dependent routines ---------------- */ + + +/* for XGI 315/550/650/740/330 */ + +static int XGIfb_get_dram_size(void) +{ + + u8 ChannelNum,tmp; + u8 reg = 0; + + /* xorg driver sets 32MB * 1 channel */ + if (xgi_video_info.chip == XG27) + outXGIIDXREG(XGISR, IND_XGI_DRAM_SIZE, 0x51); + + inXGIIDXREG(XGISR, IND_XGI_DRAM_SIZE, reg); + switch ((reg & XGI_DRAM_SIZE_MASK) >> 4) { + case XGI_DRAM_SIZE_1MB: + xgi_video_info.video_size = 0x100000; + break; + case XGI_DRAM_SIZE_2MB: + xgi_video_info.video_size = 0x200000; + break; + case XGI_DRAM_SIZE_4MB: + xgi_video_info.video_size = 0x400000; + break; + case XGI_DRAM_SIZE_8MB: + xgi_video_info.video_size = 0x800000; + break; + case XGI_DRAM_SIZE_16MB: + xgi_video_info.video_size = 0x1000000; + break; + case XGI_DRAM_SIZE_32MB: + xgi_video_info.video_size = 0x2000000; + break; + case XGI_DRAM_SIZE_64MB: + xgi_video_info.video_size = 0x4000000; + break; + case XGI_DRAM_SIZE_128MB: + xgi_video_info.video_size = 0x8000000; + break; + case XGI_DRAM_SIZE_256MB: + xgi_video_info.video_size = 0x10000000; + break; + default: + return -1; + } + + tmp = (reg & 0x0c) >> 2; + switch(xgi_video_info.chip) + { + case XG20: + case XG21: + case XG27: + ChannelNum = 1; + break; + + case XG42: + if(reg & 0x04) + ChannelNum = 2; + else + ChannelNum = 1; + break; + + case XG45: + if(tmp == 1) + ChannelNum = 2; + else + if(tmp == 2) + ChannelNum = 3; + else + if(tmp == 3) + ChannelNum = 4; + else + ChannelNum = 1; + break; + + case XG40: + default: + if(tmp == 2) + ChannelNum = 2; + else + if(tmp == 3) + ChannelNum = 3; + else + ChannelNum = 1; + break; + } + + + xgi_video_info.video_size = xgi_video_info.video_size * ChannelNum; + //PLiad fixed for benchmarking and fb set + //xgi_video_info.video_size = 0x200000;//1024x768x16 + //xgi_video_info.video_size = 0x1000000;//benchmark + + printk("XGIfb: SR14=%x DramSzie %x ChannelNum %x\n",reg,xgi_video_info.video_size ,ChannelNum ); + return 0; + +} + +static void XGIfb_detect_VB(void) +{ + u8 cr32, temp=0; + + xgi_video_info.TV_plug = xgi_video_info.TV_type = 0; + + switch(xgi_video_info.hasVB) { + case HASVB_LVDS_CHRONTEL: + case HASVB_CHRONTEL: + break; + case HASVB_301: + case HASVB_302: +// XGI_Sense30x(); //Yi-Lin TV Sense? + break; + } + + inXGIIDXREG(XGICR, IND_XGI_SCRATCH_REG_CR32, cr32); + + if ((cr32 & XGI_CRT1) && !XGIfb_crt1off) + XGIfb_crt1off = 0; + else { + if (cr32 & 0x5F) + XGIfb_crt1off = 1; + else + XGIfb_crt1off = 0; + } + + if (XGIfb_crt2type != -1) + /* TW: Override with option */ + xgi_video_info.disp_state = XGIfb_crt2type; + else if (cr32 & XGI_VB_TV) + xgi_video_info.disp_state = DISPTYPE_TV; + else if (cr32 & XGI_VB_LCD) + xgi_video_info.disp_state = DISPTYPE_LCD; + else if (cr32 & XGI_VB_CRT2) + xgi_video_info.disp_state = DISPTYPE_CRT2; + else + xgi_video_info.disp_state = 0; + + if(XGIfb_tvplug != -1) + /* PR/TW: Override with option */ + xgi_video_info.TV_plug = XGIfb_tvplug; + else if (cr32 & XGI_VB_HIVISION) { + xgi_video_info.TV_type = TVMODE_HIVISION; + xgi_video_info.TV_plug = TVPLUG_SVIDEO; + } + else if (cr32 & XGI_VB_SVIDEO) + xgi_video_info.TV_plug = TVPLUG_SVIDEO; + else if (cr32 & XGI_VB_COMPOSITE) + xgi_video_info.TV_plug = TVPLUG_COMPOSITE; + else if (cr32 & XGI_VB_SCART) + xgi_video_info.TV_plug = TVPLUG_SCART; + + if(xgi_video_info.TV_type == 0) { + /* TW: PAL/NTSC changed for 650 */ + if((xgi_video_info.chip <= XGI_315PRO) || (xgi_video_info.chip >= XGI_330)) { + + inXGIIDXREG(XGICR, 0x38, temp); + if(temp & 0x10) + xgi_video_info.TV_type = TVMODE_PAL; + else + xgi_video_info.TV_type = TVMODE_NTSC; + + } else { + + inXGIIDXREG(XGICR, 0x79, temp); + if(temp & 0x20) + xgi_video_info.TV_type = TVMODE_PAL; + else + xgi_video_info.TV_type = TVMODE_NTSC; + } + } + + /* TW: Copy forceCRT1 option to CRT1off if option is given */ + if (XGIfb_forcecrt1 != -1) { + if (XGIfb_forcecrt1) XGIfb_crt1off = 0; + else XGIfb_crt1off = 1; + } +} + +static void XGIfb_get_VB_type(void) +{ + u8 reg; + + if (!XGIfb_has_VB()) { + inXGIIDXREG(XGICR, IND_XGI_SCRATCH_REG_CR37, reg); + switch ((reg & XGI_EXTERNAL_CHIP_MASK) >> 1) { + case XGI310_EXTERNAL_CHIP_LVDS: + xgi_video_info.hasVB = HASVB_LVDS; + break; + case XGI310_EXTERNAL_CHIP_LVDS_CHRONTEL: + xgi_video_info.hasVB = HASVB_LVDS_CHRONTEL; + break; + default: + break; + } + } +} + + +static int XGIfb_has_VB(void) +{ + u8 vb_chipid; + + inXGIIDXREG(XGIPART4, 0x00, vb_chipid); + switch (vb_chipid) { + case 0x01: + xgi_video_info.hasVB = HASVB_301; + break; + case 0x02: + xgi_video_info.hasVB = HASVB_302; + break; + default: + xgi_video_info.hasVB = HASVB_NONE; + return FALSE; + } + return TRUE; +} + + + +/* ------------------ Sensing routines ------------------ */ + +/* TW: Determine and detect attached devices on XGI30x */ +int +XGIDoSense(int tempbl, int tempbh, int tempcl, int tempch) +{ + int temp,i; + + outXGIIDXREG(XGIPART4,0x11,tempbl); + temp = tempbh | tempcl; + setXGIIDXREG(XGIPART4,0x10,0xe0,temp); + for(i=0; i<10; i++) XGI_LongWait(&XGI_Pr); + tempch &= 0x7f; + inXGIIDXREG(XGIPART4,0x03,temp); + temp ^= 0x0e; + temp &= tempch; + return(temp); +} + +void +XGI_Sense30x(void) +{ + u8 backupP4_0d; + u8 testsvhs_tempbl, testsvhs_tempbh; + u8 testsvhs_tempcl, testsvhs_tempch; + u8 testcvbs_tempbl, testcvbs_tempbh; + u8 testcvbs_tempcl, testcvbs_tempch; + u8 testvga2_tempbl, testvga2_tempbh; + u8 testvga2_tempcl, testvga2_tempch; + int myflag, result; + + inXGIIDXREG(XGIPART4,0x0d,backupP4_0d); + outXGIIDXREG(XGIPART4,0x0d,(backupP4_0d | 0x04)); + + + + testvga2_tempbh = 0x00; testvga2_tempbl = 0xd1; + testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9; + testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3; + if((XGIhw_ext.ujVBChipID != VB_CHIP_301) && + (XGIhw_ext.ujVBChipID != VB_CHIP_302)) { + testvga2_tempbh = 0x01; testvga2_tempbl = 0x90; + testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b; + testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74; + if(XGIhw_ext.ujVBChipID == VB_CHIP_301LV || + XGIhw_ext.ujVBChipID == VB_CHIP_302LV) { + testvga2_tempbh = 0x00; testvga2_tempbl = 0x00; + testsvhs_tempbh = 0x02; testsvhs_tempbl = 0x00; + testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x00; + } + } + if(XGIhw_ext.ujVBChipID != VB_CHIP_301LV && + XGIhw_ext.ujVBChipID != VB_CHIP_302LV) { + inXGIIDXREG(XGIPART4,0x01,myflag); + if(myflag & 0x04) { + testvga2_tempbh = 0x00; testvga2_tempbl = 0xfd; + testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xdd; + testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee; + } + } + if((XGIhw_ext.ujVBChipID == VB_CHIP_301LV) || + (XGIhw_ext.ujVBChipID == VB_CHIP_302LV) ) { + testvga2_tempbh = 0x00; testvga2_tempbl = 0x00; + testvga2_tempch = 0x00; testvga2_tempcl = 0x00; + testsvhs_tempch = 0x04; testsvhs_tempcl = 0x08; + testcvbs_tempch = 0x08; testcvbs_tempcl = 0x08; + } else { + testvga2_tempch = 0x0e; testvga2_tempcl = 0x08; + testsvhs_tempch = 0x06; testsvhs_tempcl = 0x04; + testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04; + } + + + if(testvga2_tempch || testvga2_tempcl || testvga2_tempbh || testvga2_tempbl) { + result = XGIDoSense(testvga2_tempbl, testvga2_tempbh, + testvga2_tempcl, testvga2_tempch); + if(result) { + printk(KERN_INFO "XGIfb: Detected secondary VGA connection\n"); + orXGIIDXREG(XGICR, 0x32, 0x10); + } + } + + result = XGIDoSense(testsvhs_tempbl, testsvhs_tempbh, + testsvhs_tempcl, testsvhs_tempch); + if(result) { + printk(KERN_INFO "XGIfb: Detected TV connected to SVHS output\n"); + /* TW: So we can be sure that there IS a SVHS output */ + xgi_video_info.TV_plug = TVPLUG_SVIDEO; + orXGIIDXREG(XGICR, 0x32, 0x02); + } + + if(!result) { + result = XGIDoSense(testcvbs_tempbl, testcvbs_tempbh, + testcvbs_tempcl, testcvbs_tempch); + if(result) { + printk(KERN_INFO "XGIfb: Detected TV connected to CVBS output\n"); + /* TW: So we can be sure that there IS a CVBS output */ + xgi_video_info.TV_plug = TVPLUG_COMPOSITE; + orXGIIDXREG(XGICR, 0x32, 0x01); + } + } + XGIDoSense(0, 0, 0, 0); + + outXGIIDXREG(XGIPART4,0x0d,backupP4_0d); +} + + + +/* ------------------------ Heap routines -------------------------- */ + +static int XGIfb_heap_init(void) +{ + XGI_OH *poh; + u8 temp=0; + + int agp_enabled = 1; + u32 agp_size; + unsigned long *cmdq_baseport = 0; + unsigned long *read_port = 0; + unsigned long *write_port = 0; + XGI_CMDTYPE cmd_type; +#ifndef AGPOFF + struct agp_kern_info *agp_info; + struct agp_memory *agp; + u32 agp_phys; +#endif + +/* TW: The heap start is either set manually using the "mem" parameter, or + * defaults as follows: + * -) If more than 16MB videoRAM available, let our heap start at 12MB. + * -) If more than 8MB videoRAM available, let our heap start at 8MB. + * -) If 4MB or less is available, let it start at 4MB. + * This is for avoiding a clash with X driver which uses the beginning + * of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem + * in XF86Config-4. + * The heap start can also be specified by parameter "mem" when starting the XGIfb + * driver. XGIfb mem=1024 lets heap starts at 1MB, etc. + */ + if ((!XGIfb_mem) || (XGIfb_mem > (xgi_video_info.video_size/1024))) { + if (xgi_video_info.video_size > 0x1000000) { + xgi_video_info.heapstart = 0xD00000; + } else if (xgi_video_info.video_size > 0x800000) { + xgi_video_info.heapstart = 0x800000; + } else { + xgi_video_info.heapstart = 0x400000; + } + } else { + xgi_video_info.heapstart = XGIfb_mem * 1024; + } + XGIfb_heap_start = + (unsigned long) (xgi_video_info.video_vbase + xgi_video_info.heapstart); + printk(KERN_INFO "XGIfb: Memory heap starting at %dK\n", + (int)(xgi_video_info.heapstart / 1024)); + + XGIfb_heap_end = (unsigned long) xgi_video_info.video_vbase + xgi_video_info.video_size; + XGIfb_heap_size = XGIfb_heap_end - XGIfb_heap_start; + + + + /* TW: Now initialize the 310 series' command queue mode. + * On 310/325, there are three queue modes available which + * are chosen by setting bits 7:5 in SR26: + * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep + * track of the queue, the FIFO, command parsing and so + * on. This is the one comparable to the 300 series. + * 2. VRAM queue mode (bit 6, 0x40). In this case, one will + * have to do queue management himself. Register 0x85c4 will + * hold the location of the next free queue slot, 0x85c8 + * is the "queue read pointer" whose way of working is + * unknown to me. Anyway, this mode would require a + * translation of the MMIO commands to some kind of + * accelerator assembly and writing these commands + * to the memory location pointed to by 0x85c4. + * We will not use this, as nobody knows how this + * "assembly" works, and as it would require a complete + * re-write of the accelerator code. + * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the + * queue in AGP memory space. + * + * SR26 bit 4 is called "Bypass H/W queue". + * SR26 bit 1 is called "Enable Command Queue Auto Correction" + * SR26 bit 0 resets the queue + * Size of queue memory is encoded in bits 3:2 like this: + * 00 (0x00) 512K + * 01 (0x04) 1M + * 10 (0x08) 2M + * 11 (0x0C) 4M + * The queue location is to be written to 0x85C0. + * + */ + cmdq_baseport = (unsigned long *)(xgi_video_info.mmio_vbase + MMIO_QUEUE_PHYBASE); + write_port = (unsigned long *)(xgi_video_info.mmio_vbase + MMIO_QUEUE_WRITEPORT); + read_port = (unsigned long *)(xgi_video_info.mmio_vbase + MMIO_QUEUE_READPORT); + + DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port); + + agp_size = COMMAND_QUEUE_AREA_SIZE; + +#ifndef AGPOFF + if (XGIfb_queuemode == AGP_CMD_QUEUE) { + agp_info = vmalloc(sizeof(*agp_info)); + memset((void*)agp_info, 0x00, sizeof(*agp_info)); + agp_copy_info(agp_info); + + agp_backend_acquire(); + + agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE, + AGP_NORMAL_MEMORY); + if (agp == NULL) { + DPRINTK("XGIfb: Allocating AGP buffer failed.\n"); + agp_enabled = 0; + } else { + if (agp_bind_memory(agp, agp->pg_start) != 0) { + DPRINTK("XGIfb: AGP: Failed to bind memory\n"); + /* TODO: Free AGP memory here */ + agp_enabled = 0; + } else { + agp_enable(0); + } + } + } +#else + agp_enabled = 0; +#endif + + /* TW: Now select the queue mode */ + + if ((agp_enabled) && (XGIfb_queuemode == AGP_CMD_QUEUE)) { + cmd_type = AGP_CMD_QUEUE; + printk(KERN_INFO "XGIfb: Using AGP queue mode\n"); +/* } else if (XGIfb_heap_size >= COMMAND_QUEUE_AREA_SIZE) */ + } else if (XGIfb_queuemode == VM_CMD_QUEUE) { + cmd_type = VM_CMD_QUEUE; + printk(KERN_INFO "XGIfb: Using VRAM queue mode\n"); + } else { + printk(KERN_INFO "XGIfb: Using MMIO queue mode\n"); + cmd_type = MMIO_CMD; + } + + switch (agp_size) { + case 0x80000: + temp = XGI_CMD_QUEUE_SIZE_512k; + break; + case 0x100000: + temp = XGI_CMD_QUEUE_SIZE_1M; + break; + case 0x200000: + temp = XGI_CMD_QUEUE_SIZE_2M; + break; + case 0x400000: + temp = XGI_CMD_QUEUE_SIZE_4M; + break; + } + + switch (cmd_type) { + case AGP_CMD_QUEUE: +#ifndef AGPOFF + DPRINTK("XGIfb: AGP buffer base = 0x%lx, offset = 0x%x, size = %dK\n", + agp_info->aper_base, agp->physical, agp_size/1024); + + agp_phys = agp_info->aper_base + agp->physical; + + outXGIIDXREG(XGICR, IND_XGI_AGP_IO_PAD, 0); + outXGIIDXREG(XGICR, IND_XGI_AGP_IO_PAD, XGI_AGP_2X); + + outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD); + + outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, XGI_CMD_QUEUE_RESET); + + *write_port = *read_port; + + temp |= XGI_AGP_CMDQUEUE_ENABLE; + outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, temp); + + *cmdq_baseport = agp_phys; + + XGIfb_caps |= AGP_CMD_QUEUE_CAP; +#endif + break; + + case VM_CMD_QUEUE: + XGIfb_heap_end -= COMMAND_QUEUE_AREA_SIZE; + XGIfb_heap_size -= COMMAND_QUEUE_AREA_SIZE; + + outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD); + + outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, XGI_CMD_QUEUE_RESET); + + *write_port = *read_port; + + temp |= XGI_VRAM_CMDQUEUE_ENABLE; + outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, temp); + + *cmdq_baseport = xgi_video_info.video_size - COMMAND_QUEUE_AREA_SIZE; + + XGIfb_caps |= VM_CMD_QUEUE_CAP; + + DPRINTK("XGIfb: VM Cmd Queue offset = 0x%lx, size is %dK\n", + *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024); + break; + + default: /* MMIO */ + +// printk("%s:%d - I'm here\n", __FUNCTION__, __LINE__); + /* TW: This previously only wrote XGI_MMIO_CMD_ENABLE + * to IND_XGI_CMDQUEUE_SET. I doubt that this is + * enough. Reserve memory in any way. + */ +// FIXME XGIfb_heap_end -= COMMAND_QUEUE_AREA_SIZE; +// FIXME XGIfb_heap_size -= COMMAND_QUEUE_AREA_SIZE; +// FIXME +// FIXME outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD); +// FIXME outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, XGI_CMD_QUEUE_RESET); +// FIXME +// FIXME *write_port = *read_port; +// FIXME +// FIXME /* TW: Set Auto_Correction bit */ +// FIXME temp |= (XGI_MMIO_CMD_ENABLE | XGI_CMD_AUTO_CORR); +// FIXME // FIXME outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, temp); +// FIXME +// FIXME *cmdq_baseport = xgi_video_info.video_size - COMMAND_QUEUE_AREA_SIZE; +// FIXME +// FIXME XGIfb_caps |= MMIO_CMD_QUEUE_CAP; +// FIXME +// FIXME DPRINTK("XGIfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n", +// FIXME *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024); + break; + } + + + + + /* TW: Now reserve memory for the HWCursor. It is always located at the very + top of the videoRAM, right below the TB memory area (if used). */ + if (XGIfb_heap_size >= XGIfb_hwcursor_size) { + XGIfb_heap_end -= XGIfb_hwcursor_size; + XGIfb_heap_size -= XGIfb_hwcursor_size; + XGIfb_hwcursor_vbase = XGIfb_heap_end; + + XGIfb_caps |= HW_CURSOR_CAP; + + DPRINTK("XGIfb: Hardware Cursor start at 0x%lx, size is %dK\n", + XGIfb_heap_end, XGIfb_hwcursor_size/1024); + } + + XGIfb_heap.poha_chain = NULL; + XGIfb_heap.poh_freelist = NULL; + + poh = XGIfb_poh_new_node(); + + if(poh == NULL) return 1; + + poh->poh_next = &XGIfb_heap.oh_free; + poh->poh_prev = &XGIfb_heap.oh_free; + poh->size = XGIfb_heap_end - XGIfb_heap_start + 1; + poh->offset = XGIfb_heap_start - (unsigned long) xgi_video_info.video_vbase; + + DPRINTK("XGIfb: Heap start:0x%p, end:0x%p, len=%dk\n", + (char *) XGIfb_heap_start, (char *) XGIfb_heap_end, + (unsigned int) poh->size / 1024); + + DPRINTK("XGIfb: First Node offset:0x%x, size:%dk\n", + (unsigned int) poh->offset, (unsigned int) poh->size / 1024); + + XGIfb_heap.oh_free.poh_next = poh; + XGIfb_heap.oh_free.poh_prev = poh; + XGIfb_heap.oh_free.size = 0; + XGIfb_heap.max_freesize = poh->size; + + XGIfb_heap.oh_used.poh_next = &XGIfb_heap.oh_used; + XGIfb_heap.oh_used.poh_prev = &XGIfb_heap.oh_used; + XGIfb_heap.oh_used.size = SENTINEL; + + return 0; +} + +static XGI_OH *XGIfb_poh_new_node(void) +{ + int i; + unsigned long cOhs; + XGI_OHALLOC *poha; + XGI_OH *poh; + + if (XGIfb_heap.poh_freelist == NULL) { + poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL); + if(!poha) return NULL; + + poha->poha_next = XGIfb_heap.poha_chain; + XGIfb_heap.poha_chain = poha; + + cOhs = (OH_ALLOC_SIZE - sizeof(XGI_OHALLOC)) / sizeof(XGI_OH) + 1; + + poh = &poha->aoh[0]; + for (i = cOhs - 1; i != 0; i--) { + poh->poh_next = poh + 1; + poh = poh + 1; + } + + poh->poh_next = NULL; + XGIfb_heap.poh_freelist = &poha->aoh[0]; + } + + poh = XGIfb_heap.poh_freelist; + XGIfb_heap.poh_freelist = poh->poh_next; + + return (poh); +} + +static XGI_OH *XGIfb_poh_allocate(unsigned long size) +{ + XGI_OH *pohThis; + XGI_OH *pohRoot; + int bAllocated = 0; + + if (size > XGIfb_heap.max_freesize) { + DPRINTK("XGIfb: Can't allocate %dk size on offscreen\n", + (unsigned int) size / 1024); + return (NULL); + } + + pohThis = XGIfb_heap.oh_free.poh_next; + + while (pohThis != &XGIfb_heap.oh_free) { + if (size <= pohThis->size) { + bAllocated = 1; + break; + } + pohThis = pohThis->poh_next; + } + + if (!bAllocated) { + DPRINTK("XGIfb: Can't allocate %dk size on offscreen\n", + (unsigned int) size / 1024); + return (NULL); + } + + if (size == pohThis->size) { + pohRoot = pohThis; + XGIfb_delete_node(pohThis); + } else { + pohRoot = XGIfb_poh_new_node(); + + if (pohRoot == NULL) { + return (NULL); + } + + pohRoot->offset = pohThis->offset; + pohRoot->size = size; + + pohThis->offset += size; + pohThis->size -= size; + } + + XGIfb_heap.max_freesize -= size; + + pohThis = &XGIfb_heap.oh_used; + XGIfb_insert_node(pohThis, pohRoot); + + return (pohRoot); +} + +static void XGIfb_delete_node(XGI_OH *poh) +{ + XGI_OH *poh_prev; + XGI_OH *poh_next; + + poh_prev = poh->poh_prev; + poh_next = poh->poh_next; + + poh_prev->poh_next = poh_next; + poh_next->poh_prev = poh_prev; + +} + +static void XGIfb_insert_node(XGI_OH *pohList, XGI_OH *poh) +{ + XGI_OH *pohTemp; + + pohTemp = pohList->poh_next; + + pohList->poh_next = poh; + pohTemp->poh_prev = poh; + + poh->poh_prev = pohList; + poh->poh_next = pohTemp; +} + +static XGI_OH *XGIfb_poh_free(unsigned long base) +{ + XGI_OH *pohThis; + XGI_OH *poh_freed; + XGI_OH *poh_prev; + XGI_OH *poh_next; + unsigned long ulUpper; + unsigned long ulLower; + int foundNode = 0; + + poh_freed = XGIfb_heap.oh_used.poh_next; + + while(poh_freed != &XGIfb_heap.oh_used) { + if(poh_freed->offset == base) { + foundNode = 1; + break; + } + + poh_freed = poh_freed->poh_next; + } + + if (!foundNode) return (NULL); + + XGIfb_heap.max_freesize += poh_freed->size; + + poh_prev = poh_next = NULL; + ulUpper = poh_freed->offset + poh_freed->size; + ulLower = poh_freed->offset; + + pohThis = XGIfb_heap.oh_free.poh_next; + + while (pohThis != &XGIfb_heap.oh_free) { + if (pohThis->offset == ulUpper) { + poh_next = pohThis; + } + else if ((pohThis->offset + pohThis->size) == + ulLower) { + poh_prev = pohThis; + } + pohThis = pohThis->poh_next; + } + + XGIfb_delete_node(poh_freed); + + if (poh_prev && poh_next) { + poh_prev->size += (poh_freed->size + poh_next->size); + XGIfb_delete_node(poh_next); + XGIfb_free_node(poh_freed); + XGIfb_free_node(poh_next); + return (poh_prev); + } + + if (poh_prev) { + poh_prev->size += poh_freed->size; + XGIfb_free_node(poh_freed); + return (poh_prev); + } + + if (poh_next) { + poh_next->size += poh_freed->size; + poh_next->offset = poh_freed->offset; + XGIfb_free_node(poh_freed); + return (poh_next); + } + + XGIfb_insert_node(&XGIfb_heap.oh_free, poh_freed); + + return (poh_freed); +} + +static void XGIfb_free_node(XGI_OH *poh) +{ + if(poh == NULL) return; + + poh->poh_next = XGIfb_heap.poh_freelist; + XGIfb_heap.poh_freelist = poh; + +} + +void XGI_malloc(struct XGI_memreq *req) +{ + XGI_OH *poh; + + poh = XGIfb_poh_allocate(req->size); + + if(poh == NULL) { + req->offset = 0; + req->size = 0; + DPRINTK("XGIfb: Video RAM allocation failed\n"); + } else { + DPRINTK("XGIfb: Video RAM allocation succeeded: 0x%p\n", + (char *) (poh->offset + (unsigned long) xgi_video_info.video_vbase)); + + req->offset = poh->offset; + req->size = poh->size; + } + +} + +void XGI_free(unsigned long base) +{ + XGI_OH *poh; + + poh = XGIfb_poh_free(base); + + if(poh == NULL) { + DPRINTK("XGIfb: XGIfb_poh_free() failed at base 0x%x\n", + (unsigned int) base); + } +} + +/* --------------------- SetMode routines ------------------------- */ + +static void XGIfb_pre_setmode(void) +{ + u8 cr30 = 0, cr31 = 0; + + inXGIIDXREG(XGICR, 0x31, cr31); + cr31 &= ~0x60; + + switch (xgi_video_info.disp_state & DISPTYPE_DISP2) { + case DISPTYPE_CRT2: + cr30 = (XGI_VB_OUTPUT_CRT2 | XGI_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= XGI_DRIVER_MODE; + break; + case DISPTYPE_LCD: + cr30 = (XGI_VB_OUTPUT_LCD | XGI_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= XGI_DRIVER_MODE; + break; + case DISPTYPE_TV: + if (xgi_video_info.TV_type == TVMODE_HIVISION) + cr30 = (XGI_VB_OUTPUT_HIVISION | XGI_SIMULTANEOUS_VIEW_ENABLE); + else if (xgi_video_info.TV_plug == TVPLUG_SVIDEO) + cr30 = (XGI_VB_OUTPUT_SVIDEO | XGI_SIMULTANEOUS_VIEW_ENABLE); + else if (xgi_video_info.TV_plug == TVPLUG_COMPOSITE) + cr30 = (XGI_VB_OUTPUT_COMPOSITE | XGI_SIMULTANEOUS_VIEW_ENABLE); + else if (xgi_video_info.TV_plug == TVPLUG_SCART) + cr30 = (XGI_VB_OUTPUT_SCART | XGI_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= XGI_DRIVER_MODE; + + if (XGIfb_tvmode == 1 || xgi_video_info.TV_type == TVMODE_PAL) + cr31 |= 0x01; + else + cr31 &= ~0x01; + break; + default: /* disable CRT2 */ + cr30 = 0x00; + cr31 |= (XGI_DRIVER_MODE | XGI_VB_OUTPUT_DISABLE); + } + + outXGIIDXREG(XGICR, IND_XGI_SCRATCH_REG_CR30, cr30); + outXGIIDXREG(XGICR, IND_XGI_SCRATCH_REG_CR31, cr31); + outXGIIDXREG(XGICR, IND_XGI_SCRATCH_REG_CR33, (XGIfb_rate_idx & 0x0F)); + + if(xgi_video_info.accel) XGIfb_syncaccel(); + + +} + +static void XGIfb_post_setmode(void) +{ + u8 reg; + BOOLEAN doit = TRUE; +#if 0 /* TW: Wrong: Is not in MMIO space, but in RAM */ + /* Backup mode number to MMIO space */ + if(xgi_video_info.mmio_vbase) { + *(volatile u8 *)(((u8*)xgi_video_info.mmio_vbase) + 0x449) = (unsigned char)XGIfb_mode_no; + } +#endif +/* outXGIIDXREG(XGISR,IND_XGI_PASSWORD,XGI_PASSWORD); + outXGIIDXREG(XGICR,0x13,0x00); + setXGIIDXREG(XGISR,0x0E,0xF0,0x01); +*test**/ + if (xgi_video_info.video_bpp == 8) { + /* TW: We can't switch off CRT1 on LVDS/Chrontel in 8bpp Modes */ + if ((xgi_video_info.hasVB == HASVB_LVDS) || (xgi_video_info.hasVB == HASVB_LVDS_CHRONTEL)) { + doit = FALSE; + } + /* TW: We can't switch off CRT1 on 301B-DH in 8bpp Modes if using LCD */ + if (xgi_video_info.disp_state & DISPTYPE_LCD) { + doit = FALSE; + } + } + + /* TW: We can't switch off CRT1 if bridge is in slave mode */ + if(xgi_video_info.hasVB != HASVB_NONE) { + inXGIIDXREG(XGIPART1, 0x00, reg); + + + if((reg & 0x50) == 0x10) { + doit = FALSE; + } + + } else XGIfb_crt1off = 0; + + inXGIIDXREG(XGICR, 0x17, reg); + if((XGIfb_crt1off) && (doit)) + reg &= ~0x80; + else + reg |= 0x80; + outXGIIDXREG(XGICR, 0x17, reg); + + andXGIIDXREG(XGISR, IND_XGI_RAMDAC_CONTROL, ~0x04); + + if((xgi_video_info.disp_state & DISPTYPE_TV) && (xgi_video_info.hasVB == HASVB_301)) { + + inXGIIDXREG(XGIPART4, 0x01, reg); + + if(reg < 0xB0) { /* Set filter for XGI301 */ + + switch (xgi_video_info.video_width) { + case 320: + filter_tb = (xgi_video_info.TV_type == TVMODE_NTSC) ? 4 : 12; + break; + case 640: + filter_tb = (xgi_video_info.TV_type == TVMODE_NTSC) ? 5 : 13; + break; + case 720: + filter_tb = (xgi_video_info.TV_type == TVMODE_NTSC) ? 6 : 14; + break; + case 800: + filter_tb = (xgi_video_info.TV_type == TVMODE_NTSC) ? 7 : 15; + break; + default: + filter = -1; + break; + } + + orXGIIDXREG(XGIPART1, XGIfb_CRT2_write_enable, 0x01); + + if(xgi_video_info.TV_type == TVMODE_NTSC) { + + andXGIIDXREG(XGIPART2, 0x3a, 0x1f); + + if (xgi_video_info.TV_plug == TVPLUG_SVIDEO) { + + andXGIIDXREG(XGIPART2, 0x30, 0xdf); + + } else if (xgi_video_info.TV_plug == TVPLUG_COMPOSITE) { + + orXGIIDXREG(XGIPART2, 0x30, 0x20); + + switch (xgi_video_info.video_width) { + case 640: + outXGIIDXREG(XGIPART2, 0x35, 0xEB); + outXGIIDXREG(XGIPART2, 0x36, 0x04); + outXGIIDXREG(XGIPART2, 0x37, 0x25); + outXGIIDXREG(XGIPART2, 0x38, 0x18); + break; + case 720: + outXGIIDXREG(XGIPART2, 0x35, 0xEE); + outXGIIDXREG(XGIPART2, 0x36, 0x0C); + outXGIIDXREG(XGIPART2, 0x37, 0x22); + outXGIIDXREG(XGIPART2, 0x38, 0x08); + break; + case 800: + outXGIIDXREG(XGIPART2, 0x35, 0xEB); + outXGIIDXREG(XGIPART2, 0x36, 0x15); + outXGIIDXREG(XGIPART2, 0x37, 0x25); + outXGIIDXREG(XGIPART2, 0x38, 0xF6); + break; + } + } + + } else if(xgi_video_info.TV_type == TVMODE_PAL) { + + andXGIIDXREG(XGIPART2, 0x3A, 0x1F); + + if (xgi_video_info.TV_plug == TVPLUG_SVIDEO) { + + andXGIIDXREG(XGIPART2, 0x30, 0xDF); + + } else if (xgi_video_info.TV_plug == TVPLUG_COMPOSITE) { + + orXGIIDXREG(XGIPART2, 0x30, 0x20); + + switch (xgi_video_info.video_width) { + case 640: + outXGIIDXREG(XGIPART2, 0x35, 0xF1); + outXGIIDXREG(XGIPART2, 0x36, 0xF7); + outXGIIDXREG(XGIPART2, 0x37, 0x1F); + outXGIIDXREG(XGIPART2, 0x38, 0x32); + break; + case 720: + outXGIIDXREG(XGIPART2, 0x35, 0xF3); + outXGIIDXREG(XGIPART2, 0x36, 0x00); + outXGIIDXREG(XGIPART2, 0x37, 0x1D); + outXGIIDXREG(XGIPART2, 0x38, 0x20); + break; + case 800: + outXGIIDXREG(XGIPART2, 0x35, 0xFC); + outXGIIDXREG(XGIPART2, 0x36, 0xFB); + outXGIIDXREG(XGIPART2, 0x37, 0x14); + outXGIIDXREG(XGIPART2, 0x38, 0x2A); + break; + } + } + } + + if ((filter >= 0) && (filter <=7)) { + DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter, + XGI_TV_filter[filter_tb].filter[filter][0], + XGI_TV_filter[filter_tb].filter[filter][1], + XGI_TV_filter[filter_tb].filter[filter][2], + XGI_TV_filter[filter_tb].filter[filter][3] + ); + outXGIIDXREG(XGIPART2, 0x35, (XGI_TV_filter[filter_tb].filter[filter][0])); + outXGIIDXREG(XGIPART2, 0x36, (XGI_TV_filter[filter_tb].filter[filter][1])); + outXGIIDXREG(XGIPART2, 0x37, (XGI_TV_filter[filter_tb].filter[filter][2])); + outXGIIDXREG(XGIPART2, 0x38, (XGI_TV_filter[filter_tb].filter[filter][3])); + } + + } + + } + +} + +#ifndef MODULE +XGIINITSTATIC int __init XGIfb_setup(char *options) +{ + char *this_opt; + + + + xgi_video_info.refresh_rate = 0; + + printk(KERN_INFO "XGIfb: Options %s\n", options); + + if (!options || !*options) + return 0; + + while((this_opt = strsep(&options, ",")) != NULL) { + + if (!*this_opt) continue; + + if (!strncmp(this_opt, "mode:", 5)) { + XGIfb_search_mode(this_opt + 5); + } else if (!strncmp(this_opt, "vesa:", 5)) { + XGIfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0)); + } else if (!strncmp(this_opt, "mode:", 5)) { + XGIfb_search_mode(this_opt + 5); + } else if (!strncmp(this_opt, "vesa:", 5)) { + XGIfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0)); + } else if (!strncmp(this_opt, "vrate:", 6)) { + xgi_video_info.refresh_rate = simple_strtoul(this_opt + 6, NULL, 0); + } else if (!strncmp(this_opt, "rate:", 5)) { + xgi_video_info.refresh_rate = simple_strtoul(this_opt + 5, NULL, 0); + } else if (!strncmp(this_opt, "off", 3)) { + XGIfb_off = 1; + } else if (!strncmp(this_opt, "crt1off", 7)) { + XGIfb_crt1off = 1; + } else if (!strncmp(this_opt, "filter:", 7)) { + filter = (int)simple_strtoul(this_opt + 7, NULL, 0); + } else if (!strncmp(this_opt, "forcecrt2type:", 14)) { + XGIfb_search_crt2type(this_opt + 14); + } else if (!strncmp(this_opt, "forcecrt1:", 10)) { + XGIfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0); + } else if (!strncmp(this_opt, "tvmode:",7)) { + XGIfb_search_tvstd(this_opt + 7); + } else if (!strncmp(this_opt, "tvstandard:",11)) { + XGIfb_search_tvstd(this_opt + 7); + } else if (!strncmp(this_opt, "mem:",4)) { + XGIfb_mem = simple_strtoul(this_opt + 4, NULL, 0); + } else if (!strncmp(this_opt, "dstn", 4)) { + enable_dstn = 1; + /* TW: DSTN overrules forcecrt2type */ + XGIfb_crt2type = DISPTYPE_LCD; + } else if (!strncmp(this_opt, "queuemode:", 10)) { + XGIfb_search_queuemode(this_opt + 10); + } else if (!strncmp(this_opt, "pdc:", 4)) { + XGIfb_pdc = simple_strtoul(this_opt + 4, NULL, 0); + if(XGIfb_pdc & ~0x3c) { + printk(KERN_INFO "XGIfb: Illegal pdc parameter\n"); + XGIfb_pdc = 0; + } + } else if (!strncmp(this_opt, "noaccel", 7)) { + XGIfb_accel = 0; + } else if (!strncmp(this_opt, "noypan", 6)) { + XGIfb_ypan = 0; + } else if (!strncmp(this_opt, "userom:", 7)) { + XGIfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0); +// } else if (!strncmp(this_opt, "useoem:", 7)) { +// XGIfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0); + } else { + XGIfb_search_mode(this_opt); +// printk(KERN_INFO "XGIfb: Invalid option %s\n", this_opt); + } + + /* TW: Acceleration only with MMIO mode */ + if((XGIfb_queuemode != -1) && (XGIfb_queuemode != MMIO_CMD)) { + XGIfb_ypan = 0; + XGIfb_accel = 0; + } + /* TW: Panning only with acceleration */ + if(XGIfb_accel == 0) XGIfb_ypan = 0; + + } + printk("\nxgifb: outa xgifb_setup 3450"); + return 0; +} +#endif + +static unsigned char VBIOS_BUF[65535]; + +unsigned char* attempt_map_rom(struct pci_dev *dev,void *copy_address) +{ + u32 rom_size = 0; + u32 rom_address = 0; + int j; + + /* Get the size of the expansion rom */ + pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0xFFFFFFFF); + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &rom_size); + if ((rom_size & 0x01) == 0) + { + printk("No ROM\n"); + return NULL; + } + + rom_size &= 0xFFFFF800; + rom_size = (~rom_size)+1; + + rom_address = pci_resource_start(dev, 0); + if (rom_address == 0 || rom_address == 0xFFFFFFF0) + { + printk("No suitable rom address found\n"); return NULL; + } + + printk("ROM Size is %dK, Address is %x\n", rom_size/1024, rom_address); + + /* Map ROM */ + pci_write_config_dword(dev, PCI_ROM_ADDRESS, rom_address | PCI_ROM_ADDRESS_ENABLE); + + /* memcpy(copy_address, rom_address, rom_size); */ + { + unsigned char *virt_addr = ioremap(rom_address, 0x8000000); + + unsigned char *from = (unsigned char *)virt_addr; + unsigned char *to = (unsigned char *)copy_address; + for (j=0; j<65536 /*rom_size*/; j++) *to++ = *from++; + } + + pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); + + printk("Copy is done\n"); + + return copy_address; +} + +int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + u16 reg16; + u8 reg, reg1; + u8 CR48,CR38; + if (XGIfb_off) + return -ENXIO; + + XGIfb_registered = 0; + + memset(&XGIhw_ext, 0, sizeof(HW_DEVICE_EXTENSION)); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3)) + fb_info = framebuffer_alloc(sizeof(struct fb_info), &pdev->dev); + if(!fb_info) return -ENOMEM; +#else + XGI_fb_info = kmalloc( sizeof(struct fb_info), GFP_KERNEL); + if(!XGI_fb_info) return -ENOMEM; + memset(XGI_fb_info, 0, sizeof(struct fb_info)); +#endif + + xgi_video_info.chip_id = pdev->device; + pci_read_config_byte(pdev, PCI_REVISION_ID,&xgi_video_info.revision_id); + pci_read_config_word(pdev, PCI_COMMAND, ®16); + XGIhw_ext.jChipRevision = xgi_video_info.revision_id; + XGIvga_enabled = reg16 & 0x01; + + xgi_video_info.pcibus = pdev->bus->number; + xgi_video_info.pcislot = PCI_SLOT(pdev->devfn); + xgi_video_info.pcifunc = PCI_FUNC(pdev->devfn); + xgi_video_info.subsysvendor = pdev->subsystem_vendor; + xgi_video_info.subsysdevice = pdev->subsystem_device; + + xgi_video_info.video_base = pci_resource_start(pdev, 0); + xgi_video_info.mmio_base = pci_resource_start(pdev, 1); + XGIfb_mmio_size = pci_resource_len(pdev, 1); + xgi_video_info.vga_base = pci_resource_start(pdev, 2) + 0x30; + XGIhw_ext.pjIOAddress = (PUCHAR)xgi_video_info.vga_base; + //XGI_Pr.RelIO = ioremap(pci_resource_start(pdev, 2), 128) + 0x30; + printk("XGIfb: Relocate IO address: %lx [%08lx] \n", (unsigned long)pci_resource_start(pdev, 2), XGI_Pr.RelIO); + + if (pci_enable_device(pdev)) + return -EIO; + + XGIRegInit(&XGI_Pr, (ULONG)XGIhw_ext.pjIOAddress); + + outXGIIDXREG(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD); + inXGIIDXREG(XGISR, IND_XGI_PASSWORD, reg1); + + if(reg1 != 0xa1) /*I/O error */ + { + printk("\nXGIfb: I/O error!!!"); + return -EIO; + } + + switch (xgi_video_info.chip_id) { + case PCI_DEVICE_ID_XG_20: + orXGIIDXREG(XGICR, Index_CR_GPIO_Reg3, GPIOG_EN); + inXGIIDXREG(XGICR, Index_CR_GPIO_Reg1, CR48); + if (CR48&GPIOG_READ) + xgi_video_info.chip = XG21; + else + xgi_video_info.chip = XG20; + XGIfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; + XGIfb_CRT2_write_enable = IND_XGI_CRT2_WRITE_ENABLE_315; + break; + case PCI_DEVICE_ID_XG_40: + xgi_video_info.chip = XG40; + XGIfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; + XGIfb_CRT2_write_enable = IND_XGI_CRT2_WRITE_ENABLE_315; + break; + case PCI_DEVICE_ID_XG_41: + xgi_video_info.chip = XG41; + XGIfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; + XGIfb_CRT2_write_enable = IND_XGI_CRT2_WRITE_ENABLE_315; + break; + case PCI_DEVICE_ID_XG_42: + xgi_video_info.chip = XG42; + XGIfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; + XGIfb_CRT2_write_enable = IND_XGI_CRT2_WRITE_ENABLE_315; + break; + case PCI_DEVICE_ID_XG_27: + xgi_video_info.chip = XG27; + XGIfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; + XGIfb_CRT2_write_enable = IND_XGI_CRT2_WRITE_ENABLE_315; + break; + default: + return -ENODEV; + } + + printk("XGIfb:chipid = %x\n",xgi_video_info.chip); + XGIhw_ext.jChipType = xgi_video_info.chip; + + switch (xgi_video_info.chip) { + case XG40: + case XG41: + case XG42: + case XG45: + case XG20: + case XG21: + case XG27: + XGIhw_ext.bIntegratedMMEnabled = TRUE; + break; + + default: + break; + } + + + XGIhw_ext.pDevice = NULL; + if ((xgi_video_info.chip == XG21) || (XGIfb_userom)) + { + XGIhw_ext.pjVirtualRomBase = attempt_map_rom(pdev, VBIOS_BUF); + + if(XGIhw_ext.pjVirtualRomBase) + printk(KERN_INFO "XGIfb: Video ROM found and mapped to %p\n",XGIhw_ext.pjVirtualRomBase); + else + printk(KERN_INFO "XGIfb: Video ROM not found\n"); + } else { + XGIhw_ext.pjVirtualRomBase = NULL; + printk(KERN_INFO "XGIfb: Video ROM usage disabled\n"); + } + XGIhw_ext.pjCustomizedROMImage = NULL; + XGIhw_ext.bSkipDramSizing = 0; + XGIhw_ext.pQueryVGAConfigSpace = &XGIfb_query_VGA_config_space; +// XGIhw_ext.pQueryNorthBridgeSpace = &XGIfb_query_north_bridge_space; + strcpy(XGIhw_ext.szVBIOSVer, "0.84"); + + + XGIhw_ext.pSR = vmalloc(sizeof(XGI_DSReg) * SR_BUFFER_SIZE); + if (XGIhw_ext.pSR == NULL) + { + printk(KERN_ERR "XGIfb: Fatal error: Allocating SRReg space failed.\n"); + return -ENODEV; + } + XGIhw_ext.pSR[0].jIdx = XGIhw_ext.pSR[0].jVal = 0xFF; + + XGIhw_ext.pCR = vmalloc(sizeof(XGI_DSReg) * CR_BUFFER_SIZE); + if (XGIhw_ext.pCR == NULL) + { + vfree(XGIhw_ext.pSR); + printk(KERN_ERR "XGIfb: Fatal error: Allocating CRReg space failed.\n"); + return -ENODEV; + } + XGIhw_ext.pCR[0].jIdx = XGIhw_ext.pCR[0].jVal = 0xFF; + + + + + if (!XGIvga_enabled) + { + /* Mapping Max FB Size for 315 Init */ + XGIhw_ext.pjVideoMemoryAddress = ioremap(xgi_video_info.video_base, 0x10000000); + if((xgifb_mode_idx < 0) || ((XGIbios_mode[xgifb_mode_idx].mode_no) != 0xFF)) + { +#ifdef LINUXBIOS + printk("XGIfb: XGIInit() ..."); + /* XGIInitNewt for LINUXBIOS only */ + if(XGIInitNew(&XGIhw_ext)) + { + printk("OK\n"); + } + else + { + printk("Fail\n"); + } +#endif + + outXGIIDXREG(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD); + + + } + } +#ifdef LINUXBIOS + else + { + XGIhw_ext.pjVideoMemoryAddress = ioremap(xgi_video_info.video_base, 0x10000000); + if((xgifb_mode_idx < 0) || ((XGIbios_mode[xgifb_mode_idx].mode_no) != 0xFF)) + { + + outXGIIDXREG(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD); + + // yilin Because no VBIOS DRAM Sizing, Dram size will error. + // Set SR13 ,14 temporarily for UDtech + outXGIIDXREG(XGISR, 0x13, 0x45); + outXGIIDXREG(XGISR, 0x14, 0x51); + + + } + } +#endif + if (XGIfb_get_dram_size()) + { + vfree(XGIhw_ext.pSR); + vfree(XGIhw_ext.pCR); + printk(KERN_INFO "XGIfb: Fatal error: Unable to determine RAM size.\n"); + return -ENODEV; + } + + + + if((xgifb_mode_idx < 0) || ((XGIbios_mode[xgifb_mode_idx].mode_no) != 0xFF)) + { + /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */ + orXGIIDXREG(XGISR, IND_XGI_PCI_ADDRESS_SET, (XGI_PCI_ADDR_ENABLE | XGI_MEM_MAP_IO_ENABLE)); + /* Enable 2D accelerator engine */ + orXGIIDXREG(XGISR, IND_XGI_MODULE_ENABLE, XGI_ENABLE_2D); + } + + XGIhw_ext.ulVideoMemorySize = xgi_video_info.video_size; + + if (!request_mem_region(xgi_video_info.video_base, xgi_video_info.video_size, "XGIfb FB")) + { printk("unable request memory size %x",xgi_video_info.video_size); + printk(KERN_ERR "XGIfb: Fatal error: Unable to reserve frame buffer memory\n"); + printk(KERN_ERR "XGIfb: Is there another framebuffer driver active?\n"); + vfree(XGIhw_ext.pSR); + vfree(XGIhw_ext.pCR); + return -ENODEV; + } + + if (!request_mem_region(xgi_video_info.mmio_base, XGIfb_mmio_size, "XGIfb MMIO")) + { + printk(KERN_ERR "XGIfb: Fatal error: Unable to reserve MMIO region\n"); + release_mem_region(xgi_video_info.video_base, xgi_video_info.video_size); + vfree(XGIhw_ext.pSR); + vfree(XGIhw_ext.pCR); + return -ENODEV; + } + + xgi_video_info.video_vbase = XGIhw_ext.pjVideoMemoryAddress = + ioremap(xgi_video_info.video_base, xgi_video_info.video_size); + xgi_video_info.mmio_vbase = ioremap(xgi_video_info.mmio_base, XGIfb_mmio_size); + + printk(KERN_INFO "XGIfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + xgi_video_info.video_base, xgi_video_info.video_vbase,xgi_video_info.video_size / 1024); + + printk(KERN_INFO "XGIfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n", + xgi_video_info.mmio_base, xgi_video_info.mmio_vbase,XGIfb_mmio_size / 1024); + printk("XGIfb: XGIInitNew() ..."); + if(XGIInitNew(&XGIhw_ext)) + { + printk("OK\n"); + } + else + { + printk("Fail\n"); + } + + if(XGIfb_heap_init()) + { + printk(KERN_WARNING "XGIfb: Failed to initialize offscreen memory heap\n"); + } + + + xgi_video_info.mtrr = (unsigned int) 0; + + if((xgifb_mode_idx < 0) || ((XGIbios_mode[xgifb_mode_idx].mode_no) != 0xFF)) + { + xgi_video_info.hasVB = HASVB_NONE; + if((xgi_video_info.chip == XG20)||(xgi_video_info.chip == XG27)) + xgi_video_info.hasVB = HASVB_NONE; + else if(xgi_video_info.chip == XG21) { + inXGIIDXREG(XGICR,0x38,CR38); + if ((CR38&0xE0) == 0xC0) { + xgi_video_info.disp_state = DISPTYPE_LCD; + if (!XGIfb_GetXG21LVDSData()) { + int m; + for (m=0; m < sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct); m++) { + if ((XGI21_LCDCapList[m].LVDSHDE == XGIbios_mode[xgifb_mode_idx].xres) && + (XGI21_LCDCapList[m].LVDSVDE == XGIbios_mode[xgifb_mode_idx].yres)) { + XGINew_SetReg1( XGI_Pr.P3d4 , 0x36, m) ; + } + } + } + } + else if ((CR38&0xE0) == 0x60) + xgi_video_info.hasVB = HASVB_CHRONTEL ; + else + xgi_video_info.hasVB = HASVB_NONE; + } + else + XGIfb_get_VB_type(); + + XGIhw_ext.ujVBChipID = VB_CHIP_UNKNOWN; + + XGIhw_ext.ulExternalChip = 0; + + switch (xgi_video_info.hasVB) { + case HASVB_301: + inXGIIDXREG(XGIPART4, 0x01, reg); + if (reg >= 0xE0) { + XGIhw_ext.ujVBChipID = VB_CHIP_302LV; + printk(KERN_INFO "XGIfb: XGI302LV bridge detected (revision 0x%02x)\n",reg); + } else if (reg >= 0xD0) { + XGIhw_ext.ujVBChipID = VB_CHIP_301LV; + printk(KERN_INFO "XGIfb: XGI301LV bridge detected (revision 0x%02x)\n",reg); + } + /* else if (reg >= 0xB0) { + XGIhw_ext.ujVBChipID = VB_CHIP_301B; + inXGIIDXREG(XGIPART4,0x23,reg1); + printk("XGIfb: XGI301B bridge detected\n"); + }*/ + else { + XGIhw_ext.ujVBChipID = VB_CHIP_301; + printk("XGIfb: XGI301 bridge detected\n"); + } + break; + case HASVB_302: + inXGIIDXREG(XGIPART4, 0x01, reg); + if (reg >= 0xE0) { + XGIhw_ext.ujVBChipID = VB_CHIP_302LV; + printk(KERN_INFO "XGIfb: XGI302LV bridge detected (revision 0x%02x)\n",reg); + } else if (reg >= 0xD0) { + XGIhw_ext.ujVBChipID = VB_CHIP_301LV; + printk(KERN_INFO "XGIfb: XGI302LV bridge detected (revision 0x%02x)\n",reg); + } else if (reg >= 0xB0) { + inXGIIDXREG(XGIPART4,0x23,reg1); + + XGIhw_ext.ujVBChipID = VB_CHIP_302B; + + } else { + XGIhw_ext.ujVBChipID = VB_CHIP_302; + printk(KERN_INFO "XGIfb: XGI302 bridge detected\n"); + } + break; + case HASVB_LVDS: + XGIhw_ext.ulExternalChip = 0x1; + printk(KERN_INFO "XGIfb: LVDS transmitter detected\n"); + break; + case HASVB_TRUMPION: + XGIhw_ext.ulExternalChip = 0x2; + printk(KERN_INFO "XGIfb: Trumpion Zurac LVDS scaler detected\n"); + break; + case HASVB_CHRONTEL: + XGIhw_ext.ulExternalChip = 0x4; + printk(KERN_INFO "XGIfb: Chrontel TV encoder detected\n"); + break; + case HASVB_LVDS_CHRONTEL: + XGIhw_ext.ulExternalChip = 0x5; + printk(KERN_INFO "XGIfb: LVDS transmitter and Chrontel TV encoder detected\n"); + break; + default: + printk(KERN_INFO "XGIfb: No or unknown bridge type detected\n"); + break; + } + + if (xgi_video_info.hasVB != HASVB_NONE) { + XGIfb_detect_VB(); + } + + if (xgi_video_info.disp_state & DISPTYPE_DISP2) { + if (XGIfb_crt1off) + xgi_video_info.disp_state |= DISPMODE_SINGLE; + else + xgi_video_info.disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1); + } else { + xgi_video_info.disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1; + } + + if (xgi_video_info.disp_state & DISPTYPE_LCD) { + if (!enable_dstn) { + inXGIIDXREG(XGICR, IND_XGI_LCD_PANEL, reg); + reg &= 0x0f; + XGIhw_ext.ulCRT2LCDType = XGI310paneltype[reg]; + + } else { + // TW: FSTN/DSTN + XGIhw_ext.ulCRT2LCDType = LCD_320x480; + } + } + + XGIfb_detectedpdc = 0; + + XGIfb_detectedlcda = 0xff; +#ifndef LINUXBIOS + + /* TW: Try to find about LCDA */ + + if((XGIhw_ext.ujVBChipID == VB_CHIP_302B) || + (XGIhw_ext.ujVBChipID == VB_CHIP_301LV) || + (XGIhw_ext.ujVBChipID == VB_CHIP_302LV)) + { + int tmp; + inXGIIDXREG(XGICR,0x34,tmp); + if(tmp <= 0x13) + { + // Currently on LCDA? (Some BIOSes leave CR38) + inXGIIDXREG(XGICR,0x38,tmp); + if((tmp & 0x03) == 0x03) + { +// XGI_Pr.XGI_UseLCDA = TRUE; + }else + { + // Currently on LCDA? (Some newer BIOSes set D0 in CR35) + inXGIIDXREG(XGICR,0x35,tmp); + if(tmp & 0x01) + { +// XGI_Pr.XGI_UseLCDA = TRUE; + }else + { + inXGIIDXREG(XGICR,0x30,tmp); + if(tmp & 0x20) + { + inXGIIDXREG(XGIPART1,0x13,tmp); + if(tmp & 0x04) + { +// XGI_Pr.XGI_UseLCDA = TRUE; + } + } + } + } + } + + } + + +#endif + + if (xgifb_mode_idx >= 0) + xgifb_mode_idx = XGIfb_validate_mode(xgifb_mode_idx); + + if (xgifb_mode_idx < 0) { + switch (xgi_video_info.disp_state & DISPTYPE_DISP2) { + case DISPTYPE_LCD: + xgifb_mode_idx = DEFAULT_LCDMODE; + if (xgi_video_info.chip == XG21) + { + xgifb_mode_idx = XGIfb_GetXG21DefaultLVDSModeIdx(); + } + break; + case DISPTYPE_TV: + xgifb_mode_idx = DEFAULT_TVMODE; + break; + default: + xgifb_mode_idx = DEFAULT_MODE; + break; + } + } + + XGIfb_mode_no = XGIbios_mode[xgifb_mode_idx].mode_no; + + + if( xgi_video_info.refresh_rate == 0) + xgi_video_info.refresh_rate = 60; /*yilin set default refresh rate */ + if(XGIfb_search_refresh_rate(xgi_video_info.refresh_rate) == 0) + { + XGIfb_rate_idx = XGIbios_mode[xgifb_mode_idx].rate_idx; + xgi_video_info.refresh_rate = 60; + } + + xgi_video_info.video_bpp = XGIbios_mode[xgifb_mode_idx].bpp; + xgi_video_info.video_vwidth = xgi_video_info.video_width = XGIbios_mode[xgifb_mode_idx].xres; + xgi_video_info.video_vheight = xgi_video_info.video_height = XGIbios_mode[xgifb_mode_idx].yres; + xgi_video_info.org_x = xgi_video_info.org_y = 0; + xgi_video_info.video_linelength = xgi_video_info.video_width * (xgi_video_info.video_bpp >> 3); + switch(xgi_video_info.video_bpp) { + case 8: + xgi_video_info.DstColor = 0x0000; + xgi_video_info.XGI310_AccelDepth = 0x00000000; + xgi_video_info.video_cmap_len = 256; + break; + case 16: + xgi_video_info.DstColor = 0x8000; + xgi_video_info.XGI310_AccelDepth = 0x00010000; + xgi_video_info.video_cmap_len = 16; + break; + case 32: + xgi_video_info.DstColor = 0xC000; + xgi_video_info.XGI310_AccelDepth = 0x00020000; + xgi_video_info.video_cmap_len = 16; + break; + default: + xgi_video_info.video_cmap_len = 16; + printk(KERN_INFO "XGIfb: Unsupported depth %d", xgi_video_info.video_bpp); + break; + } + + + + printk(KERN_INFO "XGIfb: Default mode is %dx%dx%d (%dHz)\n", + xgi_video_info.video_width, xgi_video_info.video_height, xgi_video_info.video_bpp, + xgi_video_info.refresh_rate); + + default_var.xres = default_var.xres_virtual = xgi_video_info.video_width; + default_var.yres = default_var.yres_virtual = xgi_video_info.video_height; + default_var.bits_per_pixel = xgi_video_info.video_bpp; + + XGIfb_bpp_to_var(&default_var); + + default_var.pixclock = (u32) (1000000000 / + XGIfb_mode_rate_to_dclock(&XGI_Pr, &XGIhw_ext, + XGIfb_mode_no, XGIfb_rate_idx)); + + if(XGIfb_mode_rate_to_ddata(&XGI_Pr, &XGIhw_ext, + XGIfb_mode_no, XGIfb_rate_idx, + &default_var.left_margin, &default_var.right_margin, + &default_var.upper_margin, &default_var.lower_margin, + &default_var.hsync_len, &default_var.vsync_len, + &default_var.sync, &default_var.vmode)) { + + if((default_var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + default_var.yres <<= 1; + default_var.yres_virtual <<= 1; + } else if((default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + default_var.pixclock >>= 1; + default_var.yres >>= 1; + default_var.yres_virtual >>= 1; + } + + } + + +#if 0 +#ifdef XGIFB_PAN + if(XGIfb_ypan) { + default_var.yres_virtual = + xgi_video_info.heapstart / (default_var.xres * (default_var.bits_per_pixel >> 3)); + if(default_var.yres_virtual <= default_var.yres) { + default_var.yres_virtual = default_var.yres; + } + } +#endif +#endif + + + xgi_video_info.accel = 0; + if(XGIfb_accel) { + xgi_video_info.accel = -1; + default_var.accel_flags |= FB_ACCELF_TEXT; + XGIfb_initaccel(); + } + + fb_info->flags = FBINFO_FLAG_DEFAULT; + fb_info->var = default_var; + fb_info->fix = XGIfb_fix; + fb_info->par = &xgi_video_info; + fb_info->screen_base = xgi_video_info.video_vbase; + fb_info->fbops = &XGIfb_ops; + XGIfb_get_fix(&fb_info->fix, -1, fb_info); + fb_info->pseudo_palette = pseudo_palette; + + fb_alloc_cmap(&fb_info->cmap, 256 , 0); + + +#ifdef CONFIG_MTRR + xgi_video_info.mtrr = mtrr_add((unsigned int) xgi_video_info.video_base, + (unsigned int) xgi_video_info.video_size, + MTRR_TYPE_WRCOMB, 1); + if(xgi_video_info.mtrr) { + printk(KERN_INFO "XGIfb: Added MTRRs\n"); + } +#endif + + if(register_framebuffer(fb_info) < 0) + { + return -EINVAL; + } + + XGIfb_registered = 1; + + printk(KERN_INFO "XGIfb: Installed XGIFB_GET_INFO ioctl (%x)\n", XGIFB_GET_INFO); + +/* printk(KERN_INFO "XGIfb: 2D acceleration is %s, scrolling mode %s\n", + XGIfb_accel ? "enabled" : "disabled", + XGIfb_ypan ? "ypan" : "redraw"); +*/ + printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n", + fb_info->node, myid, VER_MAJOR, VER_MINOR, VER_LEVEL); + + + } + + dumpVGAReg(); + + return 0; +} + + +/*****************************************************/ +/* PCI DEVICE HANDLING */ +/*****************************************************/ + +static void __devexit xgifb_remove(struct pci_dev *pdev) +{ + /* Unregister the framebuffer */ +// if(xgi_video_info.registered) { + unregister_framebuffer(fb_info); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3)) + framebuffer_release(fb_info); +#else + kfree(fb_info); +#endif +// } + + pci_set_drvdata(pdev, NULL); + +}; + +static struct pci_driver xgifb_driver = { + .name = "xgifb", + .id_table = xgifb_pci_table, + .probe = xgifb_probe, + .remove = __devexit_p(xgifb_remove) +}; + +XGIINITSTATIC int __init xgifb_init(void) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("xgifb", &option)) + return -ENODEV; + XGIfb_setup(option); +#endif +#endif + return(pci_register_driver(&xgifb_driver)); +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) +#ifndef MODULE +module_init(xgifb_init); +#endif +#endif + +/*****************************************************/ +/* MODULE */ +/*****************************************************/ + +#ifdef MODULE + +static char *mode = NULL; +static int vesa = 0; +static unsigned int rate = 0; +static unsigned int crt1off = 1; +static unsigned int mem = 0; +static char *forcecrt2type = NULL; +static int forcecrt1 = -1; +static int pdc = -1; +static int pdc1 = -1; +static int noaccel = -1; +static int noypan = -1; +static int nomax = -1; +static int userom = -1; +static int useoem = -1; +static char *tvstandard = NULL; +static int nocrt2rate = 0; +static int scalelcd = -1; +static char *specialtiming = NULL; +static int lvdshl = -1; +static int tvxposoffset = 0, tvyposoffset = 0; +#if !defined(__i386__) && !defined(__x86_64__) +static int resetcard = 0; +static int videoram = 0; +#endif + +MODULE_DESCRIPTION("Z7 Z9 Z9S Z11 framebuffer device driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("XGITECH , Others"); + + + +module_param(mem, int, 0); +module_param(noaccel, int, 0); +module_param(noypan, int, 0); +module_param(nomax, int, 0); +module_param(userom, int, 0); +module_param(useoem, int, 0); +module_param(mode, charp, 0); +module_param(vesa, int, 0); +module_param(rate, int, 0); +module_param(forcecrt1, int, 0); +module_param(forcecrt2type, charp, 0); +module_param(scalelcd, int, 0); +module_param(pdc, int, 0); +module_param(pdc1, int, 0); +module_param(specialtiming, charp, 0); +module_param(lvdshl, int, 0); +module_param(tvstandard, charp, 0); +module_param(tvxposoffset, int, 0); +module_param(tvyposoffset, int, 0); +module_param(filter, int, 0); +module_param(nocrt2rate, int, 0); +#if !defined(__i386__) && !defined(__x86_64__) +module_param(resetcard, int, 0); +module_param(videoram, int, 0); +#endif + + +MODULE_PARM_DESC(mem, + "\nDetermines the beginning of the video memory heap in KB. This heap is used\n" + "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n" + "on the amount of video RAM available. If 8MB of video RAM or less is available,\n" + "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n" + "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n" + "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n" + "for XFree86 4.x/X.org 6.7 and later.\n"); + +MODULE_PARM_DESC(noaccel, + "\nIf set to anything other than 0, 2D acceleration will be disabled.\n" + "(default: 0)\n"); + +MODULE_PARM_DESC(noypan, + "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n" + "will be performed by redrawing the screen. (default: 0)\n"); + +MODULE_PARM_DESC(nomax, + "\nIf y-panning is enabled, xgifb will by default use the entire available video\n" + "memory for the virtual screen in order to optimize scrolling performance. If\n" + "this is set to anything other than 0, xgifb will not do this and thereby \n" + "enable the user to positively specify a virtual Y size of the screen using\n" + "fbset. (default: 0)\n"); + + + +MODULE_PARM_DESC(mode, + "\nSelects the desired default display mode in the format XxYxDepth,\n" + "eg. 1024x768x16. Other formats supported include XxY-Depth and\n" + "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n" + "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n"); + +MODULE_PARM_DESC(vesa, + "\nSelects the desired default display mode by VESA defined mode number, eg.\n" + "0x117 (default: 0x0103)\n"); + + +MODULE_PARM_DESC(rate, + "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n" + "If the mode is specified in the format XxY-Depth@Rate, this parameter\n" + "will be ignored (default: 60)\n"); + +MODULE_PARM_DESC(forcecrt1, + "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n" + "connected. With this option, the detection can be overridden (1=CRT1 ON,\n" + "0=CRT1 OFF) (default: [autodetected])\n"); + +MODULE_PARM_DESC(forcecrt2type, + "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n" + "LCD, TV or secondary VGA. With this option, this autodetection can be\n" + "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n" + "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n" + "be used instead of TV to override the TV detection. Furthermore, on systems\n" + "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n" + "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n" + "depends on the very hardware in use. (default: [autodetected])\n"); + +MODULE_PARM_DESC(scalelcd, + "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n" + "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n" + "show black bars around the image, TMDS panels will probably do the scaling\n" + "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n"); + +MODULE_PARM_DESC(pdc, + "\nThis is for manually selecting the LCD panel delay compensation. The driver\n" + "should detect this correctly in most cases; however, sometimes this is not\n" + "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n" + "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n" + "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n" + "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n"); + +MODULE_PARM_DESC(pdc1, + "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n" + "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n" + "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n" + "implemented yet.\n"); + +MODULE_PARM_DESC(specialtiming, + "\nPlease refer to documentation for more information on this option.\n"); + +MODULE_PARM_DESC(lvdshl, + "\nPlease refer to documentation for more information on this option.\n"); + +MODULE_PARM_DESC(tvstandard, + "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n" + "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n"); + +MODULE_PARM_DESC(tvxposoffset, + "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n" + "Default: 0\n"); + +MODULE_PARM_DESC(tvyposoffset, + "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n" + "Default: 0\n"); + +MODULE_PARM_DESC(filter, + "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n" + "(Possible values 0-7, default: [no filter])\n"); + +MODULE_PARM_DESC(nocrt2rate, + "\nSetting this to 1 will force the driver to use the default refresh rate for\n" + "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n"); + + + + +int __init xgifb_init_module(void) +{ + printk("\nXGIfb_init_module"); + if(mode) + XGIfb_search_mode(mode); + else if (vesa != -1) + XGIfb_search_vesamode(vesa); + + return(xgifb_init()); +} + +static void __exit xgifb_remove_module(void) +{ + pci_unregister_driver(&xgifb_driver); + printk(KERN_DEBUG "xgifb: Module unloaded\n"); +} + +module_init(xgifb_init_module); +module_exit(xgifb_remove_module); + +#endif /* /MODULE */ + +EXPORT_SYMBOL(XGI_malloc); +EXPORT_SYMBOL(XGI_free); + diff --git a/drivers/staging/xgifb/XGIfb.h b/drivers/staging/xgifb/XGIfb.h new file mode 100644 index 000000000000..41bf163d4e6b --- /dev/null +++ b/drivers/staging/xgifb/XGIfb.h @@ -0,0 +1,215 @@ +#ifndef _LINUX_XGIFB +#define _LINUX_XGIFB +#include <linux/spinlock.h> +#include <asm/ioctl.h> +#include <asm/types.h> + +#define DISPTYPE_CRT1 0x00000008L +#define DISPTYPE_CRT2 0x00000004L +#define DISPTYPE_LCD 0x00000002L +#define DISPTYPE_TV 0x00000001L +#define DISPTYPE_DISP1 DISPTYPE_CRT1 +#define DISPTYPE_DISP2 (DISPTYPE_CRT2 | DISPTYPE_LCD | DISPTYPE_TV) +#define DISPMODE_SINGLE 0x00000020L +#define DISPMODE_MIRROR 0x00000010L +#define DISPMODE_DUALVIEW 0x00000040L + +#define HASVB_NONE 0x00 +#define HASVB_301 0x01 +#define HASVB_LVDS 0x02 +#define HASVB_TRUMPION 0x04 +#define HASVB_LVDS_CHRONTEL 0x10 +#define HASVB_302 0x20 +#define HASVB_303 0x40 +#define HASVB_CHRONTEL 0x80 + +#ifndef XGIFB_ID +#define XGIFB_ID 0x53495346 /* Identify myself with 'XGIF' */ +#endif + +typedef enum _XGI_CHIP_TYPE { + XGI_VGALegacy = 0, + XGI_300, + XGI_630, + XGI_730, + XGI_540, + XGI_315H, + XGI_315, + XGI_315PRO, + XGI_550, + XGI_640, + XGI_740, + XGI_650, + XGI_650M, + XGI_330 = 16, + XGI_660, + XGI_661, + XGI_760, + XG40 = 32, + XG41, + XG42, + XG45, + XG20 = 48, + XG21, + XG27, + MAX_XGI_CHIP +} XGI_CHIP_TYPE; + +typedef enum _TVTYPE { + TVMODE_NTSC = 0, + TVMODE_PAL, + TVMODE_HIVISION, + TVTYPE_PALM, // vicki@030226 + TVTYPE_PALN, // vicki@030226 + TVTYPE_NTSCJ, // vicki@030226 + TVMODE_TOTAL +} XGI_TV_TYPE; + + +typedef struct _XGIFB_INFO XGIfb_info; +struct _XGIFB_INFO { + +unsigned long XGIfb_id; + int chip_id; /* PCI ID of detected chip */ + int memory; /* video memory in KB which XGIfb manages */ + int heapstart; /* heap start (= XGIfb "mem" argument) in KB */ + unsigned char fbvidmode; /* current XGIfb mode */ + + unsigned char XGIfb_version; + unsigned char XGIfb_revision; + unsigned char XGIfb_patchlevel; + + unsigned char XGIfb_caps; /* XGIfb capabilities */ + + int XGIfb_tqlen; /* turbo queue length (in KB) */ + + unsigned int XGIfb_pcibus; /* The card's PCI ID */ + unsigned int XGIfb_pcislot; + unsigned int XGIfb_pcifunc; + + unsigned char XGIfb_lcdpdc; /* PanelDelayCompensation */ + + unsigned char XGIfb_lcda; /* Detected status of LCDA for low res/text modes */ + + char reserved[235]; /* for future use */ +}; + + + + +typedef enum _TVPLUGTYPE { // vicki@030226 +// TVPLUG_Legacy = 0, +// TVPLUG_COMPOSITE, +// TVPLUG_SVIDEO, +// TVPLUG_SCART, +// TVPLUG_TOTAL + TVPLUG_UNKNOWN = 0, + TVPLUG_COMPOSITE = 1, + TVPLUG_SVIDEO = 2, + TVPLUG_COMPOSITE_AND_SVIDEO = 3, + TVPLUG_SCART = 4, + TVPLUG_YPBPR_525i = 5, + TVPLUG_YPBPR_525P = 6, + TVPLUG_YPBPR_750P = 7, + TVPLUG_YPBPR_1080i = 8, + TVPLUG_TOTAL +} XGI_TV_PLUG; + + +struct mode_info { + int bpp; + int xres; + int yres; + int v_xres; + int v_yres; + int org_x; + int org_y; + unsigned int vrate; +}; + +struct ap_data { + struct mode_info minfo; + unsigned long iobase; + unsigned int mem_size; + unsigned long disp_state; + XGI_CHIP_TYPE chip; + unsigned char hasVB; + XGI_TV_TYPE TV_type; + XGI_TV_PLUG TV_plug; + unsigned long version; + char reserved[256]; +}; + + + +/* If changing this, vgatypes.h must also be changed (for X driver) */ + + +/* + * NOTE! The ioctl types used to be "size_t" by mistake, but were + * really meant to be __u32. Changed to "__u32" even though that + * changes the value on 64-bit architectures, because the value + * (with a 4-byte size) is also hardwired in vgatypes.h for user + * space exports. So "__u32" is actually more compatible, duh! + */ +#define XGIFB_GET_INFO _IOR('n',0xF8,__u32) +#define XGIFB_GET_VBRSTATUS _IOR('n',0xF9,__u32) + + + +struct video_info{ + int chip_id; + unsigned int video_size; + unsigned long video_base; + char * video_vbase; + unsigned long mmio_base; + char * mmio_vbase; + unsigned long vga_base; + unsigned long mtrr; + unsigned long heapstart; + + int video_bpp; + int video_cmap_len; + int video_width; + int video_height; + int video_vwidth; + int video_vheight; + int org_x; + int org_y; + int video_linelength; + unsigned int refresh_rate; + + unsigned long disp_state; + unsigned char hasVB; + unsigned char TV_type; + unsigned char TV_plug; + + XGI_CHIP_TYPE chip; + unsigned char revision_id; + + unsigned short DstColor; + unsigned long XGI310_AccelDepth; + unsigned long CommandReg; + + spinlock_t lockaccel; + + unsigned int pcibus; + unsigned int pcislot; + unsigned int pcifunc; + + int accel; + unsigned short subsysvendor; + unsigned short subsysdevice; + + char reserved[236]; +}; + + +extern struct video_info xgi_video_info; + +#ifdef __KERNEL__ +//extern void xgi_malloc(struct xgi_memreq *req); +extern void xgi_free(unsigned long base); +extern void xgi_dispinfo(struct ap_data *rec); +#endif +#endif diff --git a/drivers/staging/xgifb/osdef.h b/drivers/staging/xgifb/osdef.h new file mode 100644 index 000000000000..4bc7d3a7440c --- /dev/null +++ b/drivers/staging/xgifb/osdef.h @@ -0,0 +1,153 @@ +#ifndef _OSDEF_H_ +#define _OSDEF_H_ + +/* #define WINCE_HEADER*/ +/*#define WIN2000*/ +/* #define TC */ +#define LINUX_KERNEL +/* #define LINUX_XF86 */ + +/**********************************************************************/ +#ifdef LINUX_KERNEL +//#include <linux/config.h> +#endif + + +/**********************************************************************/ +#ifdef TC +#endif +#ifdef WIN2000 +#endif +#ifdef WINCE_HEADER +#endif +#ifdef LINUX_XF86 +#define LINUX +#endif +#ifdef LINUX_KERNEL +#define LINUX +#endif + +/**********************************************************************/ +#ifdef TC +#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize); +#endif +#ifdef WIN2000 +#define XGI_SetMemory(MemoryAddress,MemorySize,value) MemFill((PVOID) MemoryAddress,(ULONG) MemorySize,(UCHAR) value); +#endif +#ifdef WINCE_HEADER +#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize); +#endif +#ifdef LINUX_XF86 +#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize) +#endif +#ifdef LINUX_KERNEL +#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize) +#endif +/**********************************************************************/ + +/**********************************************************************/ + +#ifdef TC +#define XGI_MemoryCopy(Destination,Soruce,Length) memmove(Destination, Soruce, Length); +#endif +#ifdef WIN2000 +#define XGI_MemoryCopy(Destination,Soruce,Length) /*VideoPortMoveMemory((PUCHAR)Destination , Soruce,length);*/ +#endif +#ifdef WINCE_HEADER +#define XGI_MemoryCopy(Destination,Soruce,Length) memmove(Destination, Soruce, Length); +#endif +#ifdef LINUX_XF86 +#define XGI_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length) +#endif +#ifdef LINUX_KERNEL +#define XGI_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length) +#endif + +/**********************************************************************/ + +#ifdef OutPortByte +#undef OutPortByte +#endif /* OutPortByte */ + +#ifdef OutPortWord +#undef OutPortWord +#endif /* OutPortWord */ + +#ifdef OutPortLong +#undef OutPortLong +#endif /* OutPortLong */ + +#ifdef InPortByte +#undef InPortByte +#endif /* InPortByte */ + +#ifdef InPortWord +#undef InPortWord +#endif /* InPortWord */ + +#ifdef InPortLong +#undef InPortLong +#endif /* InPortLong */ + +/**********************************************************************/ +/* TC */ +/**********************************************************************/ + +#ifdef TC +#define OutPortByte(p,v) outp((unsigned short)(p),(unsigned char)(v)) +#define OutPortWord(p,v) outp((unsigned short)(p),(unsigned short)(v)) +#define OutPortLong(p,v) outp((unsigned short)(p),(unsigned long)(v)) +#define InPortByte(p) inp((unsigned short)(p)) +#define InPortWord(p) inp((unsigned short)(p)) +#define InPortLong(p) ((inp((unsigned short)(p+2))<<16) | inp((unsigned short)(p))) +#endif + +/**********************************************************************/ +/* LINUX XF86 */ +/**********************************************************************/ + +#ifdef LINUX_XF86 +#define OutPortByte(p,v) outb((CARD16)(p),(CARD8)(v)) +#define OutPortWord(p,v) outw((CARD16)(p),(CARD16)(v)) +#define OutPortLong(p,v) outl((CARD16)(p),(CARD32)(v)) +#define InPortByte(p) inb((CARD16)(p)) +#define InPortWord(p) inw((CARD16)(p)) +#define InPortLong(p) inl((CARD16)(p)) +#endif + +#ifdef LINUX_KERNEL +#define OutPortByte(p,v) outb((u8)(v),(p)) +#define OutPortWord(p,v) outw((u16)(v),(p)) +#define OutPortLong(p,v) outl((u32)(v),(p)) +#define InPortByte(p) inb(p) +#define InPortWord(p) inw(p) +#define InPortLong(p) inl(p) +#endif + +/**********************************************************************/ +/* WIN 2000 */ +/**********************************************************************/ + +#ifdef WIN2000 +#define OutPortByte(p,v) VideoPortWritePortUchar ((PUCHAR) (p), (UCHAR) (v)) +#define OutPortWord(p,v) VideoPortWritePortUshort((PUSHORT) (p), (USHORT) (v)) +#define OutPortLong(p,v) VideoPortWritePortUlong ((PULONG) (p), (ULONG) (v)) +#define InPortByte(p) VideoPortReadPortUchar ((PUCHAR) (p)) +#define InPortWord(p) VideoPortReadPortUshort ((PUSHORT) (p)) +#define InPortLong(p) VideoPortReadPortUlong ((PULONG) (p)) +#endif + + +/**********************************************************************/ +/* WIN CE */ +/**********************************************************************/ + +#ifdef WINCE_HEADER +#define OutPortByte(p,v) WRITE_PORT_UCHAR ((PUCHAR) (p), (UCHAR) (v)) +#define OutPortWord(p,v) WRITE_PORT_USHORT((PUSHORT) (p), (USHORT) (v)) +#define OutPortLong(p,v) WRITE_PORT_ULONG ((PULONG) (p), (ULONG) (v)) +#define InPortByte(p) READ_PORT_UCHAR ((PUCHAR) (p)) +#define InPortWord(p) READ_PORT_USHORT ((PUSHORT) (p)) +#define InPortLong(p) READ_PORT_ULONG ((PULONG) (p)) +#endif +#endif // _OSDEF_H_ diff --git a/drivers/staging/xgifb/vb_def.h b/drivers/staging/xgifb/vb_def.h new file mode 100644 index 000000000000..17a7ada4926e --- /dev/null +++ b/drivers/staging/xgifb/vb_def.h @@ -0,0 +1,1017 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/xgi/initdef.h,v 1.4 2000/12/02 01:16:17 dawes Exp $ */ +#ifndef _INITDEF_ +#define _INITDEF_ + +#ifndef NewScratch +#define NewScratch +#endif +/* shampoo */ +#ifdef LINUX_KERNEL +#define SEQ_ADDRESS_PORT 0x0014 +#define SEQ_DATA_PORT 0x0015 +#define MISC_OUTPUT_REG_READ_PORT 0x001C +#define MISC_OUTPUT_REG_WRITE_PORT 0x0012 +#define GRAPH_DATA_PORT 0x1F +#define GRAPH_ADDRESS_PORT 0x1E +#define XGI_MASK_DUAL_CHIP 0x04 /* SR3A */ +#define CRTC_ADDRESS_PORT_COLOR 0x0024 +#define VIDEO_SUBSYSTEM_ENABLE_PORT 0x0013 +#define PCI_COMMAND 0x04 +#endif +/* ~shampoo */ + + +#define VB_XGI301 0x0001 /*301b*/ +#define VB_XGI301B 0x0002 +#define VB_XGI302B 0x0004 +#define VB_XGI301LV 0x0008 /*301lv*/ +#define VB_XGI302LV 0x0010 +#define VB_XGI301C 0x0020 /* for 301C */ +#define VB_NoLCD 0x8000 +/*end 301b*/ + +#define VB_YPbPrInfo 0x07 /*301lv*/ +#define VB_YPbPr525i 0x00 +#define VB_YPbPr525p 0x01 +#define VB_YPbPr750p 0x02 +#define VB_YPbPr1080i 0x03 + +/* #define CRT1Len 17 */ +#define LVDSCRT1Len 15 +#define CHTVRegDataLen 5 + +/* #define ModeInfoFlag 0x07 */ +/* #define IsTextMode 0x07 */ +/* #define ModeText 0x00 */ +/* #define ModeCGA 0x01 */ +/* #define ModeEGA 0x02 */ +/* #define ModeVGA 0x03 */ +/* #define Mode15Bpp 0x04 */ +/* #define Mode16Bpp 0x05 */ +/* #define Mode24Bpp 0x06 */ +/* #define Mode32Bpp 0x07 */ + +/* #define DACInfoFlag 0x18 */ +/* #define MemoryInfoFlag 0x1E0 */ +/* #define MemorySizeShift 0x05 */ + +#define Charx8Dot 0x0200 +#define LineCompareOff 0x0400 +#define CRT2Mode 0x0800 +#define HalfDCLK 0x1000 +#define NoSupportSimuTV 0x2000 +#define DoubleScanMode 0x8000 + +#define SupportAllCRT2 0x0078 +#define SupportTV 0x0008 +#define SupportHiVisionTV 0x0010 +#define SupportLCD 0x0020 +#define SupportRAMDAC2 0x0040 +#define NoSupportTV 0x0070 +#define NoSupportHiVisionTV 0x0060 +#define NoSupportLCD 0x0058 +#define SupportCHTV 0x0800 +#define SupportCRT2in301C 0x0100 /* for 301C */ +#define SupportTV1024 0x0800 /*301b*/ +#define SupportYPbPr 0x1000 /*301lv*/ +#define InterlaceMode 0x0080 +#define SyncPP 0x0000 +#define SyncPN 0x4000 +#define SyncNP 0x8000 +/* #define SyncNN 0xc000 */ +#define ECLKindex0 0x0000 +#define ECLKindex1 0x0100 +#define ECLKindex2 0x0200 +#define ECLKindex3 0x0300 +#define ECLKindex4 0x0400 + +#define SetSimuScanMode 0x0001 +#define SwitchToCRT2 0x0002 +/* #define SetCRT2ToTV 0x009C */ +#define SetCRT2ToAVIDEO 0x0004 +#define SetCRT2ToSVIDEO 0x0008 +#define SetCRT2ToSCART 0x0010 +#define SetCRT2ToLCD 0x0020 +#define SetCRT2ToRAMDAC 0x0040 +#define SetCRT2ToHiVisionTV 0x0080 +#define SetNTSCTV 0x0000 +/* #define SetPALTV 0x0100 */ +#define SetInSlaveMode 0x0200 +#define SetNotSimuMode 0x0400 +#define SetNotSimuTVMode 0x0400 +#define SetDispDevSwitch 0x0800 +#define LoadDACFlag 0x1000 +#define DisableCRT2Display 0x2000 +#define DriverMode 0x4000 +#define HotKeySwitch 0x8000 +#define SetCHTVOverScan 0x8000 +/* #define SetCRT2ToLCDA 0x8000 301b */ +#define PanelRGB18Bit 0x0100 +#define PanelRGB24Bit 0x0000 + +#define TVOverScan 0x10 +#define TVOverScanShift 4 +#define ClearBufferFlag 0x20 +#define EnableDualEdge 0x01 /*301b*/ +#define SetToLCDA 0x02 + +#define YPbPrModeInfo 0x38 +/* #define YPbPrMode525i 0x00 */ +/* #define YPbPrMode525p 0x08 */ +/* #define YPbPrMode750p 0x10 */ +/* #define YPbPrMode1080i 0x18 */ + +#define SetSCARTOutput 0x01 +#define BoardTVType 0x02 +#define EnablePALMN 0x40 +/* #define ProgrammingCRT2 0x01 */ +/* #define TVSimuMode 0x02 */ +/* #define RPLLDIV2XO 0x04 */ +/* #define LCDVESATiming 0x08 */ +/* #define EnableLVDSDDA 0x10 */ +#define SetDispDevSwitchFlag 0x20 +#define CheckWinDos 0x40 +#define SetJDOSMode 0x80 + +#define Panel320x480 0x07/*fstn*/ +/* [ycchen] 02/12/03 Modify for Multi-Sync. LCD Support */ +#define PanelResInfo 0x1F /* CR36 Panel Type/LCDResInfo */ +#define PanelRefInfo 0x60 +#define Panel800x600 0x01 +#define Panel1024x768 0x02 +#define Panel1024x768x75 0x22 +#define Panel1280x1024 0x03 +#define Panel1280x1024x75 0x23 +#define Panel640x480 0x04 +#define Panel1024x600 0x05 +#define Panel1152x864 0x06 +#define Panel1280x960 0x07 +#define Panel1152x768 0x08 +#define Panel1400x1050 0x09 +#define Panel1280x768 0x0A +#define Panel1600x1200 0x0B + +#define PanelRef60Hz 0x00 +#define PanelRef75Hz 0x20 +#define LCDRGB18Bit 0x01 + +#define ExtChipTrumpion 0x06 +#define ExtChipCH7005 0x08 +#define ExtChipMitacTV 0x0a +#define LCDNonExpanding 0x10 +#define LCDNonExpandingShift 4 +#define LCDSync 0x20 +#define LCDSyncBit 0xe0 +#define LCDSyncShift 6 + +/* #define DDC2DelayTime 300 */ + +#define CRT2DisplayFlag 0x2000 +/* #define LCDDataLen 8 */ +/* #define HiTVDataLen 12 */ +/* #define TVDataLen 16 */ +/* #define SetPALTV 0x0100 */ +#define HalfDCLK 0x1000 +#define NTSCHT 1716 +#define NTSCVT 525 +#define PALHT 1728 +#define PALVT 625 +#define StHiTVHT 892 +#define StHiTVVT 1126 +#define StHiTextTVHT 1000 +#define StHiTextTVVT 1126 +#define ExtHiTVHT 2100 +#define ExtHiTVVT 1125 + +#define St750pTVHT 1716 +#define St750pTVVT 525 +#define Ext750pTVHT 1716 +#define Ext750pTVVT 525 +#define St525pTVHT 1716 +#define St525pTVVT 525 +#define Ext525pTVHT 1716 +#define Ext525pTVVT 525 +#define St525iTVHT 1716 +#define St525iTVVT 525 +#define Ext525iTVHT 1716 +#define Ext525iTVVT 525 + +#define VCLKStartFreq 25 +#define SoftDramType 0x80 +#define VCLK40 0x04 + +#define VCLK162 0x21 + +#define LCDRGB18Bit 0x01 +#define LoadDACFlag 0x1000 +#define AfterLockCRT2 0x4000 +#define SetCRT2ToAVIDEO 0x0004 +#define SetCRT2ToSCART 0x0010 +#define Ext2StructSize 5 + + +#define YPbPr525iVCLK 0x03B +#define YPbPr525iVCLK_2 0x03A + +#define SwitchToCRT2 0x0002 +/* #define LCDVESATiming 0x08 */ +#define SetSCARTOutput 0x01 +#define AVIDEOSense 0x01 +#define SVIDEOSense 0x02 +#define SCARTSense 0x04 +#define LCDSense 0x08 +#define Monitor1Sense 0x20 +#define Monitor2Sense 0x10 +#define HiTVSense 0x40 +#define BoardTVType 0x02 +#define HotPlugFunction 0x08 +#define StStructSize 0x06 + + +#define XGI_CRT2_PORT_00 0x00 - 0x030 +#define XGI_CRT2_PORT_04 0x04 - 0x030 +#define XGI_CRT2_PORT_10 0x10 - 0x30 +#define XGI_CRT2_PORT_12 0x12 - 0x30 +#define XGI_CRT2_PORT_14 0x14 - 0x30 + + +#define LCDNonExpanding 0x10 +#define ADR_CRT2PtrData 0x20E +#define offset_Zurac 0x210 +#define ADR_LVDSDesPtrData 0x212 +#define ADR_LVDSCRT1DataPtr 0x214 +#define ADR_CHTVVCLKPtr 0x216 +#define ADR_CHTVRegDataPtr 0x218 + +#define LVDSDataLen 6 +/* #define EnableLVDSDDA 0x10 */ +/* #define LVDSDesDataLen 3 */ +#define ActiveNonExpanding 0x40 +#define ActiveNonExpandingShift 6 +/* #define ActivePAL 0x20 */ +#define ActivePALShift 5 +/* #define ModeSwitchStatus 0x0F */ +#define SoftTVType 0x40 +#define SoftSettingAddr 0x52 +#define ModeSettingAddr 0x53 + +/* #define SelectCRT1Rate 0x4 */ + +#define _PanelType00 0x00 +#define _PanelType01 0x08 +#define _PanelType02 0x10 +#define _PanelType03 0x18 +#define _PanelType04 0x20 +#define _PanelType05 0x28 +#define _PanelType06 0x30 +#define _PanelType07 0x38 +#define _PanelType08 0x40 +#define _PanelType09 0x48 +#define _PanelType0A 0x50 +#define _PanelType0B 0x58 +#define _PanelType0C 0x60 +#define _PanelType0D 0x68 +#define _PanelType0E 0x70 +#define _PanelType0F 0x78 + + +#define PRIMARY_VGA 0 /* 1: XGI is primary vga 0:XGI is secondary vga */ +#define BIOSIDCodeAddr 0x235 +#define OEMUtilIDCodeAddr 0x237 +#define VBModeIDTableAddr 0x239 +#define OEMTVPtrAddr 0x241 +#define PhaseTableAddr 0x243 +#define NTSCFilterTableAddr 0x245 +#define PALFilterTableAddr 0x247 +#define OEMLCDPtr_1Addr 0x249 +#define OEMLCDPtr_2Addr 0x24B +#define LCDHPosTable_1Addr 0x24D +#define LCDHPosTable_2Addr 0x24F +#define LCDVPosTable_1Addr 0x251 +#define LCDVPosTable_2Addr 0x253 +#define OEMLCDPIDTableAddr 0x255 + +#define VBModeStructSize 5 +#define PhaseTableSize 4 +#define FilterTableSize 4 +#define LCDHPosTableSize 7 +#define LCDVPosTableSize 5 +#define OEMLVDSPIDTableSize 4 +#define LVDSHPosTableSize 4 +#define LVDSVPosTableSize 6 + +#define VB_ModeID 0 +#define VB_TVTableIndex 1 +#define VB_LCDTableIndex 2 +#define VB_LCDHIndex 3 +#define VB_LCDVIndex 4 + +#define OEMLCDEnable 0x0001 +#define OEMLCDDelayEnable 0x0002 +#define OEMLCDPOSEnable 0x0004 +#define OEMTVEnable 0x0100 +#define OEMTVDelayEnable 0x0200 +#define OEMTVFlickerEnable 0x0400 +#define OEMTVPhaseEnable 0x0800 +#define OEMTVFilterEnable 0x1000 + +#define OEMLCDPanelIDSupport 0x0080 + +/* #define LCDVESATiming 0x0001 //LCD Info CR37 */ +/* #define EnableLVDSDDA 0x0002 */ +#define EnableScalingLCD 0x0008 +#define SetPWDEnable 0x0004 +#define SetLCDtoNonExpanding 0x0010 +/* #define SetLCDPolarity 0x00E0 */ +#define SetLCDDualLink 0x0100 +#define SetLCDLowResolution 0x0200 +#define SetLCDStdMode 0x0400 +#define SetTVStdMode 0x0200 +#define SetTVLowResolution 0x0400 +/* ============================================================= + for 310 +============================================================== */ +#define SoftDRAMType 0x80 +#define SoftSetting_OFFSET 0x52 +#define SR07_OFFSET 0x7C +#define SR15_OFFSET 0x7D +#define SR16_OFFSET 0x81 +#define SR17_OFFSET 0x85 +#define SR19_OFFSET 0x8D +#define SR1F_OFFSET 0x99 +#define SR21_OFFSET 0x9A +#define SR22_OFFSET 0x9B +#define SR23_OFFSET 0x9C +#define SR24_OFFSET 0x9D +#define SR25_OFFSET 0x9E +#define SR31_OFFSET 0x9F +#define SR32_OFFSET 0xA0 +#define SR33_OFFSET 0xA1 + +#define CR40_OFFSET 0xA2 +#define SR25_1_OFFSET 0xF6 +#define CR49_OFFSET 0xF7 + +#define VB310Data_1_2_Offset 0xB6 +#define VB310Data_4_D_Offset 0xB7 +#define VB310Data_4_E_Offset 0xB8 +#define VB310Data_4_10_Offset 0xBB + +#define RGBSenseDataOffset 0xBD +#define YCSenseDataOffset 0xBF +#define VideoSenseDataOffset 0xC1 +#define OutputSelectOffset 0xF3 + +#define ECLK_MCLK_DISTANCE 0x14 +#define VBIOSTablePointerStart 0x200 +#define StandTablePtrOffset VBIOSTablePointerStart+0x02 +#define EModeIDTablePtrOffset VBIOSTablePointerStart+0x04 +#define CRT1TablePtrOffset VBIOSTablePointerStart+0x06 +#define ScreenOffsetPtrOffset VBIOSTablePointerStart+0x08 +#define VCLKDataPtrOffset VBIOSTablePointerStart+0x0A +#define MCLKDataPtrOffset VBIOSTablePointerStart+0x0E +#define CRT2PtrDataPtrOffset VBIOSTablePointerStart+0x10 +#define TVAntiFlickPtrOffset VBIOSTablePointerStart+0x12 +#define TVDelayPtr1Offset VBIOSTablePointerStart+0x14 +#define TVPhaseIncrPtr1Offset VBIOSTablePointerStart+0x16 +#define TVYFilterPtr1Offset VBIOSTablePointerStart+0x18 +#define LCDDelayPtr1Offset VBIOSTablePointerStart+0x20 +#define TVEdgePtr1Offset VBIOSTablePointerStart+0x24 +#define CRT2Delay1Offset VBIOSTablePointerStart+0x28 +#define LCDDataDesOffset VBIOSTablePointerStart-0x02 +#define LCDDataPtrOffset VBIOSTablePointerStart+0x2A +#define LCDDesDataPtrOffset VBIOSTablePointerStart+0x2C +#define LCDDataList VBIOSTablePointerStart+0x22 /* add for GetLCDPtr */ +#define TVDataList VBIOSTablePointerStart+0x36 /* add for GetTVPtr */ +/* */ +/* Modify from 310.inc */ +/* */ +/* */ + + +#define ShowMsgFlag 0x20 /* SoftSetting */ +#define ShowVESAFlag 0x10 +#define HotPlugFunction 0x08 +#define ModeSoftSetting 0x04 +#define TVSoftSetting 0x02 +#define LCDSoftSetting 0x01 + +#define GatingCRTinLCDA 0x10 +#define SetHiTVOutput 0x08 +#define SetYPbPrOutput 0x04 +#define BoardTVType 0x02 +#define SetSCARTOutput 0x01 + +#define ModeSettingYPbPr 0x02 /* TVModeSetting, Others as same as CR30 */ + +/* TVModeSetting same as CR35 */ + +/* LCDModeSetting same as CR37 */ + +#define EnableNewTVFont 0x10 /* MiscCapability */ + +#define EnableLCDOutput 0x80 /* LCDCfgSetting */ + +#define SoftDRAMType 0x80 /* DRAMSetting */ +#define SoftDRAMConfig 0x40 +#define MosSelDRAMType 0x20 +#define SDRAM 000h +#define SGRAM 0x01 +#define ESDRAM 0x02 + +#define EnableAGPCfgSetting 0x01 /* AGPCfgSetting */ + +/* ---------------- SetMode Stack */ +#define CRT1Len 15 +#define VCLKLen 4 +#define DefThreshold 0x0100 +#define ExtRegsSize (57+8+37+70+63+28+768+1)/64+1 + +#define VGA_XGI315 0x0001 /* VGA Type Info */ +#define VGA_SNewis315e 0x0002 /* 315 series */ +#define VGA_XGI550 0x0004 +#define VGA_XGI640 0x0008 +#define VGA_XGI740 0x0010 +#define VGA_XGI650 0x0020 +#define VGA_XGI650M 0x0040 +#define VGA_XGI651 0x0080 +#define VGA_XGI340 0x0001 /* 340 series */ +#define VGA_XGI330 0x0001 /* 330 series */ +#define VGA_XGI660 0x0001 /* 660 series */ + +#define VB_XGI301 0x0001 /* VB Type Info */ +#define VB_XGI301B 0x0002 /* 301 series */ +#define VB_XGI302B 0x0004 +#define VB_NoLCD 0x8000 +#define VB_XGI301LV 0x0008 +#define VB_XGI302LV 0x0010 +#define VB_LVDS_NS 0x0001 /* 3rd party chip */ +#define VB_CH7017 0x0002 +#define VB_CH7007 0x0080 /* [Billy] 07/05/03 */ +/* #define VB_LVDS_SI 0x0004 */ + +#define ModeInfoFlag 0x0007 +#define IsTextMode 0x0007 +#define ModeText 0x0000 +#define ModeCGA 0x0001 +#define ModeEGA 0x0002 /* 16 colors mode */ +#define ModeVGA 0x0003 /* 256 colors mode */ +#define Mode15Bpp 0x0004 /* 15 Bpp Color Mode */ +#define Mode16Bpp 0x0005 /* 16 Bpp Color Mode */ +#define Mode24Bpp 0x0006 /* 24 Bpp Color Mode */ +#define Mode32Bpp 0x0007 /* 32 Bpp Color Mode */ + +#define DACInfoFlag 0x0018 +#define MONODAC 0x0000 +#define CGADAC 0x0008 +#define EGADAC 0x0010 +#define VGADAC 0x0018 + +#define MemoryInfoFlag 0x01e0 +#define MemorySizeShift 5 +#define Need1MSize 0x0000 +#define Need2MSize 0x0020 +#define Need4MSize 0x0060 +#define Need8MSize 0x00e0 +#define Need16MSize 0x01e0 + +#define Charx8Dot 0x0200 +#define LineCompareOff 0x0400 +#define CRT2Mode 0x0800 +#define HalfDCLK 0x1000 +#define NoSupportSimuTV 0x2000 +#define DoubleScanMode 0x8000 + +/* -------------- Ext_InfoFlag */ +#define SupportModeInfo 0x0007 +#define Support256 0x0003 +#define Support15Bpp 0x0004 +#define Support16Bpp 0x0005 +#define Support24Bpp 0x0006 +#define Support32Bpp 0x0007 + +#define SupportAllCRT2 0x0078 +#define SupportTV 0x0008 +#define SupportHiVisionTV 0x0010 +#define SupportLCD 0x0020 +#define SupportRAMDAC2 0x0040 +#define NoSupportTV 0x0070 +#define NoSupportHiVisionTV 0x0060 +#define NoSupportLCD 0x0058 +#define SupportTV1024 0x0800 /* 301btest */ +#define SupportYPbPr 0x1000 /* 301lv */ +#define InterlaceMode 0x0080 +#define SyncPP 0x0000 +#define SyncPN 0x4000 +#define SyncNP 0x8000 +#define SyncNN 0xC000 + +/* -------------- SetMode Stack/Scratch */ +#define SetSimuScanMode 0x0001 /* VBInfo/CR30 & CR31 */ +#define SwitchToCRT2 0x0002 +#define SetCRT2ToTV1 0x009C +#define SetCRT2ToTV 0x089C +#define SetCRT2ToAVIDEO 0x0004 +#define SetCRT2ToSVIDEO 0x0008 +#define SetCRT2ToSCART 0x0010 +#define SetCRT2ToLCD 0x0020 +#define SetCRT2ToRAMDAC 0x0040 +#define SetCRT2ToHiVisionTV 0x0080 +#define SetCRT2ToLCDA 0x0100 +#define SetInSlaveMode 0x0200 +#define SetNotSimuMode 0x0400 +#define HKEventMode 0x0800 +#define SetCRT2ToYPbPr 0x0800 +#define LoadDACFlag 0x1000 +#define DisableCRT2Display 0x2000 +#define DriverMode 0x4000 +#define SetCRT2ToDualEdge 0x8000 +#define HotKeySwitch 0x8000 + +#define ProgrammingCRT2 0x0001 /* Set Flag */ +#define EnableVCMode 0x0002 +#define SetHKEventMode 0x0004 +#define ReserveTVOption 0x0008 +#define DisableRelocateIO 0x0010 +#define Win9xDOSMode 0x0020 +#define JDOSMode 0x0040 +/* #define SetWin9xforJap 0x0080 // not used now */ +/* #define SetWin9xforKorea 0x0100 // not used now */ +#define GatingCRT 0x0800 +#define DisableChB 0x1000 +#define EnableChB 0x2000 +#define DisableChA 0x4000 +#define EnableChA 0x8000 + +#define SetNTSCTV 0x0000 /* TV Info */ +#define SetPALTV 0x0001 +#define SetNTSCJ 0x0002 +#define SetPALMTV 0x0004 +#define SetPALNTV 0x0008 +#define SetCHTVUnderScan 0x0000 +/* #define SetCHTVOverScan 0x0010 */ +#define SetYPbPrMode525i 0x0020 +#define SetYPbPrMode525p 0x0040 +#define SetYPbPrMode750p 0x0080 +#define SetYPbPrMode1080i 0x0100 +#define SetTVStdMode 0x0200 +#define SetTVLowResolution 0x0400 +#define SetTVSimuMode 0x0800 +#define TVSimuMode 0x0800 +#define RPLLDIV2XO 0x1000 +#define NTSC1024x768 0x2000 +#define SetTVLockMode 0x4000 + +#define LCDVESATiming 0x0001 /* LCD Info/CR37 */ +#define EnableLVDSDDA 0x0002 +#define EnableScalingLCD 0x0008 +#define SetPWDEnable 0x0004 +#define SetLCDtoNonExpanding 0x0010 +#define SetLCDPolarity 0x00e0 +#define SetLCDDualLink 0x0100 +#define SetLCDLowResolution 0x0200 +#define SetLCDStdMode 0x0400 + +#define DefaultLCDCap 0x80ea /* LCD Capability shampoo */ +#define RLVDSDHL00 0x0000 +#define RLVDSDHL01 0x0001 +#define RLVDSDHL10 0x0002 /* default */ +#define RLVDSDHL11 0x0003 +#define EnableLCD24bpp 0x0004 /* default */ +#define DisableLCD24bpp 0x0000 +#define RLVDSClkSFT0 0x0000 +#define RLVDSClkSFT1 0x0008 /* default */ +#define EnableLVDSDCBal 0x0010 +#define DisableLVDSDCBal 0x0000 /* default */ +#define SinglePolarity 0x0020 /* default */ +#define MultiPolarity 0x0000 +#define LCDPolarity 0x00c0 /* default: SyncNN */ +#define LCDSingleLink 0x0000 /* default */ +#define LCDDualLink 0x0100 +#define EnableSpectrum 0x0200 +#define DisableSpectrum 0x0000 /* default */ +#define PWDEnable 0x0400 +#define PWDDisable 0x0000 /* default */ +#define PWMEnable 0x0800 +#define PWMDisable 0x0000 /* default */ +#define EnableVBCLKDRVLOW 0x4000 +#define EnableVBCLKDRVHigh 0x0000 /* default */ +#define EnablePLLSPLOW 0x8000 +#define EnablePLLSPHigh 0x0000 /* default */ + +#define LCDBToA 0x20 /* LCD SetFlag */ +#define StLCDBToA 0x40 +#define LockLCDBToA 0x80 +#define LCDToFull 0x10 +#define AVIDEOSense 0x01 /* CR32 */ +#define SVIDEOSense 0x02 +#define SCARTSense 0x04 +#define LCDSense 0x08 +#define Monitor2Sense 0x10 +#define Monitor1Sense 0x20 +#define HiTVSense 0x40 + +#ifdef NewScratch +#define YPbPrSense 0x80 /* NEW SCRATCH */ +#endif + +#define TVSense 0xc7 + +#define TVOverScan 0x10 /* CR35 */ +#define TVOverScanShift 4 + +#ifdef NewScratch +#define NTSCMode 0x00 +#define PALMode 0x00 +#define NTSCJMode 0x02 +#define PALMNMode 0x0c +#define YPbPrMode 0xe0 +#define YPbPrMode525i 0x00 +#define YPbPrMode525p 0x20 +#define YPbPrMode750p 0x40 +#define YPbPrMode1080i 0x60 +#else /* Old Scratch */ +#define ClearBufferFlag 0x20 +#endif + + +#define LCDRGB18Bit 0x01 /* CR37 */ +#define LCDNonExpanding 0x10 +#define LCDNonExpandingShift 4 +#define LCDSync 0x20 +#define LCDSyncBit 0xe0 /* H/V polarity & sync ID */ +#define LCDSyncShift 6 + +#ifdef NewScratch +#define ScalingLCD 0x08 +#else /* Old Scratch */ +#define ExtChipType 0x0e +#define ExtChip301 0x02 +#define ExtChipLVDS 0x04 +#define ExtChipCH7019 0x06 +#define ScalingLCD 0x10 +#endif + +#define EnableDualEdge 0x01 /* CR38 */ +#define SetToLCDA 0x02 +#ifdef NewScratch +#define SetYPbPr 0x04 +#define DisableChannelA 0x08 +#define DisableChannelB 0x10 +#define ExtChipType 0xe0 +#define ExtChip301 0x20 +#define ExtChipLVDS 0x40 +#define ExtChipCH7019 0x60 +#else /* Old Scratch */ +#define YPbPrSense 0x04 +#define SetYPbPr 0x08 +#define YPbPrMode 0x30 +#define YPbPrMode525i 0x00 +#define YPbPrMode525p 0x10 +#define YPbPrMode750p 0x20 +#define YPbPrMode1080i 0x30 +#define PALMNMode 0xc0 +#endif + +#define BacklightControlBit 0x01 /* CR3A */ +#define Win9xforJap 0x40 +#define Win9xforKorea 0x80 + +#define ForceMDBits 0x07 /* CR3B */ +#define ForceMD_JDOS 0x00 +#define ForceMD_640x400T 0x01 +#define ForceMD_640x350T 0x02 +#define ForceMD_720x400T 0x03 +#define ForceMD_640x480E 0x04 +#define ForceMD_640x400E 0x05 +#define ForceP1Bit 0x10 +#define ForceP2Bit 0x20 +#define EnableForceMDinBIOS 0x40 +#define EnableForceMDinDrv 0x80 + +#ifdef NewScratch /* New Scratch */ +/* ---------------------- VUMA Information */ +#define LCDSettingFromCMOS 0x04 /* CR3C */ +#define TVSettingFromCMOS 0x08 +#define DisplayDeviceFromCMOS 0x10 +#define HKSupportInSBIOS 0x20 +#define OSDSupportInSBIOS 0x40 +#define DisableLogo 0x80 + +/* ---------------------- HK Evnet Definition */ +#define HKEvent 0x0f /* CR3D */ +#define HK_ModeSwitch 0x01 +#define HK_Expanding 0x02 +#define HK_OverScan 0x03 +#define HK_Brightness 0x04 +#define HK_Contrast 0x05 +#define HK_Mute 0x06 +#define HK_Volume 0x07 +#define ModeSwitchStatus 0xf0 +#define ActiveCRT1 0x10 +#define ActiveLCD 0x0020 +#define ActiveTV 0x40 +#define ActiveCRT2 0x80 + +#define TVSwitchStatus 0x1f /* CR3E */ +#define ActiveAVideo 0x01 +#define ActiveSVideo 0x02 +#define ActiveSCART 0x04 +#define ActiveHiTV 0x08 +#define ActiveYPbPr 0x10 + +#define EnableHKEvent 0x01 /* CR3F */ +#define EnableOSDEvent 0x02 +#define StartOSDEvent 0x04 +#define IgnoreHKEvent 0x08 +#define IgnoreOSDEvent 0x10 +#else /* Old Scratch */ +#define OSD_SBIOS 0x02 /* SR17 */ +#define DisableLogo 0x04 +#define SelectKDOS 0x08 +#define KorWinMode 0x10 +#define KorMode3Bit 0x0020 +#define PSCCtrlBit 0x40 +#define NPSCCtrlBitShift 6 +#define BlueScreenBit 0x80 + +#define HKEvent 0x0f /* CR79 */ +#define HK_ModeSwitch 0x01 +#define HK_Expanding 0x02 +#define HK_OverScan 0x03 +#define HK_Brightness 0x04 +#define HK_Contrast 0x05 +#define HK_Mute 0x06 +#define HK_Volume 0x07 +#define ActivePAL 0x0020 +#define ActivePALShift 5 +#define ActiveNonExpanding 0x40 +#define ActiveNonExpandingShift 6 +#define ActiveOverScan 0x80 +#define ActiveOverScanShift 7 + +#define ModeSwitchStatus 0x0b /* SR15 */ +#define ActiveCRT1 0x01 +#define ActiveLCD 0x02 +#define ActiveCRT2 0x08 + +#define TVSwitchStatus 0xf0 /* SR16 */ +#define TVConfigShift 3 +#define ActiveTV 0x01 +#define ActiveYPbPr 0x04 +#define ActiveAVideo 0x10 +#define ActiveSVideo 0x0020 +#define ActiveSCART 0x40 +#define ActiveHiTV 0x80 + +#define EnableHKEvent 0x01 /* CR7A */ +#define EnableOSDEvent 0x02 +#define StartOSDEvent 0x04 +#define CMOSSupport 0x08 +#define HotKeySupport 0x10 +#define IngoreHKOSDEvent 0x20 +#endif + +/* //------------- Misc. Definition */ +#define SelectCRT1Rate 00h +/* #define SelectCRT2Rate 04h */ + +#define DDC1DelayTime 1000 +#ifdef TRUMPION +#define DDC2DelayTime 15 +#else +#define DDC2DelayTime 150 +#endif + +#define R_FACTOR 04Dh +#define G_FACTOR 097h +#define B_FACTOR 01Ch +/* --------------------------------------------------------- */ +/* translated from asm code 301def.h */ +/* */ +/* --------------------------------------------------------- */ +#define LCDDataLen 8 +#define HiTVDataLen 12 +#define TVDataLen 12 +#define LVDSCRT1Len_H 8 +#define LVDSCRT1Len_V 7 +#define LVDSDataLen 6 +#define LVDSDesDataLen 6 +#define LCDDesDataLen 6 +#define LVDSDesDataLen2 8 +#define LCDDesDataLen2 8 +#define CHTVRegLen 16 +#define CHLVRegLen 12 + +#define StHiTVHT 892 +#define StHiTVVT 1126 +#define StHiTextTVHT 1000 +#define StHiTextTVVT 1126 +#define ExtHiTVHT 2100 +#define ExtHiTVVT 1125 +#define NTSCHT 1716 +#define NTSCVT 525 +#define NTSC1024x768HT 1908 +#define NTSC1024x768VT 525 +#define PALHT 1728 +#define PALVT 625 + +#define YPbPrTV525iHT 1716 /* YPbPr */ +#define YPbPrTV525iVT 525 +#define YPbPrTV525pHT 1716 +#define YPbPrTV525pVT 525 +#define YPbPrTV750pHT 1650 +#define YPbPrTV750pVT 750 + +#define CRT2VCLKSel 0xc0 + +#define CRT2Delay1 0x04 /* XGI301 */ +#define CRT2Delay2 0x0A /* 301B,302 */ + + +#define VCLK25_175 0x00 +#define VCLK28_322 0x01 +#define VCLK31_5 0x02 +#define VCLK36 0x03 +#define VCLK40 0x04 +#define VCLK43_163 0x05 +#define VCLK44_9 0x06 +#define VCLK49_5 0x07 +#define VCLK50 0x08 +#define VCLK52_406 0x09 +#define VCLK56_25 0x0A +#define VCLK65 0x0B +#define VCLK67_765 0x0C +#define VCLK68_179 0x0D +#define VCLK72_852 0x0E +#define VCLK75 0x0F +#define VCLK75_8 0x10 +#define VCLK78_75 0x11 +#define VCLK79_411 0x12 +#define VCLK83_95 0x13 +#define VCLK84_8 0x14 +#define VCLK86_6 0x15 +#define VCLK94_5 0x16 +#define VCLK104_998 0x17 +#define VCLK105_882 0x18 +#define VCLK108_2 0x19 +#define VCLK109_175 0x1A +#define VCLK113_309 0x1B +#define VCLK116_406 0x1C +#define VCLK132_258 0x1D +#define VCLK135_5 0x1E +#define VCLK139_054 0x1F +#define VCLK157_5 0x20 +#define VCLK162 0x21 +#define VCLK175 0x22 +#define VCLK189 0x23 +#define VCLK194_4 0x24 +#define VCLK202_5 0x25 +#define VCLK229_5 0x26 +#define VCLK234 0x27 +#define VCLK252_699 0x28 +#define VCLK254_817 0x29 +#define VCLK265_728 0x2A +#define VCLK266_952 0x2B +#define VCLK269_655 0x2C +#define VCLK272_042 0x2D +#define VCLK277_015 0x2E +#define VCLK286_359 0x2F +#define VCLK291_132 0x30 +#define VCLK291_766 0x31 +#define VCLK309_789 0x32 +#define VCLK315_195 0x33 +#define VCLK323_586 0x34 +#define VCLK330_615 0x35 +#define VCLK332_177 0x36 +#define VCLK340_477 0x37 +#define VCLK375_847 0x38 +#define VCLK388_631 0x39 +#define VCLK125_999 0x51 +#define VCLK148_5 0x52 +#define VCLK178_992 0x54 +#define VCLK217_325 0x55 +#define VCLK299_505 0x56 +#define YPbPr750pVCLK 0x57 + +#define TVVCLKDIV2 0x3A +#define TVVCLK 0x3B +#define HiTVVCLKDIV2 0x3C +#define HiTVVCLK 0x3D +#define HiTVSimuVCLK 0x3E +#define HiTVTextVCLK 0x3F +#define VCLK39_77 0x40 +/* #define YPbPr750pVCLK 0x0F */ +#define YPbPr525pVCLK 0x3A +/* #define ;;YPbPr525iVCLK 0x3B */ +/* #define ;;YPbPr525iVCLK_2 0x3A */ +#define NTSC1024VCLK 0x41 +#define VCLK25_175_41 0x42 /* ; ScaleLCD */ +#define VCLK25_175_42 0x43 +#define VCLK28_322_43 0x44 +#define VCLK40_44 0x45 +#define VCLKQVGA_1 0x46 /* ; QVGA */ +#define VCLKQVGA_2 0x47 +#define VCLKQVGA_3 0x48 +#define VCLK35_2 0x49 /* ; 800x480 */ +#define VCLK122_61 0x4A +#define VCLK80_350 0x4B +#define VCLK107_385 0x4C + +#define CHTVVCLK30_2 0x50 /* ;;CHTV */ +#define CHTVVCLK28_1 0x51 +#define CHTVVCLK43_6 0x52 +#define CHTVVCLK26_4 0x53 +#define CHTVVCLK24_6 0x54 +#define CHTVVCLK47_8 0x55 +#define CHTVVCLK31_5 0x56 +#define CHTVVCLK26_2 0x57 +#define CHTVVCLK39 0x58 +#define CHTVVCLK36 0x59 + +#define CH7007TVVCLK30_2 0x00 /* [Billy] 2007/05/18 For CH7007 */ +#define CH7007TVVCLK28_1 0x01 +#define CH7007TVVCLK43_6 0x02 +#define CH7007TVVCLK26_4 0x03 +#define CH7007TVVCLK24_6 0x04 +#define CH7007TVVCLK47_8 0x05 +#define CH7007TVVCLK31_5 0x06 +#define CH7007TVVCLK26_2 0x07 +#define CH7007TVVCLK39 0x08 +#define CH7007TVVCLK36 0x09 + +#define RES320x200 0x00 +#define RES320x240 0x01 +#define RES400x300 0x02 +#define RES512x384 0x03 +#define RES640x400 0x04 +#define RES640x480x60 0x05 +#define RES640x480x72 0x06 +#define RES640x480x75 0x07 +#define RES640x480x85 0x08 +#define RES640x480x100 0x09 +#define RES640x480x120 0x0A +#define RES640x480x160 0x0B +#define RES640x480x200 0x0C +#define RES800x600x56 0x0D +#define RES800x600x60 0x0E +#define RES800x600x72 0x0F +#define RES800x600x75 0x10 +#define RES800x600x85 0x11 +#define RES800x600x100 0x12 +#define RES800x600x120 0x13 +#define RES800x600x160 0x14 +#define RES1024x768x43 0x15 +#define RES1024x768x60 0x16 +#define RES1024x768x70 0x17 +#define RES1024x768x75 0x18 +#define RES1024x768x85 0x19 +#define RES1024x768x100 0x1A +#define RES1024x768x120 0x1B +#define RES1280x1024x43 0x1C +#define RES1280x1024x60 0x1D +#define RES1280x1024x75 0x1E +#define RES1280x1024x85 0x1F +#define RES1600x1200x60 0x20 +#define RES1600x1200x65 0x21 +#define RES1600x1200x70 0x22 +#define RES1600x1200x75 0x23 +#define RES1600x1200x85 0x24 +#define RES1600x1200x100 0x25 +#define RES1600x1200x120 0x26 +#define RES1920x1440x60 0x27 +#define RES1920x1440x65 0x28 +#define RES1920x1440x70 0x29 +#define RES1920x1440x75 0x2A +#define RES1920x1440x85 0x2B +#define RES1920x1440x100 0x2C +#define RES2048x1536x60 0x2D +#define RES2048x1536x65 0x2E +#define RES2048x1536x70 0x2F +#define RES2048x1536x75 0x30 +#define RES2048x1536x85 0x31 +#define RES800x480x60 0x32 +#define RES800x480x75 0x33 +#define RES800x480x85 0x34 +#define RES1024x576x60 0x35 +#define RES1024x576x75 0x36 +#define RES1024x576x85 0x37 +#define RES1280x720x60 0x38 +#define RES1280x720x75 0x39 +#define RES1280x720x85 0x3A +#define RES1280x960x60 0x3B +#define RES720x480x60 0x3C +#define RES720x576x56 0x3D +#define RES856x480x79I 0x3E +#define RES856x480x60 0x3F +#define RES1280x768x60 0x40 +#define RES1400x1050x60 0x41 +#define RES1152x864x60 0x42 +#define RES1152x864x75 0x43 +#define RES1024x768x160 0x44 +#define RES1280x960x75 0x45 +#define RES1280x960x85 0x46 +#define RES1280x960x120 0x47 + +#define LFBDRAMTrap 0x30 +#endif diff --git a/drivers/staging/xgifb/vb_ext.c b/drivers/staging/xgifb/vb_ext.c new file mode 100644 index 000000000000..49b39ee93a89 --- /dev/null +++ b/drivers/staging/xgifb/vb_ext.c @@ -0,0 +1,1370 @@ +#include "osdef.h" + + + + +#ifdef WIN2000 + +#include <dderror.h> +#include <devioctl.h> +#include <miniport.h> +#include <ntddvdeo.h> +#include <video.h> +#include "xgiv.h" +#include "dd_i2c.h" +#include "tools.h" +#endif /* WIN2000 */ + +#ifdef LINUX_XF86 +#include "xf86.h" +#include "xf86PciInfo.h" +#include "xgi.h" +#include "xgi_regs.h" +#endif + +#ifdef LINUX_KERNEL +#include <linux/version.h> +#include <asm/io.h> +#include <linux/types.h> +#include "XGIfb.h" +/*#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#include <video/XGIfb.h> +#else +#include <linux/XGIfb.h> +#endif*/ +#endif + + + +#include "vb_def.h" +#include "vgatypes.h" +#include "vb_struct.h" +#include "vb_util.h" +#include "vb_setmode.h" +#include "vb_ext.h" +extern UCHAR XGI330_SoftSetting; +extern UCHAR XGI330_OutputSelect; +extern USHORT XGI330_RGBSenseData2; +extern USHORT XGI330_YCSenseData2; +extern USHORT XGI330_VideoSenseData2; +#ifdef WIN2000 +extern UCHAR SenseCHTV(PHW_DEVICE_EXTENSION pHWDE); /* 2007/05/17 Billy */ +#endif +void XGI_GetSenseStatus( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ); +BOOLEAN XGINew_GetPanelID(PVB_DEVICE_INFO pVBInfo); +USHORT XGINew_SenseLCD(PXGI_HW_DEVICE_INFO,PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGINew_GetLCDDDCInfo(PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo); +void XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE ) ; +BOOLEAN XGINew_BridgeIsEnable(PXGI_HW_DEVICE_INFO,PVB_DEVICE_INFO pVBInfo ); +BOOLEAN XGINew_Sense(USHORT tempbx,USHORT tempcx, PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGINew_SenseHiTV( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ; + +/************************************************************** + Dynamic Sense +*************************************************************/ + +void XGI_WaitDisplay(void); +BOOLEAN XGI_Is301C(PVB_DEVICE_INFO); +BOOLEAN XGI_Is301LV(PVB_DEVICE_INFO); + +#ifdef WIN2000 +UCHAR XGI_SenseLCD(PHW_DEVICE_EXTENSION, PVB_DEVICE_INFO); +UCHAR XGI_GetLCDDDCInfo(PHW_DEVICE_EXTENSION,PVB_DEVICE_INFO); + +extern BOOL bGetDdcInfo( +PHW_DEVICE_EXTENSION pHWDE, +ULONG ulWhichOne, +PUCHAR pjQueryBuffer, +ULONG ulBufferSize + ); + +#endif + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_Is301B */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGINew_Is301B( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT flag ; + + flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) ; + + if ( flag > 0x0B0 ) + return( 0 ) ; /* 301b */ + else + return( 1 ) ; +} + +/* --------------------------------------------------------------------- */ +/* Function : XGI_Is301C */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_Is301C( PVB_DEVICE_INFO pVBInfo ) +{ + if ( ( XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) & 0xF0 ) == 0xC0 ) + return( 1 ) ; + + if ( XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) >= 0xD0 ) + { + if ( XGINew_GetReg1( pVBInfo->Part4Port , 0x39 ) == 0xE0 ) + return( 1 ) ; + } + + return( 0 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_Is301LV */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_Is301LV( PVB_DEVICE_INFO pVBInfo ) +{ + if ( XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) >= 0xD0 ) + { + if ( XGINew_GetReg1( pVBInfo->Part4Port , 0x39 ) == 0xFF ) + { + return( 1 ) ; + } + } + return( 0 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_Sense */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGINew_Sense( USHORT tempbx , USHORT tempcx, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT temp , i , tempch ; + + temp = tempbx & 0xFF ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x11 , temp ) ; + temp = ( tempbx & 0xFF00 ) >> 8 ; + temp |= ( tempcx & 0x00FF ) ; + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x10 , ~0x1F , temp ) ; + + for( i = 0 ; i < 10 ; i++ ) + XGI_LongWait( pVBInfo) ; + + tempch = ( tempcx & 0x7F00 ) >> 8 ; + temp = XGINew_GetReg1( pVBInfo->Part4Port , 0x03 ) ; + temp = temp ^ ( 0x0E ) ; + temp &= tempch ; + + if ( temp > 0 ) + return( 1 ) ; + else + return( 0 ) ; +} + +#ifdef WIN2000 +/* --------------------------------------------------------------------- */ +/* Function : XGI_SenseLCD */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +UCHAR XGI_SenseLCD( PHW_DEVICE_EXTENSION pHWDE, PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempax , tempbx , tempcx ; + UCHAR SoftSetting = XGI330_SoftSetting ; + + if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV ) ) + return( 1 ) ; + + + if ( SoftSetting & HotPlugFunction ) /* Hot Plug Detection */ + { + XGINew_SetRegAND( pVBInfo->Part4Port , 0x0F , 0x3F ) ; + tempbx = 0 ; + tempcx = 0x9010 ; + if ( XGINew_Sense( tempbx , tempcx, pVBInfo ) ) + return( 1 ) ; + + return( 0 ) ; + } + else /* Get LCD Info from EDID */ + return(XGI_GetLCDDDCInfo(pHWDE, pVBInfo)); +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetLCDDDCInfo */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +UCHAR XGI_GetLCDDDCInfo( PHW_DEVICE_EXTENSION pHWDE , PVB_DEVICE_INFO pVBInfo) +{ + UCHAR tempah , tempbl , tempbh ; + USHORT tempbx , temp ; + UCHAR pjEDIDBuf[ 256 ] ; + ULONG ulBufferSize = 256 ; + UCHAR bMASK_OUTPUTSTATE_CRT2LCD = 2 ; /* 0423 shampoo */ + + bGetDdcInfo( pHWDE , MASK_OUTPUTSTATE_CRT2LCD , pjEDIDBuf , ulBufferSize ) ; + if ( ( *( ( PULONG )pjEDIDBuf ) == 0xFFFFFF00 ) && ( *( ( PULONG )( pjEDIDBuf + 4 ) ) == 0x00FFFFFF ) ) + { + tempah = Panel1024x768 ; + tempbl=( *( pjEDIDBuf + 0x3A ) ) & 0xf0 ; + + if ( tempbl != 0x40 ) + { + tempah = Panel1600x1200 ; + if ( tempbl != 0x60 ) + { + tempah = Panel1280x1024 ; + tempbh = ( *( pjEDIDBuf + 0x3B ) ) ; + if ( tempbh != 0x00 ) + { + tempah = Panel1280x960 ; + if ( tempbh != 0x0C0 ) + { + tempbx = ( ( *( pjEDIDBuf + 0x24 ) ) << 8 ) | ( *( pjEDIDBuf + 0x23 ) ) ; + tempah = Panel1280x1024 ; + if ( !( tempbx & 0x0100 ) ) + { + tempah = Panel1024x768 ; + if ( !( tempbx & 0x0E00 ) ) + { + tempah = Panel1280x1024 ; + } + } + } + + if ( tempbx & 0x00FF ) + { + temp = ScalingLCD ; + XGINew_SetRegOR( pVBInfo->P3d4 , 0x37 , temp ) ; + } + } + } + } + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x36 , ( ~0x07 ) , tempah ) ; + tempah = ( ( *( pjEDIDBuf + 0x47 ) ) & 0x06 ) ; /* Polarity */ + tempah = ( tempah ^ 0x06 ) << 4 ; + tempah |= LCDSync ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , ( ~LCDSyncBit ) , tempah ) ; + tempbh= XGINew_GetReg1( pVBInfo->P3d4 , 0x36 ) ; + tempbh &= 0x07 ; + if ( tempbh == Panel1280x960 ) + XGINew_SetRegAND( pVBInfo->P3d4 , 0x37 , 0x0E ) ; + } + else if ( *pjEDIDBuf == 0x20 ) + { + tempah = Panel1024x768 ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x36 , ( ~0x07 ) , tempah ) ; + } + else + { + return( 0 ) ; + } + + return( 1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_DySense */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_DySense( PHW_DEVICE_EXTENSION pHWDE , PUCHAR ujConnectStatus) +{ + UCHAR pre_CRD,pre_SR1E , pre_Part2_0 , pre_Part4_D ; + USHORT tempax , tempbx , tempcx , pushax , temp ; + VB_DEVICE_INFO VBINF; + PVB_DEVICE_INFO pVBInfo = &VBINF; + UCHAR OutputSelect = XGI330_OutputSelect ; + PXGI_HW_DEVICE_INFO HwDeviceExtension= pHWDE->pXGIHWDE ; + UCHAR bConnectStatus = 0 ; + pVBInfo->BaseAddr = HwDeviceExtension->pjIOAddress ; + pVBInfo->ROMAddr = pHWDE->pjVirtualRomBase ; + + pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ; + pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ; + pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ; + pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ; + pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ; + pushax = XGINew_GetReg1( pVBInfo->P3d4 , 0x17 ) ; /* 0512 Fix Dysense hanged */ + temp = ( pushax & 0x00FF ) | 0x80 ; + XGINew_SetRegOR( pVBInfo->P3d4 , 0x17 , temp ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ; + /* beginning of dynamic sense CRT1 */ + + pVBInfo->IF_DEF_CH7007 = 0; + if (pHWDE->bCH7007) + { + InitTo330Pointer( pHWDE->pXGIHWDE->jChipType, pVBInfo ) ; + HwDeviceExtension->pDevice = (PVOID)pHWDE; + pVBInfo->IF_DEF_CH7007 = 1; + /* [Billy] 2007/05/14 For CH7007 */ + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + bConnectStatus = SenseCHTV(HwDeviceExtension->pDevice) ; /* 07/05/28 */ + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~0x03 , (UCHAR)bConnectStatus ) ; + } + } + if(( pHWDE->jChipID >= XG40 ) || ( pHWDE->jChipID >= XG20 )) + { + + if ( pHWDE->jChipID >= XG40 ) + XGINew_SetReg1( pVBInfo->P3d4 , 0x57 , 0x4A ) ; /* write sense pattern 30->4a */ + else + XGINew_SetReg1( pVBInfo->P3d4 , 0x57 , 0x5F ) ; /* write sense pattern */ + + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x53 , 0xFF , 0x02 ) ; /* enable sense DAC */ + XGI_WaitDisply(pVBInfo) ; + + if(XGINew_GetReg2( pVBInfo->P3c2 ) & 0x10 ) + bConnectStatus |= Monitor1Sense ; + + XGINew_SetRegAND( pVBInfo->P3d4 , 0x53 , 0xFD ) ; /* disable sense DAC */ + XGINew_SetRegAND( pVBInfo->P3d4 , 0x57 , 0x00 ) ; /* clear sense pattern */ + + + /* ---------- End of dynamic sense CRT1 ----------- */ + + /* ---------- beginning of dynamic sense VB ------------ */ + pre_SR1E = XGINew_GetReg1( pVBInfo->P3c4 , 0x1E ) ; + XGINew_SetRegOR( pVBInfo->P3c4 , 0x1E , 0x20 ) ; /* Enable CRT2,work-a-round for 301B/301LV/302LV */ + pre_Part2_0 = XGINew_GetReg1( pVBInfo->Part2Port , 0x00 ) ; + pre_Part4_D = XGINew_GetReg1( pVBInfo->Part4Port , 0x0D ) ; + + if ( XGI_Is301C( pVBInfo ) ) /* 301C only */ + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x0D , ~0x07 , 0x01 ) ; /* Set Part4 0x0D D[2:0] to 001b */ + + /* tempax = 0 ; */ + if ( !XGI_Is301LV( pVBInfo ) ) + { + tempbx = XGI330_RGBSenseData2 ; + tempcx = 0x0E08 ; + if(XGINew_Sense( tempbx , tempcx, pVBInfo ) ) + { + bConnectStatus |= Monitor2Sense ; + if ( OutputSelect & SetSCARTOutput ) + { + bConnectStatus ^= ( Monitor2Sense | SCARTSense ) ; + } + } + } + if ( XGI_Is301C( pVBInfo ) ) /* 301C only */ + XGINew_SetRegOR( pVBInfo->Part4Port , 0x0D , 0x04 ) ; /* Set Part4 0x0D D[2]=1 for dynamic sense */ + + if ( ( XGINew_Is301B( pVBInfo ) ) ) + XGINew_SetRegOR( pVBInfo->Part2Port , 0x00 , 0x0C ) ; /* ????????? */ + + if ( XGINew_SenseHiTV( HwDeviceExtension , pVBInfo) ) /* add by kuku for Dysense HiTV //start */ + { + bConnectStatus|= YPbPrSense ; + } + else + { + tempbx = XGI330_YCSenseData2 ; /* Y/C Sense Data Ptr */ + tempcx = 0x0604 ; + if ( XGINew_Sense( tempbx , tempcx , pVBInfo) ) + bConnectStatus |= SVIDEOSense ; + + if ( OutputSelect & BoardTVType ) + { + tempbx = XGI330_VideoSenseData2 ; + tempcx = 0x0804 ; + if ( XGINew_Sense(tempbx , tempcx, pVBInfo) ) + bConnectStatus|= AVIDEOSense ; + } + else + { + if ( !( bConnectStatus & SVIDEOSense ) ) + { + tempbx = XGI330_VideoSenseData2 ; + tempcx = 0x0804 ; + if ( XGINew_Sense( tempbx , tempcx, pVBInfo ) ) + bConnectStatus |= AVIDEOSense ; + } + } + } /* end */ + /* DySenseVBCnt */ + + tempbx = 0 ; + tempcx = 0 ; + XGINew_Sense(tempbx , tempcx, pVBInfo ) ; + + if ( !( bConnectStatus & Monitor2Sense ) ) + { + if ( XGI_SenseLCD( pHWDE , pVBInfo ) ) + bConnectStatus |= LCDSense ; + } + + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~( AVIDEOSense | SVIDEOSense | LCDSense | Monitor2Sense | Monitor1Sense ) , bConnectStatus ) ; + + XGINew_SetReg1( pVBInfo->Part4Port , 0x0D , pre_Part4_D ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , pre_Part2_0 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x1E , pre_SR1E ) ; + + if ( XGI_Is301C( pVBInfo ) ) /* 301C only */ + { + tempax = XGINew_GetReg1( pVBInfo->Part2Port , 0x00 ) ; + if ( tempax & 0x20 ) + { + /* Reset VBPro */ + for( tempcx = 2 ; tempcx > 0 ; tempcx-- ) + { + tempax ^= 0x20 ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , tempax ) ; + } + } + } + /* End of dynamic sense VB */ + } + else + { + XGI_SenseCRT1(pVBInfo) ; + XGI_GetSenseStatus( HwDeviceExtension, pVBInfo ) ; /* sense CRT2 */ + bConnectStatus = XGINew_GetReg1( pVBInfo->P3d4 , 0x32 ) ; + } + temp = pushax & 0x00FF ; /* 0512 Fix Dysense hanged */ + XGINew_SetReg1( pVBInfo->P3d4 , 0x17 , temp ) ; + if ( bConnectStatus ) + { + *ujConnectStatus = bConnectStatus ; + return( 1 ) ; + } + else + return( 0 ) ; +} + +#endif /* WIN2000 */ + +/* --------------------------------------------------------------------- */ +/* Function : XGISetDPMS */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +VOID XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE ) +{ + USHORT ModeNo, ModeIdIndex ; + UCHAR temp ; + VB_DEVICE_INFO VBINF; + PVB_DEVICE_INFO pVBInfo = &VBINF; + pVBInfo->BaseAddr = (ULONG)pXGIHWDE->pjIOAddress ; + pVBInfo->ROMAddr = pXGIHWDE->pjVirtualRomBase ; + + + pVBInfo->IF_DEF_LVDS = 0 ; + pVBInfo->IF_DEF_CH7005 = 0 ; + pVBInfo->IF_DEF_HiVision = 1 ; + pVBInfo->IF_DEF_LCDA = 1 ; + pVBInfo->IF_DEF_CH7017 = 0 ; + pVBInfo->IF_DEF_YPbPr = 1 ; + pVBInfo->IF_DEF_CRT2Monitor = 0 ; + pVBInfo->IF_DEF_VideoCapture = 0 ; + pVBInfo->IF_DEF_ScaleLCD = 0 ; + pVBInfo->IF_DEF_OEMUtil = 0 ; + pVBInfo->IF_DEF_PWD = 0 ; + + InitTo330Pointer( pXGIHWDE->jChipType, pVBInfo ) ; + ReadVBIOSTablData( pXGIHWDE->jChipType , pVBInfo) ; + + pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ; + pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ; + pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ; + pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ; + pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ; + pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ; + pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ; + pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ; + pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ; + pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ; + pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ; + pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ; + pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ; + pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ; + pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ; + pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ; + pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ; + + if ( pXGIHWDE->jChipType == XG27 ) + { + if ( ( XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) & 0xE0 ) == 0xC0 ) + { + if ( XGINew_GetReg1( pVBInfo->P3d4 , 0x30 ) & 0x20 ) + { + pVBInfo->IF_DEF_LVDS = 1 ; + } + } + } + + if ( pVBInfo->IF_DEF_CH7007 == 0 ) + { + XGINew_SetModeScratch ( pXGIHWDE , pVBInfo ) ; + } + XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ; /* 1.Openkey */ + XGI_UnLockCRT2( pXGIHWDE , pVBInfo) ; + ModeNo = XGINew_GetReg1( pVBInfo->P3d4 , 0x34 ) ; + XGI_SearchModeID( ModeNo , &ModeIdIndex, pVBInfo ) ; + XGI_GetVGAType( pXGIHWDE , pVBInfo ) ; + + if ( ( pXGIHWDE->ujVBChipID == VB_CHIP_301 ) || ( pXGIHWDE->ujVBChipID == VB_CHIP_302 ) || ( pVBInfo->IF_DEF_CH7007 == 1 )) + { + XGI_GetVBType( pVBInfo ) ; + XGI_GetVBInfo( ModeNo , ModeIdIndex , pXGIHWDE, pVBInfo ) ; + XGI_GetTVInfo( ModeNo , ModeIdIndex, pVBInfo ) ; + XGI_GetLCDInfo( ModeNo , ModeIdIndex, pVBInfo ) ; + } + + if ( VESA_POWER_STATE == 0x00000400 ) + XGINew_SetReg1( pVBInfo->Part4Port , 0x31 , ( UCHAR )( XGINew_GetReg1( pVBInfo->Part4Port , 0x31 ) & 0xFE ) ) ; + else + XGINew_SetReg1( pVBInfo->Part4Port , 0x31 , ( UCHAR )( XGINew_GetReg1( pVBInfo->Part4Port , 0x31 ) | 0x01 ) ) ; + + temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x1f ) ; + temp &= 0x3f ; + switch ( VESA_POWER_STATE ) + { + case 0x00000000: /* on */ + if ( ( pXGIHWDE->ujVBChipID == VB_CHIP_301 ) || ( pXGIHWDE->ujVBChipID == VB_CHIP_302 ) ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0x00 ) ) ; + XGI_EnableBridge( pXGIHWDE, pVBInfo ) ; + } + else + { + if ( pXGIHWDE->jChipType == XG21 ) + { + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + XGI_XG21BLSignalVDD( 0x01 , 0x01, pVBInfo ) ; /* LVDS VDD on */ + XGI_XG21SetPanelDelay( 2,pVBInfo ) ; + } + } + if ( pXGIHWDE->jChipType == XG27 ) + { + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + XGI_XG27BLSignalVDD( 0x01 , 0x01, pVBInfo ) ; /* LVDS VDD on */ + XGI_XG21SetPanelDelay( 2,pVBInfo ) ; + } + } + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x1F , ~0xC0 , 0x00 ) ; + XGINew_SetRegAND( pVBInfo->P3c4 , 0x01 , ~0x20 ) ; /* CRT on */ + + if ( pXGIHWDE->jChipType == XG21 ) + { + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ; + if ( temp & 0xE0 ) + { + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x09 , ~0x80 , 0x80 ) ; /* DVO ON */ + XGI_SetXG21FPBits( pVBInfo ); + XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x20 ) ; /* Enable write GPIOF */ + /*XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x48 , ~0x20 , 0x20 ) ;*/ /* LCD Display ON */ + } + XGI_XG21BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* LVDS signal on */ + XGI_DisplayOn( pXGIHWDE, pVBInfo ); + } + if ( pXGIHWDE->jChipType == XG27 ) + { + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ; + if ( temp & 0xE0 ) + { + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x09 , ~0x80 , 0x80 ) ; /* DVO ON */ + XGI_SetXG27FPBits( pVBInfo ); + XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x20 ) ; /* Enable write GPIOF */ + /*XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x48 , ~0x20 , 0x20 ) ;*/ /* LCD Display ON */ + } + XGI_XG27BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* LVDS signal on */ + XGI_DisplayOn( pXGIHWDE, pVBInfo ); + } + } + break ; + case 0x00000100: /* standby */ + if ( pXGIHWDE->jChipType >= XG21 ) + { + XGI_DisplayOff( pXGIHWDE, pVBInfo ); + } + + XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0x40 ) ) ; + break ; + case 0x00000200: /* suspend */ + if ( pXGIHWDE->jChipType == XG21 ) + { + XGI_DisplayOff( pXGIHWDE, pVBInfo ); + XGI_XG21BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* LVDS signal off */ + } + if ( pXGIHWDE->jChipType == XG27 ) + { + XGI_DisplayOff( pXGIHWDE, pVBInfo ); + XGI_XG27BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* LVDS signal off */ + } + XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0x80 ) ) ; + break ; + case 0x00000400: /* off */ + if ( (pXGIHWDE->ujVBChipID == VB_CHIP_301 ) || ( pXGIHWDE->ujVBChipID == VB_CHIP_302 ) ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0xc0 ) ) ; + XGI_DisableBridge( pXGIHWDE, pVBInfo ) ; + } + else + { + if ( pXGIHWDE->jChipType == XG21 ) + { + XGI_DisplayOff( pXGIHWDE, pVBInfo ); + + XGI_XG21BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* LVDS signal off */ + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ; + if ( temp & 0xE0 ) + { + XGINew_SetRegAND( pVBInfo->P3c4 , 0x09 , ~0x80 ) ; /* DVO Off */ + XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x20 ) ; /* Enable write GPIOF */ + /*XGINew_SetRegAND( pVBInfo->P3d4 , 0x48 , ~0x20 ) ;*/ /* LCD Display OFF */ + } + } + if ( pXGIHWDE->jChipType == XG27 ) + { + XGI_DisplayOff( pXGIHWDE, pVBInfo ); + + XGI_XG27BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* LVDS signal off */ + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ; + if ( temp & 0xE0 ) + { + XGINew_SetRegAND( pVBInfo->P3c4 , 0x09 , ~0x80 ) ; /* DVO Off */ + } + } + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x1F , ~0xC0 , 0xC0 ) ; + XGINew_SetRegOR( pVBInfo->P3c4 , 0x01 , 0x20 ) ; /* CRT Off */ + + if ( ( pXGIHWDE->jChipType == XG21 ) && ( pVBInfo->IF_DEF_LVDS == 1 ) ) + { + XGI_XG21SetPanelDelay( 4,pVBInfo ) ; + XGI_XG21BLSignalVDD( 0x01 , 0x00, pVBInfo ) ; /* LVDS VDD off */ + XGI_XG21SetPanelDelay( 5,pVBInfo ) ; + } + if ( ( pXGIHWDE->jChipType == XG27 ) && ( pVBInfo->IF_DEF_LVDS == 1 ) ) + { + XGI_XG21SetPanelDelay( 4,pVBInfo ) ; + XGI_XG27BLSignalVDD( 0x01 , 0x00, pVBInfo ) ; /* LVDS VDD off */ + XGI_XG21SetPanelDelay( 5,pVBInfo ) ; + } + } + break ; + + default: + break ; + } + XGI_LockCRT2( pXGIHWDE , pVBInfo ) ; +} + + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetSenseStatus */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetSenseStatus( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempax = 0 , tempbx , tempcx , temp , + P2reg0 = 0 , SenseModeNo = 0 , OutputSelect = *pVBInfo->pOutputSelect , + ModeIdIndex , i ; + pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ; + + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + tempax = XGINew_GetReg1( pVBInfo->P3c4 , 0x1A ) ; /* ynlai 02/27/2002 */ + tempbx = XGINew_GetReg1( pVBInfo->P3c4 , 0x1B ) ; + tempax = ( ( tempax & 0xFE ) >> 1 ) | ( tempbx << 8 ) ; + if ( tempax == 0x00 ) + { /* Get Panel id from DDC */ + temp = XGINew_GetLCDDDCInfo( HwDeviceExtension, pVBInfo ) ; + if ( temp == 1 ) + { /* LCD connect */ + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x39 , 0xFF , 0x01 ) ; /* set CR39 bit0="1" */ + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , 0xEF , 0x00 ) ; /* clean CR37 bit4="0" */ + temp = LCDSense ; + } + else + { /* LCD don't connect */ + temp = 0 ; + } + } + else + { + XGINew_GetPanelID(pVBInfo) ; + temp = LCDSense ; + } + + tempbx = ~( LCDSense | AVIDEOSense | SVIDEOSense ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , tempbx , temp ) ; + } + else + { /* for 301 */ + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { /* for HiVision */ + tempax = XGINew_GetReg1( pVBInfo->P3c4 , 0x38 ) ; + temp = tempax & 0x01 ; + tempax = XGINew_GetReg1( pVBInfo->P3c4 , 0x3A ) ; + temp = temp | ( tempax & 0x02 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , 0xA0 , temp ) ; + } + else + { + if ( XGI_BridgeIsOn( pVBInfo ) ) + { + P2reg0 = XGINew_GetReg1( pVBInfo->Part2Port , 0x00 ) ; + if ( !XGINew_BridgeIsEnable( HwDeviceExtension, pVBInfo ) ) + { + SenseModeNo = 0x2e ; + /* XGINew_SetReg1( pVBInfo->P3d4 , 0x30 , 0x41 ) ; */ + /* XGISetModeNew( HwDeviceExtension , 0x2e ) ; // ynlai InitMode */ + + temp = XGI_SearchModeID( SenseModeNo , &ModeIdIndex, pVBInfo ) ; + XGI_GetVGAType( HwDeviceExtension , pVBInfo) ; + XGI_GetVBType( pVBInfo ) ; + pVBInfo->SetFlag = 0x00 ; + pVBInfo->ModeType = ModeVGA ; + pVBInfo->VBInfo = SetCRT2ToRAMDAC | LoadDACFlag | SetInSlaveMode ; + XGI_GetLCDInfo( 0x2e , ModeIdIndex, pVBInfo ) ; + XGI_GetTVInfo( 0x2e , ModeIdIndex, pVBInfo ) ; + XGI_EnableBridge( HwDeviceExtension, pVBInfo ) ; + XGI_SetCRT2Group301( SenseModeNo , HwDeviceExtension, pVBInfo ) ; + XGI_SetCRT2ModeRegs( 0x2e , HwDeviceExtension, pVBInfo ) ; + /* XGI_DisableBridge( HwDeviceExtension, pVBInfo ) ; */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x01 , 0xDF , 0x20 ) ; /* Display Off 0212 */ + for( i = 0 ; i < 20 ; i++ ) + { + XGI_LongWait(pVBInfo) ; + } + } + XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , 0x1c ) ; + tempax = 0 ; + tempbx = *pVBInfo->pRGBSenseData ; + + if ( !( XGINew_Is301B( pVBInfo ) ) ) + { + tempbx = *pVBInfo->pRGBSenseData2 ; + } + + tempcx = 0x0E08 ; + if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) ) + { + if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) ) + { + tempax |= Monitor2Sense ; + } + } + + if ( pVBInfo->VBType & VB_XGI301C) + { + XGINew_SetRegOR( pVBInfo->Part4Port , 0x0d , 0x04 ) ; + } + + if ( XGINew_SenseHiTV( HwDeviceExtension , pVBInfo) ) /* add by kuku for Multi-adapter sense HiTV */ + { + tempax |= HiTVSense ; + if ( ( pVBInfo->VBType & VB_XGI301C ) ) + { + tempax ^= ( HiTVSense | YPbPrSense ) ; + } + } + + if ( !( tempax & ( HiTVSense | YPbPrSense ) ) ) /* start */ + { + + tempbx = *pVBInfo->pYCSenseData ; + + if ( !( XGINew_Is301B( pVBInfo ) ) ) + { + tempbx=*pVBInfo->pYCSenseData2; + } + + tempcx = 0x0604 ; + if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) ) + { + if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) ) + { + tempax |= SVIDEOSense ; + } + } + + if ( OutputSelect & BoardTVType ) + { + tempbx = *pVBInfo->pVideoSenseData ; + + if ( !( XGINew_Is301B( pVBInfo ) ) ) + { + tempbx = *pVBInfo->pVideoSenseData2 ; + } + + tempcx = 0x0804 ; + if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) ) + { + if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) ) + { + tempax |= AVIDEOSense ; + } + } + } + else + { + if ( !( tempax & SVIDEOSense ) ) + { + tempbx = *pVBInfo->pVideoSenseData ; + + if ( !( XGINew_Is301B( pVBInfo ) ) ) + { + tempbx=*pVBInfo->pVideoSenseData2; + } + + tempcx = 0x0804 ; + if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) ) + { + if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) ) + { + tempax |= AVIDEOSense ; + } + } + } + } + } + } /* end */ + if ( !( tempax & Monitor2Sense ) ) + { + if ( XGINew_SenseLCD( HwDeviceExtension, pVBInfo ) ) + { + tempax |= LCDSense ; + } + } + tempbx = 0 ; + tempcx = 0 ; + XGINew_Sense(tempbx , tempcx, pVBInfo ) ; + + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~0xDF , tempax ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , P2reg0 ) ; + + if ( !( P2reg0 & 0x20 ) ) + { + pVBInfo->VBInfo = DisableCRT2Display ; + /* XGI_SetCRT2Group301( SenseModeNo , HwDeviceExtension, pVBInfo ) ; */ + } + } + } + XGI_DisableBridge( HwDeviceExtension, pVBInfo ) ; /* shampoo 0226 */ + +} + + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SenseLCD */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGINew_SenseLCD( PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE_INFO pVBInfo) +{ + /* USHORT SoftSetting ; */ + USHORT temp ; + + if ( ( HwDeviceExtension->jChipType >= XG20 ) || ( HwDeviceExtension->jChipType >= XG40 ) ) + temp = 0 ; + else + temp=XGINew_GetPanelID(pVBInfo) ; + + if( !temp ) + temp = XGINew_GetLCDDDCInfo( HwDeviceExtension, pVBInfo ) ; + + return( temp ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_GetLCDDDCInfo */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGINew_GetLCDDDCInfo( PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo) +{ + USHORT temp ; + + /* add lcd sense */ + if ( HwDeviceExtension->ulCRT2LCDType == LCD_UNKNOWN ) + { + return( 0 ) ; + } + else + { + temp = ( USHORT )HwDeviceExtension->ulCRT2LCDType ; + switch( HwDeviceExtension->ulCRT2LCDType ) + { + case LCD_INVALID: + case LCD_800x600: + case LCD_1024x768: + case LCD_1280x1024: + break ; + + case LCD_640x480: + case LCD_1024x600: + case LCD_1152x864: + case LCD_1280x960: + case LCD_1152x768: + temp = 0 ; + break ; + + case LCD_1400x1050: + case LCD_1280x768: + case LCD_1600x1200: + break ; + + case LCD_1920x1440: + case LCD_2048x1536: + temp = 0 ; + break ; + + default: + break ; + } + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x36 , 0xF0 , temp ) ; + return( 1 ) ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGINew_GetPanelID(PVB_DEVICE_INFO pVBInfo ) +{ + USHORT PanelTypeTable[ 16 ] = { SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType00 , + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType01 , + SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType02 , + SyncNN | PanelRGB18Bit | Panel640x480 | _PanelType03 , + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType04 , + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType05 , + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType06 , + SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType07 , + SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType08 , + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType09 , + SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType0A , + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0B , + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0C , + SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType0D , + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0E , + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0F } ; + USHORT tempax , tempbx , temp ; + /* USHORT return_flag ; */ + + tempax = XGINew_GetReg1( pVBInfo->P3c4 , 0x1A ) ; + tempbx = tempax & 0x1E ; + + if ( tempax == 0 ) + return( 0 ) ; + else + { +/* + if ( !( tempax & 0x10 ) ) + { + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + tempbx = 0 ; + temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x38 ) ; + if ( temp & 0x40 ) + tempbx |= 0x08 ; + if ( temp & 0x20 ) + tempbx |= 0x02 ; + if ( temp & 0x01 ) + tempbx |= 0x01 ; + + temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x39 ) ; + if ( temp & 0x80 ) + tempbx |= 0x04 ; + } + else + { + return( 0 ) ; + } + } +*/ + + tempbx = tempbx >> 1 ; + temp = tempbx & 0x00F ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x36 , temp ) ; + tempbx-- ; + tempbx = PanelTypeTable[ tempbx ] ; + + temp = ( tempbx & 0xFF00 ) >> 8 ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , ~( LCDSyncBit | LCDRGB18Bit ) , temp ) ; + return( 1 ) ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_BridgeIsEnable */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGINew_BridgeIsEnable( PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE_INFO pVBInfo) +{ + USHORT flag ; + + if ( XGI_BridgeIsOn( pVBInfo ) == 0 ) + { + flag = XGINew_GetReg1( pVBInfo->Part1Port , 0x0 ) ; + + if ( flag & 0x050 ) + { + return( 1 ) ; + } + else + { + return( 0 ) ; + } + + } + return( 0 ) ; +} + +/* ------------------------------------------------------ */ +/* Function : XGINew_SenseHiTV */ +/* Input : */ +/* Output : */ +/* Description : */ +/* ------------------------------------------------------ */ +BOOLEAN XGINew_SenseHiTV( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempbx , tempcx , temp , i , tempch; + + tempbx = *pVBInfo->pYCSenseData2 ; + + tempcx = 0x0604 ; + + temp = tempbx & 0xFF ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x11 , temp ) ; + temp = ( tempbx & 0xFF00 ) >> 8 ; + temp |= ( tempcx & 0x00FF ) ; + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x10 , ~0x1F , temp ) ; + + for( i = 0 ; i < 10 ; i++ ) + XGI_LongWait(pVBInfo) ; + + tempch = ( tempcx & 0xFF00 ) >> 8; + temp = XGINew_GetReg1( pVBInfo->Part4Port , 0x03 ) ; + temp = temp ^ ( 0x0E ) ; + temp &= tempch ; + + if ( temp != tempch ) + return( 0 ) ; + + tempbx = *pVBInfo->pVideoSenseData2 ; + + tempcx = 0x0804 ; + temp = tempbx & 0xFF ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x11 , temp ) ; + temp = ( tempbx & 0xFF00 ) >> 8 ; + temp |= ( tempcx & 0x00FF ) ; + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x10 , ~0x1F , temp ) ; + + for( i = 0 ; i < 10 ; i++ ) + XGI_LongWait(pVBInfo) ; + + tempch = ( tempcx & 0xFF00 ) >> 8; + temp = XGINew_GetReg1( pVBInfo->Part4Port , 0x03 ) ; + temp = temp ^ ( 0x0E ) ; + temp &= tempch ; + + if ( temp != tempch ) + return( 0 ) ; + else + { + tempbx = 0x3FF ; + tempcx = 0x0804 ; + temp = tempbx & 0xFF ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x11 , temp ) ; + temp = ( tempbx & 0xFF00 ) >> 8 ; + temp |= ( tempcx & 0x00FF ) ; + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x10 , ~0x1F , temp ) ; + + for( i = 0 ; i < 10 ; i++ ) + XGI_LongWait(pVBInfo) ; + + tempch = ( tempcx & 0xFF00 ) >> 8; + temp = XGINew_GetReg1( pVBInfo->Part4Port , 0x03 ) ; + temp = temp ^ ( 0x0E ) ; + temp &= tempch ; + + if ( temp != tempch ) + return( 1 ) ; + else + return( 0 ) ; + } +} + + + +/* +;----------------------------------------------------------------------------- +; Description: Get Panel support +; O/P : +; BL: Panel ID=81h for no scaler LVDS +; BH: Panel enhanced Mode Count +; CX: Panel H. resolution +; DX: PAnel V. resolution +;----------------------------------------------------------------------------- +*/ +void XGI_XG21Fun14Sub70( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments ) +{ + + USHORT ModeIdIndex; + USHORT ModeNo; + + USHORT EModeCount; + USHORT lvdstableindex; + + lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo ); + pBiosArguments->h.bl = 0x81; + pBiosArguments->x.cx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE; + pBiosArguments->x.dx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE; + EModeCount = 0; + + pBiosArguments->x.ax = 0x0014; + for( ModeIdIndex = 0 ; ; ModeIdIndex ++ ) + { + ModeNo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeID; + if ( pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeID == 0xFF ) + { + pBiosArguments->h.bh = (UCHAR) EModeCount; + return; + } + if ( !XGI_XG21CheckLVDSMode( ModeNo , ModeIdIndex, pVBInfo) ) + { + continue; + } + EModeCount++ ; + } +} +/*( +;----------------------------------------------------------------------------- +; +; Description: Get Panel mode ID for enhanced mode +; I/P : BH: EModeIndex ( which < Panel enhanced Mode Count ) +; O/P : +; BL: Mode ID +; CX: H. resolution of the assigned by the index +; DX: V. resolution of the assigned by the index +; +;----------------------------------------------------------------------------- +*/ +void XGI_XG21Fun14Sub71( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments ) +{ + + USHORT EModeCount; + USHORT ModeIdIndex,resindex; + USHORT ModeNo; + USHORT EModeIndex = pBiosArguments->h.bh; + + EModeCount = 0; + for( ModeIdIndex = 0 ; ; ModeIdIndex ++ ) + { + ModeNo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeID; + if ( pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeID == 0xFF ) + { + pBiosArguments->x.ax = 0x0114; + return; + } + if ( !XGI_XG21CheckLVDSMode( ModeNo , ModeIdIndex, pVBInfo) ) + { + continue; + } + if (EModeCount == EModeIndex) + { + resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ; + pBiosArguments->h.bl = (UCHAR) ModeNo; + pBiosArguments->x.cx = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */ + pBiosArguments->x.dx = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */ + pBiosArguments->x.ax = 0x0014; + } + EModeCount++ ; + + } + +} +/* +;----------------------------------------------------------------------------- +; +; Description: Validate Panel modes ID support +; I/P : +; BL: ModeID +; O/P : +; CX: H. resolution of the assigned by the index +; DX: V. resolution of the assigned by the index +; +;----------------------------------------------------------------------------- +*/ +void XGI_XG21Fun14Sub72( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments ) +{ + USHORT ModeIdIndex,resindex; + USHORT ModeNo; + + + ModeNo = pBiosArguments->h.bl ; + XGI_SearchModeID( ModeNo, &ModeIdIndex, pVBInfo); + if ( !XGI_XG21CheckLVDSMode( ModeNo , ModeIdIndex, pVBInfo) ) + { + pBiosArguments->x.cx = 0; + pBiosArguments->x.dx = 0; + pBiosArguments->x.ax = 0x0114; + return; + } + resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ; + if ( ModeNo <= 0x13 ) + { + pBiosArguments->x.cx = pVBInfo->StResInfo[ resindex ].HTotal ; + pBiosArguments->x.dx = pVBInfo->StResInfo[ resindex ].VTotal ; + } + else + { + pBiosArguments->x.cx = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */ + pBiosArguments->x.dx = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */ + } + + pBiosArguments->x.ax = 0x0014; + +} + +/* +;----------------------------------------------------------------------------- +; Description: Get Customized Panel misc. information support +; I/P : Select +; to get panel horizontal timing +; to get panel vertical timing +; to get channel clock parameter +; to get panel misc information +; +; O/P : +; BL: for input Select = 0 ; +; BX: *Value1 = Horizontal total +; CX: *Value2 = Horizontal front porch +; DX: *Value2 = Horizontal sync width +; BL: for input Select = 1 ; +; BX: *Value1 = Vertical total +; CX: *Value2 = Vertical front porch +; DX: *Value2 = Vertical sync width +; BL: for input Select = 2 ; +; BX: Value1 = The first CLK parameter +; CX: Value2 = The second CLK parameter +; BL: for input Select = 4 ; +; BX[15]: *Value1 D[15] VESA V. Polarity +; BX[14]: *Value1 D[14] VESA H. Polarity +; BX[7]: *Value1 D[7] Panel V. Polarity +; BX[6]: *Value1 D[6] Panel H. Polarity +;----------------------------------------------------------------------------- +*/ +void XGI_XG21Fun14Sub73( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments ) +{ + UCHAR Select; + + USHORT lvdstableindex; + + lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo ); + Select = pBiosArguments->h.bl; + + switch (Select) + { + case 0: + pBiosArguments->x.bx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHT; + pBiosArguments->x.cx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHFP; + pBiosArguments->x.dx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHSYNC; + break; + case 1: + pBiosArguments->x.bx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVT; + pBiosArguments->x.cx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVFP; + pBiosArguments->x.dx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVSYNC; + break; + case 2: + pBiosArguments->x.bx = pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData1; + pBiosArguments->x.cx = pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData2; + break; + case 4: + pBiosArguments->x.bx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability; + break; + } + + pBiosArguments->x.ax = 0x0014; +} + + +void XGI_XG21Fun14( PXGI_HW_DEVICE_INFO pXGIHWDE, PX86_REGS pBiosArguments) +{ + VB_DEVICE_INFO VBINF; + PVB_DEVICE_INFO pVBInfo = &VBINF; + + pVBInfo->IF_DEF_LVDS = 0 ; + pVBInfo->IF_DEF_CH7005 = 0 ; + pVBInfo->IF_DEF_HiVision = 1 ; + pVBInfo->IF_DEF_LCDA = 1 ; + pVBInfo->IF_DEF_CH7017 = 0 ; + pVBInfo->IF_DEF_YPbPr = 1 ; + pVBInfo->IF_DEF_CRT2Monitor = 0 ; + pVBInfo->IF_DEF_VideoCapture = 0 ; + pVBInfo->IF_DEF_ScaleLCD = 0 ; + pVBInfo->IF_DEF_OEMUtil = 0 ; + pVBInfo->IF_DEF_PWD = 0 ; + + InitTo330Pointer( pXGIHWDE->jChipType, pVBInfo ) ; + ReadVBIOSTablData( pXGIHWDE->jChipType , pVBInfo) ; + + pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ; + pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ; + pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ; + pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ; + pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ; + pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ; + pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ; + pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ; + pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ; + pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ; + pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ; + pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ; + pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ; + pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ; + pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ; + pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ; + pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ; + + switch(pBiosArguments->x.ax) + { + case 0x1470: + XGI_XG21Fun14Sub70( pVBInfo , pBiosArguments ) ; + break; + case 0x1471: + XGI_XG21Fun14Sub71( pVBInfo , pBiosArguments ) ; + break; + case 0x1472: + XGI_XG21Fun14Sub72( pVBInfo , pBiosArguments ) ; + break; + case 0x1473: + XGI_XG21Fun14Sub73( pVBInfo , pBiosArguments ) ; + break; + } +} diff --git a/drivers/staging/xgifb/vb_ext.h b/drivers/staging/xgifb/vb_ext.h new file mode 100644 index 000000000000..9a72f5ecb713 --- /dev/null +++ b/drivers/staging/xgifb/vb_ext.h @@ -0,0 +1,32 @@ +#ifndef _VBEXT_ +#define _VBEXT_ + +struct DWORDREGS { + ULONG Eax, Ebx, Ecx, Edx, Esi, Edi, Ebp; +}; + +struct WORDREGS { + USHORT ax, hi_ax, bx, hi_bx, cx, hi_cx, dx, hi_dx, si, hi_si, di ,hi_di, bp, hi_bp; +}; + +struct BYTEREGS { + UCHAR al, ah, hi_al, hi_ah, bl, bh, hi_bl, hi_bh, cl, ch, hi_cl, hi_ch, dl, dh, hi_dl, hi_dh; +}; + +typedef union _X86_REGS { + struct DWORDREGS e; + struct WORDREGS x; + struct BYTEREGS h; +} X86_REGS, *PX86_REGS; + +extern void XGI_XG21Fun14( PXGI_HW_DEVICE_INFO pXGIHWDE, PX86_REGS pBiosArguments); +extern void XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE ) ; +extern void XGI_GetSenseStatus( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ); +extern void XGINew_SetModeScratch ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ; +extern void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo); +extern USHORT XGINew_SenseLCD(PXGI_HW_DEVICE_INFO,PVB_DEVICE_INFO pVBInfo); +#ifdef WIN2000 +extern BOOLEAN XGI_DySense( PHW_DEVICE_EXTENSION pHWDE , PUCHAR ujConnectStatus ); +#endif /* WIN2000 */ + +#endif diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c new file mode 100644 index 000000000000..b85ca9ba8076 --- /dev/null +++ b/drivers/staging/xgifb/vb_init.c @@ -0,0 +1,3444 @@ +#include "osdef.h" +#include "vgatypes.h" + + +#ifdef LINUX_KERNEL +#include <linux/version.h> +#include <linux/types.h> +#include <linux/delay.h> /* udelay */ +#include "XGIfb.h" +/*#if LINUX_VERSxION_CODE >= KERNEL_VERSION(2,5,0) +#include <video/XGIfb.h> +#else +#include <linux/XGIfb.h> +#endif */ +#endif + +#ifdef WIN2000 +#include <dderror.h> +#include <devioctl.h> +#include <miniport.h> +#include <ntddvdeo.h> +#include <video.h> +#include "xgiv.h" +#include "dd_i2c.h" +#include "tools.h" +#endif + +#include "vb_def.h" +#include "vb_struct.h" +#include "vb_util.h" +#include "vb_setmode.h" +#include "vb_init.h" +#include "vb_ext.h" + +#ifdef LINUX_XF86 +#include "xf86.h" +#include "xf86PciInfo.h" +#include "xgi.h" +#include "xgi_regs.h" +#endif + +#ifdef LINUX_KERNEL +#include <asm/io.h> +#include <linux/types.h> +#endif + + + + +UCHAR XGINew_ChannelAB,XGINew_DataBusWidth; + +USHORT XGINew_DRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48}, + {0x0C,0x09,0x02,0x20,0x35},{0x0D,0x09,0x01,0x20,0x44}, + {0x0C,0x08,0x02,0x10,0x31},{0x0D,0x08,0x01,0x10,0x40}, + {0x0C,0x0A,0x01,0x20,0x34},{0x0C,0x09,0x01,0x08,0x32}, + {0x0B,0x08,0x02,0x08,0x21},{0x0C,0x08,0x01,0x08,0x30}, + {0x0A,0x08,0x02,0x04,0x11},{0x0B,0x0A,0x01,0x10,0x28}, + {0x09,0x08,0x02,0x02,0x01},{0x0B,0x09,0x01,0x08,0x24}, + {0x0B,0x08,0x01,0x04,0x20},{0x0A,0x08,0x01,0x02,0x10}, + {0x09,0x08,0x01,0x01,0x00}}; + +USHORT XGINew_SDRDRAM_TYPE[13][5]= +{ +{ 2,12, 9,64,0x35}, +{ 1,13, 9,64,0x44}, +{ 2,12, 8,32,0x31}, +{ 2,11, 9,32,0x25}, +{ 1,12, 9,32,0x34}, +{ 1,13, 8,32,0x40}, +{ 2,11, 8,16,0x21}, +{ 1,12, 8,16,0x30}, +{ 1,11, 9,16,0x24}, +{ 1,11, 8, 8,0x20}, +{ 2, 9, 8, 4,0x01}, +{ 1,10, 8, 4,0x10}, +{ 1, 9, 8, 2,0x00} +}; + +USHORT XGINew_DDRDRAM_TYPE[4][5]= +{ +{ 2,12, 9,64,0x35}, +{ 2,12, 8,32,0x31}, +{ 2,11, 8,16,0x21}, +{ 2, 9, 8, 4,0x01} +}; +USHORT XGINew_DDRDRAM_TYPE340[4][5]= +{ +{ 2,13, 9,64,0x45}, +{ 2,12, 9,32,0x35}, +{ 2,12, 8,16,0x31}, +{ 2,11, 8, 8,0x21} +}; +USHORT XGINew_DDRDRAM_TYPE20[12][5]= +{ +{ 2,14,11,128,0x5D}, +{ 2,14,10,64,0x59}, +{ 2,13,11,64,0x4D}, +{ 2,14, 9,32,0x55}, +{ 2,13,10,32,0x49}, +{ 2,12,11,32,0x3D}, +{ 2,14, 8,16,0x51}, +{ 2,13, 9,16,0x45}, +{ 2,12,10,16,0x39}, +{ 2,13, 8, 8,0x41}, +{ 2,12, 9, 8,0x35}, +{ 2,12, 8, 4,0x31} +}; + +void XGINew_SetDRAMSize_340(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO); +void XGINew_SetDRAMSize_310(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO); +void XGINew_SetMemoryClock(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO ); +void XGINew_SetDRAMModeRegister(PVB_DEVICE_INFO ); +void XGINew_SetDRAMModeRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension ); +void XGINew_SetDRAMDefaultRegister340(PXGI_HW_DEVICE_INFO HwDeviceExtension, ULONG, PVB_DEVICE_INFO ); +UCHAR XGINew_GetXG20DRAMType( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGIInitNew( PXGI_HW_DEVICE_INFO HwDeviceExtension) ; + +int XGINew_DDRSizing340( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO ); +void XGINew_DisableRefresh( PXGI_HW_DEVICE_INFO ,PVB_DEVICE_INFO) ; +void XGINew_CheckBusWidth_310( PVB_DEVICE_INFO) ; +int XGINew_SDRSizing(PVB_DEVICE_INFO); +int XGINew_DDRSizing( PVB_DEVICE_INFO ); +void XGINew_EnableRefresh( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO); +int XGINew_RAMType; /*int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,REFIndex;*/ +ULONG UNIROM; /* UNIROM */ +BOOLEAN ChkLFB( PVB_DEVICE_INFO ); +void XGINew_Delay15us(ULONG); +void SetPowerConsume (PXGI_HW_DEVICE_INFO HwDeviceExtension,ULONG XGI_P3d4Port); +void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo); +void XGINew_DDR1x_MRS_XG20( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo); +void XGINew_SetDRAMModeRegister_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension ); +void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension ); +void XGINew_ChkSenseStatus ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ; +void XGINew_SetModeScratch ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ; +void XGINew_GetXG21Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) ; +UCHAR GetXG21FPBits(PVB_DEVICE_INFO pVBInfo); +void XGINew_GetXG27Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) ; +UCHAR GetXG27FPBits(PVB_DEVICE_INFO pVBInfo); + +#ifdef WIN2000 +/* [Billy] 2007/05/20 For CH7007 */ +extern UCHAR CH7007TVReg_UNTSC[][8],CH7007TVReg_ONTSC[][8],CH7007TVReg_UPAL[][8],CH7007TVReg_OPAL[][8]; +extern UCHAR XGI7007_CHTVVCLKUNTSC[],XGI7007_CHTVVCLKONTSC[],XGI7007_CHTVVCLKUPAL[],XGI7007_CHTVVCLKOPAL[]; +#endif + +#ifdef LINUX_KERNEL +void DelayUS(ULONG MicroSeconds) +{ + udelay(MicroSeconds); +} +#endif + +/* --------------------------------------------------------------------- */ +/* Function : XGIInitNew */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGIInitNew( PXGI_HW_DEVICE_INFO HwDeviceExtension ) +{ + + VB_DEVICE_INFO VBINF; + PVB_DEVICE_INFO pVBInfo = &VBINF; + UCHAR i , temp = 0 , temp1 ; + // VBIOSVersion[ 5 ] ; + PUCHAR volatile pVideoMemory; + + /* ULONG j, k ; */ + + PXGI_DSReg pSR ; + + ULONG Temp ; + + pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ; + + pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; + + pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ; + + pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr; + + +// Newdebugcode( 0x99 ) ; + + + /* if ( pVBInfo->ROMAddr == 0 ) */ + /* return( FALSE ) ; */ + + if ( pVBInfo->FBAddr == 0 ) +{ + printk("\n pVBInfo->FBAddr == 0 "); + return( FALSE ) ; +} +printk("1"); + if ( pVBInfo->BaseAddr == 0 ) +{ + printk("\npVBInfo->BaseAddr == 0 "); + return( FALSE ) ; +} +printk("2"); + + XGINew_SetReg3( ( pVBInfo->BaseAddr + 0x12 ) , 0x67 ) ; /* 3c2 <- 67 ,ynlai */ + + pVBInfo->ISXPDOS = 0 ; +printk("3"); + +if ( !HwDeviceExtension->bIntegratedMMEnabled ) +{ + return( FALSE ) ; /* alan */ +} +printk("4"); + +// XGI_MemoryCopy( VBIOSVersion , HwDeviceExtension->szVBIOSVer , 4 ) ; + + // VBIOSVersion[ 4 ] = 0x0 ; + + /* 09/07/99 modify by domao */ + + pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ; + pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ; + pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ; + pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ; + pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ; + pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ; + pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ; + pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ; + pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ; + pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ; + pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ; + pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ; + pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ; + pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ; + pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ; + pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ; + pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ; +printk("5"); + + if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */ + XGI_GetVBType( pVBInfo ) ; /* Run XGI_GetVBType before InitTo330Pointer */ + + InitTo330Pointer( HwDeviceExtension->jChipType, pVBInfo ) ; + + /* ReadVBIOSData */ + ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ; + + /* 1.Openkey */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ; +printk("6"); + + /* GetXG21Sense (GPIO) */ + if ( HwDeviceExtension->jChipType == XG21 ) + { + XGINew_GetXG21Sense(HwDeviceExtension, pVBInfo) ; + } + if ( HwDeviceExtension->jChipType == XG27 ) + { + XGINew_GetXG27Sense(HwDeviceExtension, pVBInfo) ; + } +printk("7"); + + /* 2.Reset Extended register */ + + for( i = 0x06 ; i < 0x20 ; i++ ) + XGINew_SetReg1( pVBInfo->P3c4 , i , 0 ) ; + + for( i = 0x21 ; i <= 0x27 ; i++ ) + XGINew_SetReg1( pVBInfo->P3c4 , i , 0 ) ; + + /* for( i = 0x06 ; i <= 0x27 ; i++ ) */ + /* XGINew_SetReg1( pVBInfo->P3c4 , i , 0 ) ; */ + +printk("8"); + + if(( HwDeviceExtension->jChipType >= XG20 ) || ( HwDeviceExtension->jChipType >= XG40)) + { + for( i = 0x31 ; i <= 0x3B ; i++ ) + XGINew_SetReg1( pVBInfo->P3c4 , i , 0 ) ; + } + else + { + for( i = 0x31 ; i <= 0x3D ; i++ ) + XGINew_SetReg1( pVBInfo->P3c4 , i , 0 ) ; + } +printk("9"); + + if ( HwDeviceExtension->jChipType == XG42 ) /* [Hsuan] 2004/08/20 Auto over driver for XG42 */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x3B , 0xC0 ) ; + + /* for( i = 0x30 ; i <= 0x3F ; i++ ) */ + /* XGINew_SetReg1( pVBInfo->P3d4 , i , 0 ) ; */ + + for( i = 0x79 ; i <= 0x7C ; i++ ) + XGINew_SetReg1( pVBInfo->P3d4 , i , 0 ) ; /* shampoo 0208 */ + +printk("10"); + + if ( HwDeviceExtension->jChipType >= XG20 ) + XGINew_SetReg1( pVBInfo->P3d4 , 0x97 , *pVBInfo->pXGINew_CR97 ) ; + + /* 3.SetMemoryClock + + if ( HwDeviceExtension->jChipType >= XG40 ) + XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo) ; + + if ( HwDeviceExtension->jChipType < XG40 ) + XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ; */ + +printk("11"); + + /* 4.SetDefExt1Regs begin */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x07 , *pVBInfo->pSR07 ) ; + if ( HwDeviceExtension->jChipType == XG27 ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x40 , *pVBInfo->pSR40 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x41 , *pVBInfo->pSR41 ) ; + } + XGINew_SetReg1( pVBInfo->P3c4 , 0x11 , 0x0F ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x1F , *pVBInfo->pSR1F ) ; + /* XGINew_SetReg1( pVBInfo->P3c4 , 0x20 , 0x20 ) ; */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x20 , 0xA0 ) ; /* alan, 2001/6/26 Frame buffer can read/write SR20 */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x36 , 0x70 ) ; /* Hsuan, 2006/01/01 H/W request for slow corner chip */ + if ( HwDeviceExtension->jChipType == XG27 ) /* Alan 12/07/2006 */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x36 , *pVBInfo->pSR36 ) ; + + /* SR11 = 0x0F ; */ + /* XGINew_SetReg1( pVBInfo->P3c4 , 0x11 , SR11 ) ; */ + +printk("12"); + + if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */ + { +// /* Set AGP Rate */ +// temp1 = XGINew_GetReg1( pVBInfo->P3c4 , 0x3B ) ; +// temp1 &= 0x02 ; +// if ( temp1 == 0x02 ) +// { +// XGINew_SetReg4( 0xcf8 , 0x80000000 ) ; +// ChipsetID = XGINew_GetReg3( 0x0cfc ) ; +// XGINew_SetReg4( 0xcf8 , 0x8000002C ) ; +// VendorID = XGINew_GetReg3( 0x0cfc ) ; +// VendorID &= 0x0000FFFF ; +// XGINew_SetReg4( 0xcf8 , 0x8001002C ) ; +// GraphicVendorID = XGINew_GetReg3( 0x0cfc ) ; +// GraphicVendorID &= 0x0000FFFF; +// +// if ( ChipsetID == 0x7301039 ) +/// XGINew_SetReg1( pVBInfo->P3d4 , 0x5F , 0x09 ) ; +// +// ChipsetID &= 0x0000FFFF ; +/// +// if ( ( ChipsetID == 0x700E ) || ( ChipsetID == 0x1022 ) || ( ChipsetID == 0x1106 ) || ( ChipsetID == 0x10DE ) ) +// { +// if ( ChipsetID == 0x1106 ) +// { +// if ( ( VendorID == 0x1019 ) && ( GraphicVendorID == 0x1019 ) ) +// XGINew_SetReg1( pVBInfo->P3d4 , 0x5F , 0x0D ) ; +// else +// XGINew_SetReg1( pVBInfo->P3d4 , 0x5F , 0x0B ) ; +// } +// else +// XGINew_SetReg1( pVBInfo->P3d4 , 0x5F , 0x0B ) ; +// } +// } + +printk("13"); + + if ( HwDeviceExtension->jChipType >= XG40 ) + { + /* Set AGP customize registers (in SetDefAGPRegs) Start */ + for( i = 0x47 ; i <= 0x4C ; i++ ) + XGINew_SetReg1( pVBInfo->P3d4 , i , pVBInfo->AGPReg[ i - 0x47 ] ) ; + + for( i = 0x70 ; i <= 0x71 ; i++ ) + XGINew_SetReg1( pVBInfo->P3d4 , i , pVBInfo->AGPReg[ 6 + i - 0x70 ] ) ; + + for( i = 0x74 ; i <= 0x77 ; i++ ) + XGINew_SetReg1( pVBInfo->P3d4 , i , pVBInfo->AGPReg[ 8 + i - 0x74 ] ) ; + /* Set AGP customize registers (in SetDefAGPRegs) End */ + /*[Hsuan]2004/12/14 AGP Input Delay Adjustment on 850 */ +// XGINew_SetReg4( 0xcf8 , 0x80000000 ) ; +// ChipsetID = XGINew_GetReg3( 0x0cfc ) ; +// if ( ChipsetID == 0x25308086 ) +// XGINew_SetReg1( pVBInfo->P3d4 , 0x77 , 0xF0 ) ; + + HwDeviceExtension->pQueryVGAConfigSpace( HwDeviceExtension , 0x50 , 0 , &Temp ) ; /* Get */ + Temp >>= 20 ; + Temp &= 0xF ; + + if ( Temp == 1 ) + XGINew_SetReg1( pVBInfo->P3d4 , 0x48 , 0x20 ) ; /* CR48 */ + } +printk("14"); + + if ( HwDeviceExtension->jChipType < XG40 ) + XGINew_SetReg1( pVBInfo->P3d4 , 0x49 , pVBInfo->CR49[ 0 ] ) ; + } /* != XG20 */ + + /* Set PCI */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x23 , *pVBInfo->pSR23 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x24 , *pVBInfo->pSR24 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x25 , pVBInfo->SR25[ 0 ] ) ; +printk("15"); + + if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */ + { + /* Set VB */ + XGI_UnLockCRT2( HwDeviceExtension, pVBInfo) ; + XGINew_SetRegANDOR( pVBInfo->Part0Port , 0x3F , 0xEF , 0x00 ) ; /* alan, disable VideoCapture */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x00 , 0x00 ) ; + temp1 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x7B ) ; /* chk if BCLK>=100MHz */ + temp = ( UCHAR )( ( temp1 >> 4 ) & 0x0F ) ; + + + XGINew_SetReg1( pVBInfo->Part1Port , 0x02 , ( *pVBInfo->pCRT2Data_1_2 ) ) ; + +printk("16"); + + XGINew_SetReg1( pVBInfo->Part1Port , 0x2E , 0x08 ) ; /* use VB */ + } /* != XG20 */ + + + XGINew_SetReg1( pVBInfo->P3c4 , 0x27 , 0x1F ) ; + + if ( ( HwDeviceExtension->jChipType == XG42 ) && XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo) != 0 ) /* Not DDR */ + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , ( *pVBInfo->pSR31 & 0x3F ) | 0x40 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , ( *pVBInfo->pSR32 & 0xFC ) | 0x01 ) ; + } + else + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , *pVBInfo->pSR31 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , *pVBInfo->pSR32 ) ; + } + XGINew_SetReg1( pVBInfo->P3c4 , 0x33 , *pVBInfo->pSR33 ) ; +printk("17"); + +/* + if ( HwDeviceExtension->jChipType >= XG40 ) + SetPowerConsume ( HwDeviceExtension , pVBInfo->P3c4); */ + + if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */ + { + if ( XGI_BridgeIsOn( pVBInfo ) == 1 ) + { + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , 0x1C ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x0D , *pVBInfo->pCRT2Data_4_D ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x0E , *pVBInfo->pCRT2Data_4_E ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x10 , *pVBInfo->pCRT2Data_4_10 ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x0F , 0x3F ) ; + } + + XGI_LockCRT2( HwDeviceExtension, pVBInfo ) ; + } + } /* != XG20 */ +printk("18"); + + if ( HwDeviceExtension->jChipType < XG40 ) + XGINew_SetReg1( pVBInfo->P3d4 , 0x83 , 0x00 ) ; +printk("181"); + + if ( HwDeviceExtension->bSkipSense == FALSE ) + { +printk("182"); + + XGI_SenseCRT1(pVBInfo) ; + +printk("183"); + /* XGINew_DetectMonitor( HwDeviceExtension ) ; */ +pVBInfo->IF_DEF_CH7007 = 0; + if ( ( HwDeviceExtension->jChipType == XG21 ) && (pVBInfo->IF_DEF_CH7007) ) + { +printk("184"); + XGI_GetSenseStatus( HwDeviceExtension , pVBInfo ) ; /* sense CRT2 */ +printk("185"); + + } + if ( HwDeviceExtension->jChipType == XG21 ) + { +printk("186"); + + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~Monitor1Sense , Monitor1Sense ) ; /* Z9 default has CRT */ + temp = GetXG21FPBits( pVBInfo ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , ~0x01, temp ) ; +printk("187"); + + } + if ( HwDeviceExtension->jChipType == XG27 ) + { + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~Monitor1Sense , Monitor1Sense ) ; /* Z9 default has CRT */ + temp = GetXG27FPBits( pVBInfo ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , ~0x03, temp ) ; + } + } +printk("19"); + + if ( HwDeviceExtension->jChipType >= XG40 ) + { + if ( HwDeviceExtension->jChipType >= XG40 ) + { + XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ; + } + + XGINew_SetDRAMDefaultRegister340( HwDeviceExtension , pVBInfo->P3d4, pVBInfo ) ; + + if ( HwDeviceExtension->bSkipDramSizing == TRUE ) + { + pSR = HwDeviceExtension->pSR ; + if ( pSR!=NULL ) + { + while( pSR->jIdx != 0xFF ) + { + XGINew_SetReg1( pVBInfo->P3c4 , pSR->jIdx , pSR->jVal ) ; + pSR++ ; + } + } + /* XGINew_SetDRAMModeRegister340( pVBInfo ) ; */ + } /* SkipDramSizing */ + else + { +#if 0 + if ( HwDeviceExtension->jChipType == XG20 ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , pVBInfo->SR15[0][XGINew_RAMType] ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , pVBInfo->SR15[1][XGINew_RAMType] ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x20 , 0x20 ) ; + } + else +#endif +{ +printk("20"); + + XGINew_SetDRAMSize_340( HwDeviceExtension , pVBInfo) ; +} +printk("21"); + + } + } /* XG40 */ + +printk("22"); + + + /* SetDefExt2Regs begin */ +/* + AGP = 1 ; + temp =( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x3A ) ; + temp &= 0x30 ; + if ( temp == 0x30 ) + AGP = 0 ; + + if ( AGP == 0 ) + *pVBInfo->pSR21 &= 0xEF ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , *pVBInfo->pSR21 ) ; + if ( AGP == 1 ) + *pVBInfo->pSR22 &= 0x20 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x22 , *pVBInfo->pSR22 ) ; +*/ + +// base = 0x80000000 ; +// OutPortLong( 0xcf8 , base ) ; +// Temp = ( InPortLong( 0xcfc ) & 0xFFFF ) ; +// if ( Temp == 0x1039 ) +// { + XGINew_SetReg1( pVBInfo->P3c4 , 0x22 , ( UCHAR )( ( *pVBInfo->pSR22 ) & 0xFE ) ) ; +// } +// else +// { +// XGINew_SetReg1( pVBInfo->P3c4 , 0x22 , *pVBInfo->pSR22 ) ; +// } + + XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , *pVBInfo->pSR21 ) ; + +printk("23"); + + + XGINew_ChkSenseStatus ( HwDeviceExtension , pVBInfo ) ; + XGINew_SetModeScratch ( HwDeviceExtension , pVBInfo ) ; + +printk("24"); + + +XGINew_SetReg1( pVBInfo->P3d4 , 0x8c , 0x87); +XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x31); +printk("25"); + + return( TRUE ) ; +} /* end of init */ + + + + + +/* ============== alan ====================== */ + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_GetXG20DRAMType */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +UCHAR XGINew_GetXG20DRAMType( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo) +{ + UCHAR data, temp ; + + if ( HwDeviceExtension->jChipType < XG20 ) + { + if ( *pVBInfo->pSoftSetting & SoftDRAMType ) + { + data = *pVBInfo->pSoftSetting & 0x07 ; + return( data ) ; + } + else + { + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x39 ) & 0x02 ; + + if ( data == 0 ) + data = ( XGINew_GetReg1( pVBInfo->P3c4 , 0x3A ) & 0x02 ) >> 1 ; + + return( data ) ; + } + } + else if ( HwDeviceExtension->jChipType == XG27 ) + { + if ( *pVBInfo->pSoftSetting & SoftDRAMType ) + { + data = *pVBInfo->pSoftSetting & 0x07 ; + return( data ) ; + } + temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x3B ) ; + + if (( temp & 0x88 )==0x80) /* SR3B[7][3]MAA15 MAA11 (Power on Trapping) */ + data = 0 ; /*DDR*/ + else + data = 1 ; /*DDRII*/ + return( data ) ; + } + else if ( HwDeviceExtension->jChipType == XG21 ) + { + XGINew_SetRegAND( pVBInfo->P3d4 , 0xB4 , ~0x02 ) ; /* Independent GPIO control */ + DelayUS(800); + XGINew_SetRegOR( pVBInfo->P3d4 , 0x4A , 0x80 ) ; /* Enable GPIOH read */ + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ; /* GPIOF 0:DVI 1:DVO */ +// HOTPLUG_SUPPORT +// for current XG20 & XG21, GPIOH is floating, driver will fix DDR temporarily + if ( temp & 0x01 ) /* DVI read GPIOH */ + data = 1 ; /*DDRII*/ + else + data = 0 ; /*DDR*/ +//~HOTPLUG_SUPPORT + XGINew_SetRegOR( pVBInfo->P3d4 , 0xB4 , 0x02 ) ; + return( data ) ; + } + else + { + data = XGINew_GetReg1( pVBInfo->P3d4 , 0x97 ) & 0x01 ; + + if ( data == 1 ) + data ++ ; + + return( data ); + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_Get310DRAMType */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +UCHAR XGINew_Get310DRAMType(PVB_DEVICE_INFO pVBInfo) +{ + UCHAR data ; + + /* index = XGINew_GetReg1( pVBInfo->P3c4 , 0x1A ) ; */ + /* index &= 07 ; */ + + if ( *pVBInfo->pSoftSetting & SoftDRAMType ) + data = *pVBInfo->pSoftSetting & 0x03 ; + else + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x3a ) & 0x03 ; + + return( data ) ; +} + + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_Delay15us */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +/* +void XGINew_Delay15us(ULONG ulMicrsoSec) +{ +} +*/ + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SDR_MRS */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SDR_MRS( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT data ; + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x16 ) ; + data &= 0x3F ; /* SR16 D7=0,D6=0 */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; /* enable mode register set(MRS) low */ + /* XGINew_Delay15us( 0x100 ) ; */ + data |= 0x80 ; /* SR16 D7=1,D6=0 */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; /* enable mode register set(MRS) high */ + /* XGINew_Delay15us( 0x100 ) ; */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDR1x_MRS_340 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DDR1x_MRS_340( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo) +{ + XGINew_SetReg1( P3c4 , 0x18 , 0x01 ) ; + XGINew_SetReg1( P3c4 , 0x19 , 0x20 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + + if ( *pVBInfo->pXGINew_DRAMTypeDefinition != 0x0C ) /* Samsung F Die */ + { + DelayUS( 3000 ) ; /* Delay 67 x 3 Delay15us */ + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x19 , 0x20 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + } + + DelayUS( 60 ) ; + XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x01 ) ; + XGINew_SetReg1( P3c4 , 0x16 , pVBInfo->SR16[ 0 ] ) ; + XGINew_SetReg1( P3c4 , 0x16 , pVBInfo->SR16[ 1 ] ) ; + DelayUS( 1000 ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x03 ) ; + DelayUS( 500 ) ; + XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x16 , pVBInfo->SR16[ 2 ] ) ; + XGINew_SetReg1( P3c4 , 0x16 , pVBInfo->SR16[ 3 ] ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDR2x_MRS_340 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DDR2x_MRS_340( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo) +{ + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x19 , 0x20 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + DelayUS( 60 ) ; + XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */ + /* XGINew_SetReg1( P3c4 , 0x18 , 0x31 ) ; */ + XGINew_SetReg1( P3c4 , 0x19 , 0x01 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ; + DelayUS( 1000 ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x03 ) ; + DelayUS( 500 ) ; + /* XGINew_SetReg1( P3c4 , 0x18 , 0x31 ) ; */ + XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ; +} + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDRII_Bootup_XG27 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DDRII_Bootup_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 , PVB_DEVICE_INFO pVBInfo) +{ + ULONG P3d4 = P3c4 + 0x10 ; + XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ; + XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ; + + /* Set Double Frequency */ + /* XGINew_SetReg1( P3d4 , 0x97 , 0x11 ) ; */ /* CR97 */ + XGINew_SetReg1( P3d4 , 0x97 , *pVBInfo->pXGINew_CR97 ) ; /* CR97 */ + + DelayUS( 200 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* Set SR18 */ //EMRS2 + XGINew_SetReg1( P3c4 , 0x19 , 0x80 ) ; /* Set SR19 */ + XGINew_SetReg1( P3c4 , 0x16 , 0x20 ) ; /* Set SR16 */ + DelayUS( 15 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0xA0 ) ; /* Set SR16 */ + DelayUS( 15 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* Set SR18 */ //EMRS3 + XGINew_SetReg1( P3c4 , 0x19 , 0xC0 ) ; /* Set SR19 */ + XGINew_SetReg1( P3c4 , 0x16 , 0x20 ) ; /* Set SR16 */ + DelayUS( 15 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0xA0 ) ; /* Set SR16 */ + DelayUS( 15) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* Set SR18 */ //EMRS1 + XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ; /* Set SR19 */ + XGINew_SetReg1( P3c4 , 0x16 , 0x20 ) ; /* Set SR16 */ + DelayUS( 30 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0xA0 ) ; /* Set SR16 */ + DelayUS( 15 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* Set SR18 */ //MRS, DLL Enable + XGINew_SetReg1( P3c4 , 0x19 , 0x0A ) ; /* Set SR19 */ + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; /* Set SR16 */ + DelayUS( 30 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; /* Set SR16 */ + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; /* Set SR16 */ + /* DelayUS( 15 ) ; */ + + XGINew_SetReg1( P3c4 , 0x1B , 0x04 ) ; /* Set SR1B */ + DelayUS( 60 ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ; /* Set SR1B */ + + XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* Set SR18 */ //MRS, DLL Reset + XGINew_SetReg1( P3c4 , 0x19 , 0x08 ) ; /* Set SR19 */ + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; /* Set SR16 */ + + DelayUS( 30 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x83 ) ; /* Set SR16 */ + DelayUS( 15 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x80 ) ; /* Set SR18 */ //MRS, ODT + XGINew_SetReg1( P3c4 , 0x19 , 0x46 ) ; /* Set SR19 */ + XGINew_SetReg1( P3c4 , 0x16 , 0x20 ) ; /* Set SR16 */ + DelayUS( 30 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0xA0 ) ; /* Set SR16 */ + DelayUS( 15 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* Set SR18 */ //EMRS + XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ; /* Set SR19 */ + XGINew_SetReg1( P3c4 , 0x16 , 0x20 ) ; /* Set SR16 */ + DelayUS( 30 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0xA0 ) ; /* Set SR16 */ + DelayUS( 15 ) ; + + XGINew_SetReg1( P3c4 , 0x1B , 0x04 ) ; /* Set SR1B refresh control 000:close; 010:open */ + DelayUS( 200 ) ; + + +} +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDR2_MRS_XG20 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DDR2_MRS_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 , PVB_DEVICE_INFO pVBInfo) +{ + ULONG P3d4 = P3c4 + 0x10 ; + + XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ; + XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ; + + XGINew_SetReg1( P3d4 , 0x97 , 0x11 ) ; /* CR97 */ + + DelayUS( 200 ) ; + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS2 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x80 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS3 */ + XGINew_SetReg1( P3c4 , 0x19 , 0xC0 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS1 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ; + + // XGINew_SetReg1( P3c4 , 0x18 , 0x52 ) ; /* MRS1 */ + XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* MRS1 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x02 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ; + + DelayUS( 15 ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x04 ) ; /* SR1B */ + DelayUS( 30 ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ; /* SR1B */ + DelayUS( 100 ) ; + + //XGINew_SetReg1( P3c4 , 0x18 , 0x52 ) ; /* MRS2 */ + XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* MRS1 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ; + + DelayUS( 200 ) ; +} + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDR2_MRS_XG20 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DDR2_MRS_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 , PVB_DEVICE_INFO pVBInfo) +{ + ULONG P3d4 = P3c4 + 0x10 ; + + XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ; + XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ; + + XGINew_SetReg1( P3d4 , 0x97 , 0x11 ) ; /* CR97 */ + DelayUS( 200 ) ; + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS2 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x80 ) ; + + XGINew_SetReg1( P3c4 , 0x16 , 0x10 ) ; + DelayUS( 15 ) ; ////06/11/23 XG27 A0 for CKE enable + XGINew_SetReg1( P3c4 , 0x16 , 0x90 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS3 */ + XGINew_SetReg1( P3c4 , 0x19 , 0xC0 ) ; + + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + DelayUS( 15 ) ; ////06/11/22 XG27 A0 + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + + + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS1 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ; + + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + DelayUS( 15 ) ; ////06/11/22 XG27 A0 + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* MRS1 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x06 ) ; ////[Billy]06/11/22 DLL Reset for XG27 Hynix DRAM + + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + DelayUS( 15 ) ; ////06/11/23 XG27 A0 + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + + DelayUS( 30 ) ; ////06/11/23 XG27 A0 Start Auto-PreCharge + XGINew_SetReg1( P3c4 , 0x1B , 0x04 ) ; /* SR1B */ + DelayUS( 60 ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ; /* SR1B */ + + + XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* MRS1 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x04 ) ; //// DLL without Reset for XG27 Hynix DRAM + + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + DelayUS( 30 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x80 ); ////XG27 OCD ON + XGINew_SetReg1( P3c4 , 0x19 , 0x46 ); + + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + DelayUS( 30 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ); + XGINew_SetReg1( P3c4 , 0x19 , 0x40 ); + + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + DelayUS( 30 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + + DelayUS( 15 ) ; ////Start Auto-PreCharge + XGINew_SetReg1( P3c4 , 0x1B , 0x04 ) ; /* SR1B */ + DelayUS( 200 ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x03 ) ; /* SR1B */ + +} + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDR1x_DefaultRegister */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DDR1x_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG Port , PVB_DEVICE_INFO pVBInfo) +{ + ULONG P3d4 = Port , + P3c4 = Port - 0x10 ; + + if ( HwDeviceExtension->jChipType >= XG20 ) + { + XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ; + XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */ + XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */ + XGINew_SetReg1( P3d4 , 0x86 , pVBInfo->CR40[ 13 ][ XGINew_RAMType ] ) ; /* CR86 */ + + XGINew_SetReg1( P3d4 , 0x98 , 0x01 ) ; + XGINew_SetReg1( P3d4 , 0x9A , 0x02 ) ; + + XGINew_DDR1x_MRS_XG20( P3c4 , pVBInfo) ; + } + else + { + XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ; + + switch( HwDeviceExtension->jChipType ) + { + case XG41: + case XG42: + XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */ + XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */ + XGINew_SetReg1( P3d4 , 0x86 , pVBInfo->CR40[ 13 ][ XGINew_RAMType ] ) ; /* CR86 */ + break ; + default: + XGINew_SetReg1( P3d4 , 0x82 , 0x88 ) ; + XGINew_SetReg1( P3d4 , 0x86 , 0x00 ) ; + XGINew_GetReg1( P3d4 , 0x86 ) ; /* Insert read command for delay */ + XGINew_SetReg1( P3d4 , 0x86 , 0x88 ) ; + XGINew_GetReg1( P3d4 , 0x86 ) ; + XGINew_SetReg1( P3d4 , 0x86 , pVBInfo->CR40[ 13 ][ XGINew_RAMType ] ) ; + XGINew_SetReg1( P3d4 , 0x82 , 0x77 ) ; + XGINew_SetReg1( P3d4 , 0x85 , 0x00 ) ; + XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */ + XGINew_SetReg1( P3d4 , 0x85 , 0x88 ) ; + XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */ + XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */ + XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */ + break ; + } + + XGINew_SetReg1( P3d4 , 0x97 , 0x00 ) ; + XGINew_SetReg1( P3d4 , 0x98 , 0x01 ) ; + XGINew_SetReg1( P3d4 , 0x9A , 0x02 ) ; + XGINew_DDR1x_MRS_340( P3c4 , pVBInfo ) ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDR2x_DefaultRegister */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DDR2x_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG Port ,PVB_DEVICE_INFO pVBInfo) +{ + ULONG P3d4 = Port , + P3c4 = Port - 0x10 ; + + XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ; + + /* 20040906 Hsuan modify CR82, CR85, CR86 for XG42 */ + switch( HwDeviceExtension->jChipType ) + { + case XG41: + case XG42: + XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */ + XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */ + XGINew_SetReg1( P3d4 , 0x86 , pVBInfo->CR40[ 13 ][ XGINew_RAMType ] ) ; /* CR86 */ + break ; + default: + /* keep following setting sequence, each setting in the same reg insert idle */ + XGINew_SetReg1( P3d4 , 0x82 , 0x88 ) ; + XGINew_SetReg1( P3d4 , 0x86 , 0x00 ) ; + XGINew_GetReg1( P3d4 , 0x86 ) ; /* Insert read command for delay */ + XGINew_SetReg1( P3d4 , 0x86 , 0x88 ) ; + XGINew_SetReg1( P3d4 , 0x82 , 0x77 ) ; + XGINew_SetReg1( P3d4 , 0x85 , 0x00 ) ; + XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */ + XGINew_SetReg1( P3d4 , 0x85 , 0x88 ) ; + XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */ + XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */ + XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */ + } + XGINew_SetReg1( P3d4 , 0x97 , 0x11 ) ; + if ( HwDeviceExtension->jChipType == XG42 ) + { + XGINew_SetReg1( P3d4 , 0x98 , 0x01 ) ; + } + else + { + XGINew_SetReg1( P3d4 , 0x98 , 0x03 ) ; + } + XGINew_SetReg1( P3d4 , 0x9A , 0x02 ) ; + + XGINew_DDR2x_MRS_340( P3c4 , pVBInfo ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDR2_DefaultRegister */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DDR2_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension, ULONG Port , PVB_DEVICE_INFO pVBInfo) +{ + ULONG P3d4 = Port , + P3c4 = Port - 0x10 ; + + /* keep following setting sequence, each setting in the same reg insert idle */ + XGINew_SetReg1( P3d4 , 0x82 , 0x77 ) ; + XGINew_SetReg1( P3d4 , 0x86 , 0x00 ) ; + XGINew_GetReg1( P3d4 , 0x86 ) ; /* Insert read command for delay */ + XGINew_SetReg1( P3d4 , 0x86 , 0x88 ) ; + XGINew_GetReg1( P3d4 , 0x86 ) ; /* Insert read command for delay */ + XGINew_SetReg1( P3d4 , 0x86 , pVBInfo->CR40[ 13 ][ XGINew_RAMType ] ) ; /* CR86 */ + XGINew_SetReg1( P3d4 , 0x82 , 0x77 ) ; + XGINew_SetReg1( P3d4 , 0x85 , 0x00 ) ; + XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */ + XGINew_SetReg1( P3d4 , 0x85 , 0x88 ) ; + XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */ + XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */ + if ( HwDeviceExtension->jChipType == XG27 ) + XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */ + else + XGINew_SetReg1( P3d4 , 0x82 , 0xA8 ) ; /* CR82 */ + + XGINew_SetReg1( P3d4 , 0x98 , 0x01 ) ; + XGINew_SetReg1( P3d4 , 0x9A , 0x02 ) ; + if ( HwDeviceExtension->jChipType == XG27 ) + XGINew_DDRII_Bootup_XG27( HwDeviceExtension , P3c4 , pVBInfo) ; + else + XGINew_DDR2_MRS_XG20( HwDeviceExtension , P3c4, pVBInfo ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetDRAMDefaultRegister340 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetDRAMDefaultRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG Port , PVB_DEVICE_INFO pVBInfo) +{ + UCHAR temp , temp1 , temp2 , temp3 , + i , j , k ; + + ULONG P3d4 = Port , + P3c4 = Port - 0x10 ; + + XGINew_SetReg1( P3d4 , 0x6D , pVBInfo->CR40[ 8 ][ XGINew_RAMType ] ) ; + XGINew_SetReg1( P3d4 , 0x68 , pVBInfo->CR40[ 5 ][ XGINew_RAMType ] ) ; + XGINew_SetReg1( P3d4 , 0x69 , pVBInfo->CR40[ 6 ][ XGINew_RAMType ] ) ; + XGINew_SetReg1( P3d4 , 0x6A , pVBInfo->CR40[ 7 ][ XGINew_RAMType ] ) ; + + temp2 = 0 ; + for( i = 0 ; i < 4 ; i++ ) + { + temp = pVBInfo->CR6B[ XGINew_RAMType ][ i ] ; /* CR6B DQS fine tune delay */ + for( j = 0 ; j < 4 ; j++ ) + { + temp1 = ( ( temp >> ( 2 * j ) ) & 0x03 ) << 2 ; + temp2 |= temp1 ; + XGINew_SetReg1( P3d4 , 0x6B , temp2 ) ; + XGINew_GetReg1( P3d4 , 0x6B ) ; /* Insert read command for delay */ + temp2 &= 0xF0 ; + temp2 += 0x10 ; + } + } + + temp2 = 0 ; + for( i = 0 ; i < 4 ; i++ ) + { + temp = pVBInfo->CR6E[ XGINew_RAMType ][ i ] ; /* CR6E DQM fine tune delay */ + for( j = 0 ; j < 4 ; j++ ) + { + temp1 = ( ( temp >> ( 2 * j ) ) & 0x03 ) << 2 ; + temp2 |= temp1 ; + XGINew_SetReg1( P3d4 , 0x6E , temp2 ) ; + XGINew_GetReg1( P3d4 , 0x6E ) ; /* Insert read command for delay */ + temp2 &= 0xF0 ; + temp2 += 0x10 ; + } + } + + temp3 = 0 ; + for( k = 0 ; k < 4 ; k++ ) + { + XGINew_SetRegANDOR( P3d4 , 0x6E , 0xFC , temp3 ) ; /* CR6E_D[1:0] select channel */ + temp2 = 0 ; + for( i = 0 ; i < 8 ; i++ ) + { + temp = pVBInfo->CR6F[ XGINew_RAMType ][ 8 * k + i ] ; /* CR6F DQ fine tune delay */ + for( j = 0 ; j < 4 ; j++ ) + { + temp1 = ( temp >> ( 2 * j ) ) & 0x03 ; + temp2 |= temp1 ; + XGINew_SetReg1( P3d4 , 0x6F , temp2 ) ; + XGINew_GetReg1( P3d4 , 0x6F ) ; /* Insert read command for delay */ + temp2 &= 0xF8 ; + temp2 += 0x08 ; + } + } + temp3 += 0x01 ; + } + + XGINew_SetReg1( P3d4 , 0x80 , pVBInfo->CR40[ 9 ][ XGINew_RAMType ] ) ; /* CR80 */ + XGINew_SetReg1( P3d4 , 0x81 , pVBInfo->CR40[ 10 ][ XGINew_RAMType ] ) ; /* CR81 */ + + temp2 = 0x80 ; + temp = pVBInfo->CR89[ XGINew_RAMType ][ 0 ] ; /* CR89 terminator type select */ + for( j = 0 ; j < 4 ; j++ ) + { + temp1 = ( temp >> ( 2 * j ) ) & 0x03 ; + temp2 |= temp1 ; + XGINew_SetReg1( P3d4 , 0x89 , temp2 ) ; + XGINew_GetReg1( P3d4 , 0x89 ) ; /* Insert read command for delay */ + temp2 &= 0xF0 ; + temp2 += 0x10 ; + } + + temp = pVBInfo->CR89[ XGINew_RAMType ][ 1 ] ; + temp1 = temp & 0x03 ; + temp2 |= temp1 ; + XGINew_SetReg1( P3d4 , 0x89 , temp2 ) ; + + temp = pVBInfo->CR40[ 3 ][ XGINew_RAMType ] ; + temp1 = temp & 0x0F ; + temp2 = ( temp >> 4 ) & 0x07 ; + temp3 = temp & 0x80 ; + XGINew_SetReg1( P3d4 , 0x45 , temp1 ) ; /* CR45 */ + XGINew_SetReg1( P3d4 , 0x99 , temp2 ) ; /* CR99 */ + XGINew_SetRegOR( P3d4 , 0x40 , temp3 ) ; /* CR40_D[7] */ + XGINew_SetReg1( P3d4 , 0x41 , pVBInfo->CR40[ 0 ][ XGINew_RAMType ] ) ; /* CR41 */ + + if ( HwDeviceExtension->jChipType == XG27 ) + XGINew_SetReg1( P3d4 , 0x8F , *pVBInfo->pCR8F ) ; /* CR8F */ + + for( j = 0 ; j <= 6 ; j++ ) + XGINew_SetReg1( P3d4 , ( 0x90 + j ) , pVBInfo->CR40[ 14 + j ][ XGINew_RAMType ] ) ; /* CR90 - CR96 */ + + for( j = 0 ; j <= 2 ; j++ ) + XGINew_SetReg1( P3d4 , ( 0xC3 + j ) , pVBInfo->CR40[ 21 + j ][ XGINew_RAMType ] ) ; /* CRC3 - CRC5 */ + + for( j = 0 ; j < 2 ; j++ ) + XGINew_SetReg1( P3d4 , ( 0x8A + j ) , pVBInfo->CR40[ 1 + j ][ XGINew_RAMType ] ) ; /* CR8A - CR8B */ + + if ( ( HwDeviceExtension->jChipType == XG41 ) || ( HwDeviceExtension->jChipType == XG42 ) ) + XGINew_SetReg1( P3d4 , 0x8C , 0x87 ) ; + + XGINew_SetReg1( P3d4 , 0x59 , pVBInfo->CR40[ 4 ][ XGINew_RAMType ] ) ; /* CR59 */ + + XGINew_SetReg1( P3d4 , 0x83 , 0x09 ) ; /* CR83 */ + XGINew_SetReg1( P3d4 , 0x87 , 0x00 ) ; /* CR87 */ + XGINew_SetReg1( P3d4 , 0xCF , *pVBInfo->pCRCF ) ; /* CRCF */ + if ( XGINew_RAMType ) + { + //XGINew_SetReg1( P3c4 , 0x17 , 0xC0 ) ; /* SR17 DDRII */ + XGINew_SetReg1( P3c4 , 0x17 , 0x80 ) ; /* SR17 DDRII */ + if ( HwDeviceExtension->jChipType == XG27 ) + XGINew_SetReg1( P3c4 , 0x17 , 0x02 ) ; /* SR17 DDRII */ + + } + else + XGINew_SetReg1( P3c4 , 0x17 , 0x00 ) ; /* SR17 DDR */ + XGINew_SetReg1( P3c4 , 0x1A , 0x87 ) ; /* SR1A */ + + temp = XGINew_GetXG20DRAMType( HwDeviceExtension, pVBInfo) ; + if( temp == 0 ) + XGINew_DDR1x_DefaultRegister( HwDeviceExtension, P3d4, pVBInfo ) ; + else + { + XGINew_SetReg1( P3d4 , 0xB0 , 0x80 ) ; /* DDRII Dual frequency mode */ + XGINew_DDR2_DefaultRegister( HwDeviceExtension, P3d4, pVBInfo ) ; + } + XGINew_SetReg1( P3c4 , 0x1B , pVBInfo->SR15[ 3 ][ XGINew_RAMType ] ) ; /* SR1B */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDR_MRS */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DDR_MRS(PVB_DEVICE_INFO pVBInfo) +{ + USHORT data ; + + PUCHAR volatile pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr ; + + /* SR16 <- 1F,DF,2F,AF */ + /* yriver modified SR16 <- 0F,DF,0F,AF */ + /* enable DLL of DDR SD/SGRAM , SR16 D4=1 */ + data = pVideoMemory[ 0xFB ] ; + /* data = XGINew_GetReg1( pVBInfo->P3c4 , 0x16 ) ; */ + + data &= 0x0F ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; + data |= 0xC0 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; + data &= 0x0F ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; + data |= 0x80 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; + data &= 0x0F ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; + data |= 0xD0 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; + data &= 0x0F ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; + data |= 0xA0 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; +/* + else { + data &= 0x0F; + data |= 0x10; + XGINew_SetReg1(pVBInfo->P3c4,0x16,data); + + if (!(pVBInfo->SR15[1][XGINew_RAMType] & 0x10)) + { + data &= 0x0F; + } + + data |= 0xC0; + XGINew_SetReg1(pVBInfo->P3c4,0x16,data); + + + data &= 0x0F; + data |= 0x20; + XGINew_SetReg1(pVBInfo->P3c4,0x16,data); + if (!(pVBInfo->SR15[1][XGINew_RAMType] & 0x10)) + { + data &= 0x0F; + } + + data |= 0x80; + XGINew_SetReg1(pVBInfo->P3c4,0x16,data); + } +*/ +} + + +/* check if read cache pointer is correct */ + + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_VerifyMclk */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_VerifyMclk( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo) +{ + PUCHAR pVideoMemory = pVBInfo->FBAddr ; + UCHAR i , j ; + USHORT Temp , SR21 ; + + pVideoMemory[ 0 ] = 0xaa ; /* alan */ + pVideoMemory[ 16 ] = 0x55 ; /* note: PCI read cache is off */ + + if ( ( pVideoMemory[ 0 ] != 0xaa ) || ( pVideoMemory[ 16 ] != 0x55 ) ) + { + for( i = 0 , j = 16 ; i < 2 ; i++ , j += 16 ) + { + SR21 = XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ; + Temp = SR21 & 0xFB ; /* disable PCI post write buffer empty gating */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , Temp ) ; + + Temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x3C ) ; + Temp |= 0x01 ; /* MCLK reset */ + + + Temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x3C ) ; + Temp &= 0xFE ; /* MCLK normal operation */ + + XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , SR21 ) ; + + pVideoMemory[ 16 + j ] = j ; + if ( pVideoMemory[ 16 + j ] == j ) + { + pVideoMemory[ j ] = j ; + break ; + } + } + } +} + + + + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetDRAMSize_340 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetDRAMSize_340( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo) +{ + USHORT data ; + + pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ; + pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; + + XGISetModeNew( HwDeviceExtension , 0x2e ) ; + + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data & 0xDF ) ) ; /* disable read cache */ + XGI_DisplayOff( HwDeviceExtension, pVBInfo ); + + /*data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1 ) ;*/ + /*data |= 0x20 ;*/ + /*XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , data ) ;*/ /* Turn OFF Display */ + XGINew_DDRSizing340( HwDeviceExtension, pVBInfo ) ; + data=XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data | 0x20 ) ) ; /* enable read cache */ + +} + + +/* --------------------------------------------------------------------- */ +/* Function : */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetDRAMSize_310( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo) +{ + USHORT data ; + pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase , + pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; +#ifdef XGI301 + /* XGINew_SetReg1( pVBInfo->P3d4 , 0x30 , 0x40 ) ; */ +#endif + +#ifdef XGI302 /* alan,should change value */ + XGINew_SetReg1( pVBInfo->P3d4 , 0x30 , 0x4D ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x31 , 0xc0 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x34 , 0x3F ) ; +#endif + + XGISetModeNew( HwDeviceExtension , 0x2e ) ; + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data & 0xDF ) ) ; /* disable read cache */ + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1 ) ; + data |= 0x20 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , data ) ; /* Turn OFF Display */ + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x16 ) ; + + + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , ( USHORT )( data | 0x0F ) ) ; /* assume lowest speed DRAM */ + + XGINew_SetDRAMModeRegister( pVBInfo ) ; + XGINew_DisableRefresh( HwDeviceExtension, pVBInfo ) ; + XGINew_CheckBusWidth_310( pVBInfo) ; + XGINew_VerifyMclk( HwDeviceExtension, pVBInfo ) ; /* alan 2000/7/3 */ + + + + if ( XGINew_Get310DRAMType( pVBInfo ) < 2 ) + { + XGINew_SDRSizing( pVBInfo ) ; + } + else + { + XGINew_DDRSizing( pVBInfo) ; + } + + + + + XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , pVBInfo->SR15[ 1 ][ XGINew_RAMType ] ) ; /* restore SR16 */ + + XGINew_EnableRefresh( HwDeviceExtension, pVBInfo ) ; + data=XGINew_GetReg1( pVBInfo->P3c4 ,0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data | 0x20 ) ) ; /* enable read cache */ +} + + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetDRAMModeRegister340 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ + +void XGINew_SetDRAMModeRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension ) +{ + UCHAR data ; + VB_DEVICE_INFO VBINF; + PVB_DEVICE_INFO pVBInfo = &VBINF; + pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ; + pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; + pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ; + pVBInfo->ISXPDOS = 0 ; + + pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ; + pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ; + pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ; + pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ; + pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ; + pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ; + pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ; + pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ; + pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ; + pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ; + pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ; + pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ; + pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ; + pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ; + pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ; + pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ; + pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ; + if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */ + XGI_GetVBType( pVBInfo ) ; /* Run XGI_GetVBType before InitTo330Pointer */ + + InitTo330Pointer(HwDeviceExtension->jChipType,pVBInfo); + + ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ; + + if ( XGINew_GetXG20DRAMType( HwDeviceExtension, pVBInfo) == 0 ) + { + data = ( XGINew_GetReg1( pVBInfo->P3c4 , 0x39 ) & 0x02 ) >> 1 ; + if ( data == 0x01 ) + XGINew_DDR2x_MRS_340( pVBInfo->P3c4, pVBInfo ) ; + else + XGINew_DDR1x_MRS_340( pVBInfo->P3c4, pVBInfo ) ; + } + else + XGINew_DDR2_MRS_XG20( HwDeviceExtension, pVBInfo->P3c4, pVBInfo); + + XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , 0x03 ) ; +} + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetDRAMModeRegister */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetDRAMModeRegister( PVB_DEVICE_INFO pVBInfo) +{ + if ( XGINew_Get310DRAMType( pVBInfo ) < 2 ) + { + XGINew_SDR_MRS(pVBInfo ) ; + } + else + { + /* SR16 <- 0F,CF,0F,8F */ + XGINew_DDR_MRS( pVBInfo ) ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DisableRefresh */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DisableRefresh( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo) +{ + USHORT data ; + + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1B ) ; + data &= 0xF8 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , data ) ; + +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_EnableRefresh */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_EnableRefresh( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo) +{ + + XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , pVBInfo->SR15[ 3 ][ XGINew_RAMType ] ) ; /* SR1B */ + + +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DisableChannelInterleaving */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DisableChannelInterleaving( int index , USHORT XGINew_DDRDRAM_TYPE[][ 5 ] , PVB_DEVICE_INFO pVBInfo) +{ + USHORT data ; + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x15 ) ; + data &= 0x1F ; + + switch( XGINew_DDRDRAM_TYPE[ index ][ 3 ] ) + { + case 64: + data |= 0 ; + break ; + case 32: + data |= 0x20 ; + break ; + case 16: + data |= 0x40 ; + break ; + case 4: + data |= 0x60 ; + break ; + default: + break ; + } + XGINew_SetReg1( pVBInfo->P3c4 , 0x15 , data ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetDRAMSizingType */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetDRAMSizingType( int index , USHORT DRAMTYPE_TABLE[][ 5 ] ,PVB_DEVICE_INFO pVBInfo) +{ + USHORT data ; + + data = DRAMTYPE_TABLE[ index ][ 4 ] ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x13 , 0x80 , data ) ; + DelayUS( 15 ) ; + /* should delay 50 ns */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_CheckBusWidth_310 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_CheckBusWidth_310( PVB_DEVICE_INFO pVBInfo) +{ + USHORT data ; + PULONG volatile pVideoMemory ; + + pVideoMemory = (PULONG) pVBInfo->FBAddr; + + if ( XGINew_Get310DRAMType( pVBInfo ) < 2 ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x00 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x12 ) ; + /* should delay */ + XGINew_SDR_MRS( pVBInfo ) ; + + XGINew_ChannelAB = 0 ; + XGINew_DataBusWidth = 128 ; + pVideoMemory[ 0 ] = 0x01234567L ; + pVideoMemory[ 1 ] = 0x456789ABL ; + pVideoMemory[ 2 ] = 0x89ABCDEFL ; + pVideoMemory[ 3 ] = 0xCDEF0123L ; + pVideoMemory[ 4 ] = 0x55555555L ; + pVideoMemory[ 5 ] = 0x55555555L ; + pVideoMemory[ 6 ] = 0xFFFFFFFFL ; + pVideoMemory[ 7 ] = 0xFFFFFFFFL ; + + if ( ( pVideoMemory[ 3 ] != 0xCDEF0123L ) || ( pVideoMemory[ 2 ] != 0x89ABCDEFL ) ) + { + /* ChannelA64Bit */ + XGINew_DataBusWidth = 64 ; + XGINew_ChannelAB = 0 ; + data=XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , ( USHORT )( data & 0xFD ) ) ; + } + + if ( ( pVideoMemory[ 1 ] != 0x456789ABL ) || ( pVideoMemory[ 0 ] != 0x01234567L ) ) + { + /* ChannelB64Bit */ + XGINew_DataBusWidth = 64 ; + XGINew_ChannelAB = 1 ; + data=XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , ( USHORT )( ( data & 0xFD ) | 0x01 ) ) ; + } + + return ; + } + else + { + /* DDR Dual channel */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x00 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x02 ) ; /* Channel A, 64bit */ + /* should delay */ + XGINew_DDR_MRS( pVBInfo ) ; + + XGINew_ChannelAB = 0 ; + XGINew_DataBusWidth = 64 ; + pVideoMemory[ 0 ] = 0x01234567L ; + pVideoMemory[ 1 ] = 0x456789ABL ; + pVideoMemory[ 2 ] = 0x89ABCDEFL ; + pVideoMemory[ 3 ] = 0xCDEF0123L ; + pVideoMemory[ 4 ] = 0x55555555L ; + pVideoMemory[ 5 ] = 0x55555555L ; + pVideoMemory[ 6 ] = 0xAAAAAAAAL ; + pVideoMemory[ 7 ] = 0xAAAAAAAAL ; + + if ( pVideoMemory[ 1 ] == 0x456789ABL ) + { + if ( pVideoMemory[ 0 ] == 0x01234567L ) + { + /* Channel A 64bit */ + return ; + } + } + else + { + if ( pVideoMemory[ 0 ] == 0x01234567L ) + { + /* Channel A 32bit */ + XGINew_DataBusWidth = 32 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x00 ) ; + return ; + } + } + + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x03 ) ; /* Channel B, 64bit */ + XGINew_DDR_MRS( pVBInfo); + + XGINew_ChannelAB = 1 ; + XGINew_DataBusWidth = 64 ; + pVideoMemory[ 0 ] = 0x01234567L ; + pVideoMemory[ 1 ] = 0x456789ABL ; + pVideoMemory[ 2 ] = 0x89ABCDEFL ; + pVideoMemory[ 3 ] = 0xCDEF0123L ; + pVideoMemory[ 4 ] = 0x55555555L ; + pVideoMemory[ 5 ] = 0x55555555L ; + pVideoMemory[ 6 ] = 0xAAAAAAAAL ; + pVideoMemory[ 7 ] = 0xAAAAAAAAL ; + + if ( pVideoMemory[ 1 ] == 0x456789ABL ) + { + /* Channel B 64 */ + if ( pVideoMemory[ 0 ] == 0x01234567L ) + { + /* Channel B 64bit */ + return ; + } + else + { + /* error */ + } + } + else + { + if ( pVideoMemory[ 0 ] == 0x01234567L ) + { + /* Channel B 32 */ + XGINew_DataBusWidth = 32 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x01 ) ; + } + else + { + /* error */ + } + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetRank */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_SetRank( int index , UCHAR RankNo , UCHAR XGINew_ChannelAB , USHORT DRAMTYPE_TABLE[][ 5 ] , PVB_DEVICE_INFO pVBInfo) +{ + USHORT data ; + int RankSize ; + + if ( ( RankNo == 2 ) && ( DRAMTYPE_TABLE[ index ][ 0 ] == 2 ) ) + return 0 ; + + RankSize = DRAMTYPE_TABLE[ index ][ 3 ] / 2 * XGINew_DataBusWidth / 32 ; + + if ( ( RankNo * RankSize ) <= 128 ) + { + data = 0 ; + + while( ( RankSize >>= 1 ) > 0 ) + { + data += 0x10 ; + } + data |= ( RankNo - 1 ) << 2 ; + data |= ( XGINew_DataBusWidth / 64 ) & 2 ; + data |= XGINew_ChannelAB ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , data ) ; + /* should delay */ + XGINew_SDR_MRS( pVBInfo ) ; + return( 1 ) ; + } + else + return( 0 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetDDRChannel */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_SetDDRChannel( int index , UCHAR ChannelNo , UCHAR XGINew_ChannelAB , USHORT DRAMTYPE_TABLE[][ 5 ] , PVB_DEVICE_INFO pVBInfo) +{ + USHORT data ; + int RankSize ; + + RankSize = DRAMTYPE_TABLE[index][3]/2 * XGINew_DataBusWidth/32; + /* RankSize = DRAMTYPE_TABLE[ index ][ 3 ] ; */ + if ( ChannelNo * RankSize <= 128 ) + { + data = 0 ; + while( ( RankSize >>= 1 ) > 0 ) + { + data += 0x10 ; + } + + if ( ChannelNo == 2 ) + data |= 0x0C ; + + data |= ( XGINew_DataBusWidth / 32 ) & 2 ; + data |= XGINew_ChannelAB ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , data ) ; + /* should delay */ + XGINew_DDR_MRS( pVBInfo ) ; + return( 1 ) ; + } + else + return( 0 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_CheckColumn */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_CheckColumn( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo) +{ + int i ; + ULONG Increment , Position ; + + /* Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + XGINew_DataBusWidth / 64 + 1 ) ; */ + Increment = 1 << ( 10 + XGINew_DataBusWidth / 64 ) ; + + for( i = 0 , Position = 0 ; i < 2 ; i++ ) + { + *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ; + Position += Increment ; + } + +#ifdef WIN2000 /* chiawen for linux solution */ + DelayUS( 100 ) ; +#endif + + for( i = 0 , Position = 0 ; i < 2 ; i++ ) + { + /* if ( pVBInfo->FBAddr[ Position ] != Position ) */ + if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position ) + return( 0 ) ; + Position += Increment ; + } + return( 1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_CheckBanks */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_CheckBanks( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo) +{ + int i ; + ULONG Increment , Position ; + + Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + XGINew_DataBusWidth / 64 + 2 ) ; + + for( i = 0 , Position = 0 ; i < 4 ; i++ ) + { + /* pVBInfo->FBAddr[ Position ] = Position ; */ + *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ; + Position += Increment ; + } + + for( i = 0 , Position = 0 ; i < 4 ; i++ ) + { + /* if (pVBInfo->FBAddr[ Position ] != Position ) */ + if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position ) + return( 0 ) ; + Position += Increment ; + } + return( 1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_CheckRank */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_CheckRank( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo) +{ + int i ; + ULONG Increment , Position ; + + Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + DRAMTYPE_TABLE[ index ][ 1 ] + + DRAMTYPE_TABLE[ index ][ 0 ] + XGINew_DataBusWidth / 64 + RankNo ) ; + + for( i = 0 , Position = 0 ; i < 2 ; i++ ) + { + /* pVBInfo->FBAddr[ Position ] = Position ; */ + /* *( ( PULONG )( pVBInfo->FBAddr ) ) = Position ; */ + *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ; + Position += Increment ; + } + + for( i = 0 , Position = 0 ; i < 2 ; i++ ) + { + /* if ( pVBInfo->FBAddr[ Position ] != Position ) */ + /* if ( ( *( PULONG )( pVBInfo->FBAddr ) ) != Position ) */ + if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position ) + return( 0 ) ; + Position += Increment ; + } + return( 1 ); +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_CheckDDRRank */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_CheckDDRRank( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo) +{ + ULONG Increment , Position ; + USHORT data ; + + Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + DRAMTYPE_TABLE[ index ][ 1 ] + + DRAMTYPE_TABLE[ index ][ 0 ] + XGINew_DataBusWidth / 64 + RankNo ) ; + + Increment += Increment / 2 ; + + Position = 0; + *( ( PULONG )( pVBInfo->FBAddr + Position + 0 ) ) = 0x01234567 ; + *( ( PULONG )( pVBInfo->FBAddr + Position + 1 ) ) = 0x456789AB ; + *( ( PULONG )( pVBInfo->FBAddr + Position + 2 ) ) = 0x55555555 ; + *( ( PULONG )( pVBInfo->FBAddr + Position + 3 ) ) = 0x55555555 ; + *( ( PULONG )( pVBInfo->FBAddr + Position + 4 ) ) = 0xAAAAAAAA ; + *( ( PULONG )( pVBInfo->FBAddr + Position + 5 ) ) = 0xAAAAAAAA ; + + if ( ( *( PULONG )( pVBInfo->FBAddr + 1 ) ) == 0x456789AB ) + return( 1 ) ; + + if ( ( *( PULONG )( pVBInfo->FBAddr + 0 ) ) == 0x01234567 ) + return( 0 ) ; + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ; + data &= 0xF3 ; + data |= 0x0E ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , data ) ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x15 ) ; + data += 0x20 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x15 , data ) ; + + return( 1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_CheckRanks */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_CheckRanks( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo) +{ + int r ; + + for( r = RankNo ; r >= 1 ; r-- ) + { + if ( !XGINew_CheckRank( r , index , DRAMTYPE_TABLE, pVBInfo ) ) + return( 0 ) ; + } + + if ( !XGINew_CheckBanks( index , DRAMTYPE_TABLE, pVBInfo ) ) + return( 0 ) ; + + if ( !XGINew_CheckColumn( index , DRAMTYPE_TABLE, pVBInfo ) ) + return( 0 ) ; + + return( 1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_CheckDDRRanks */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_CheckDDRRanks( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo) +{ + int r ; + + for( r = RankNo ; r >= 1 ; r-- ) + { + if ( !XGINew_CheckDDRRank( r , index , DRAMTYPE_TABLE, pVBInfo ) ) + return( 0 ) ; + } + + if ( !XGINew_CheckBanks( index , DRAMTYPE_TABLE, pVBInfo ) ) + return( 0 ) ; + + if ( !XGINew_CheckColumn( index , DRAMTYPE_TABLE, pVBInfo ) ) + return( 0 ) ; + + return( 1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_SDRSizing(PVB_DEVICE_INFO pVBInfo) +{ + int i ; + UCHAR j ; + + for( i = 0 ; i < 13 ; i++ ) + { + XGINew_SetDRAMSizingType( i , XGINew_SDRDRAM_TYPE , pVBInfo) ; + + for( j = 2 ; j > 0 ; j-- ) + { + if ( !XGINew_SetRank( i , ( UCHAR )j , XGINew_ChannelAB , XGINew_SDRDRAM_TYPE , pVBInfo) ) + continue ; + else + { + if ( XGINew_CheckRanks( j , i , XGINew_SDRDRAM_TYPE, pVBInfo) ) + return( 1 ) ; + } + } + } + return( 0 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetDRAMSizeReg */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGINew_SetDRAMSizeReg( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo) +{ + USHORT data = 0 , memsize = 0 ; + int RankSize ; + UCHAR ChannelNo ; + + RankSize = DRAMTYPE_TABLE[ index ][ 3 ] * XGINew_DataBusWidth / 32 ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x13 ) ; + data &= 0x80 ; + + if ( data == 0x80 ) + RankSize *= 2 ; + + data = 0 ; + + if( XGINew_ChannelAB == 3 ) + ChannelNo = 4 ; + else + ChannelNo = XGINew_ChannelAB ; + + if ( ChannelNo * RankSize <= 256 ) + { + while( ( RankSize >>= 1 ) > 0 ) + { + data += 0x10 ; + } + + memsize = data >> 4 ; + + /* [2004/03/25] Vicent, Fix DRAM Sizing Error */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , ( XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) & 0x0F ) | ( data & 0xF0 ) ) ; + + /* data |= XGINew_ChannelAB << 2 ; */ + /* data |= ( XGINew_DataBusWidth / 64 ) << 1 ; */ + /* XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , data ) ; */ + + /* should delay */ + /* XGINew_SetDRAMModeRegister340( pVBInfo ) ; */ + } + return( memsize ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetDRAMSize20Reg */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGINew_SetDRAMSize20Reg( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo) +{ + USHORT data = 0 , memsize = 0 ; + int RankSize ; + UCHAR ChannelNo ; + + RankSize = DRAMTYPE_TABLE[ index ][ 3 ] * XGINew_DataBusWidth / 8 ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x13 ) ; + data &= 0x80 ; + + if ( data == 0x80 ) + RankSize *= 2 ; + + data = 0 ; + + if( XGINew_ChannelAB == 3 ) + ChannelNo = 4 ; + else + ChannelNo = XGINew_ChannelAB ; + + if ( ChannelNo * RankSize <= 256 ) + { + while( ( RankSize >>= 1 ) > 0 ) + { + data += 0x10 ; + } + + memsize = data >> 4 ; + + /* [2004/03/25] Vicent, Fix DRAM Sizing Error */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , ( XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) & 0x0F ) | ( data & 0xF0 ) ) ; + DelayUS( 15 ) ; + + /* data |= XGINew_ChannelAB << 2 ; */ + /* data |= ( XGINew_DataBusWidth / 64 ) << 1 ; */ + /* XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , data ) ; */ + + /* should delay */ + /* XGINew_SetDRAMModeRegister340( pVBInfo ) ; */ + } + return( memsize ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_ReadWriteRest */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_ReadWriteRest( USHORT StopAddr , USHORT StartAddr, PVB_DEVICE_INFO pVBInfo) +{ + int i ; + ULONG Position = 0 ; + + *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ; + + for( i = StartAddr ; i <= StopAddr ; i++ ) + { + Position = 1 << i ; + *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ; + } + + DelayUS( 500 ) ; /* [Vicent] 2004/04/16. Fix #1759 Memory Size error in Multi-Adapter. */ + + Position = 0 ; + + if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position ) + return( 0 ) ; + + for( i = StartAddr ; i <= StopAddr ; i++ ) + { + Position = 1 << i ; + if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position ) + return( 0 ) ; + } + return( 1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_CheckFrequence */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +UCHAR XGINew_CheckFrequence( PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR data ; + + data = XGINew_GetReg1( pVBInfo->P3d4 , 0x97 ) ; + + if ( ( data & 0x10 ) == 0 ) + { + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x39 ) ; + data = ( data & 0x02 ) >> 1 ; + return( data ) ; + } + else + return( data & 0x01 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_CheckChannel */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_CheckChannel( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + UCHAR data; + + switch( HwDeviceExtension->jChipType ) + { + case XG20: + case XG21: + data = XGINew_GetReg1( pVBInfo->P3d4 , 0x97 ) ; + data = data & 0x01; + XGINew_ChannelAB = 1 ; /* XG20 "JUST" one channel */ + + if ( data == 0 ) /* Single_32_16 */ + { + + if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x1000000) + { + + XGINew_DataBusWidth = 32 ; /* 32 bits */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xB1 ) ; /* 22bit + 2 rank + 32bit */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x52 ) ; + DelayUS( 15 ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + return ; + + if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x800000) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x31 ) ; /* 22bit + 1 rank + 32bit */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x42 ) ; + DelayUS( 15 ) ; + + if ( XGINew_ReadWriteRest( 23 , 23 , pVBInfo ) == 1 ) + return ; + } + } + + if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x800000) + { + XGINew_DataBusWidth = 16 ; /* 16 bits */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xB1 ) ; /* 22bit + 2 rank + 16bit */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x41 ) ; + DelayUS( 15 ) ; + + if ( XGINew_ReadWriteRest( 23 , 22 , pVBInfo ) == 1 ) + return ; + else + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x31 ) ; + DelayUS( 15 ) ; + } + + } + else /* Dual_16_8 */ + { + if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x800000) + { + + XGINew_DataBusWidth = 16 ; /* 16 bits */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xB1 ) ; /* (0x31:12x8x2) 22bit + 2 rank */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x41 ) ; /* 0x41:16Mx16 bit*/ + DelayUS( 15 ) ; + + if ( XGINew_ReadWriteRest( 23 , 22 , pVBInfo ) == 1 ) + return ; + + if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x400000) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x31 ) ; /* (0x31:12x8x2) 22bit + 1 rank */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x31 ) ; /* 0x31:8Mx16 bit*/ + DelayUS( 15 ) ; + + if ( XGINew_ReadWriteRest( 22 , 22 , pVBInfo ) == 1 ) + return ; + } + } + + + if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x400000) + { + XGINew_DataBusWidth = 8 ; /* 8 bits */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xB1 ) ; /* (0x31:12x8x2) 22bit + 2 rank */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x30 ) ; /* 0x30:8Mx8 bit*/ + DelayUS( 15 ) ; + + if ( XGINew_ReadWriteRest( 22 , 21 , pVBInfo ) == 1 ) + return ; + else + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x31 ) ; /* (0x31:12x8x2) 22bit + 1 rank */ + DelayUS( 15 ) ; + } + } + break ; + + case XG27: + XGINew_DataBusWidth = 16 ; /* 16 bits */ + XGINew_ChannelAB = 1 ; /* Single channel */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x51 ) ; /* 32Mx16 bit*/ + break ; + case XG41: + if ( XGINew_CheckFrequence(pVBInfo) == 1 ) + { + XGINew_DataBusWidth = 32 ; /* 32 bits */ + XGINew_ChannelAB = 3 ; /* Quad Channel */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x4C ) ; + + if ( XGINew_ReadWriteRest( 25 , 23 , pVBInfo ) == 1 ) + return ; + + XGINew_ChannelAB = 2 ; /* Dual channels */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x48 ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + return ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x49 ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + return ; + + XGINew_ChannelAB = 3 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x3C ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + return ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x38 ) ; + + if ( XGINew_ReadWriteRest( 8 , 4 , pVBInfo ) == 1 ) + return ; + else + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x39 ) ; + } + else + { /* DDR */ + XGINew_DataBusWidth = 64 ; /* 64 bits */ + XGINew_ChannelAB = 2 ; /* Dual channels */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x5A ) ; + + if ( XGINew_ReadWriteRest( 25 , 24 , pVBInfo ) == 1 ) + return ; + + XGINew_ChannelAB = 1 ; /* Single channels */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x52 ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + return ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x53 ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + return ; + + XGINew_ChannelAB = 2 ; /* Dual channels */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x4A ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + return ; + + XGINew_ChannelAB = 1 ; /* Single channels */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x42 ) ; + + if ( XGINew_ReadWriteRest( 8 , 4 , pVBInfo ) == 1 ) + return ; + else + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x43 ) ; + } + + break ; + + case XG42: +/* + XG42 SR14 D[3] Reserve + D[2] = 1, Dual Channel + = 0, Single Channel + + It's Different from Other XG40 Series. +*/ + if ( XGINew_CheckFrequence(pVBInfo) == 1 ) /* DDRII, DDR2x */ + { + XGINew_DataBusWidth = 32 ; /* 32 bits */ + XGINew_ChannelAB = 2 ; /* 2 Channel */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x44 ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + return ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x34 ) ; + if ( XGINew_ReadWriteRest( 23 , 22 , pVBInfo ) == 1 ) + return ; + + XGINew_ChannelAB = 1 ; /* Single Channel */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x40 ) ; + + if ( XGINew_ReadWriteRest( 23 , 22 , pVBInfo ) == 1 ) + return ; + else + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x30 ) ; + } + } + else + { /* DDR */ + XGINew_DataBusWidth = 64 ; /* 64 bits */ + XGINew_ChannelAB = 1 ; /* 1 channels */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x52 ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + return ; + else + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x42 ) ; + } + } + + break ; + + default: /* XG40 */ + + if ( XGINew_CheckFrequence(pVBInfo) == 1 ) /* DDRII */ + { + XGINew_DataBusWidth = 32 ; /* 32 bits */ + XGINew_ChannelAB = 3 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x4C ) ; + + if ( XGINew_ReadWriteRest( 25 , 23 , pVBInfo ) == 1 ) + return ; + + XGINew_ChannelAB = 2 ; /* 2 channels */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x48 ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + return ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x3C ) ; + + if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 ) + XGINew_ChannelAB = 3 ; /* 4 channels */ + else + { + XGINew_ChannelAB = 2 ; /* 2 channels */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x38 ) ; + } + } + else + { /* DDR */ + XGINew_DataBusWidth = 64 ; /* 64 bits */ + XGINew_ChannelAB = 2 ; /* 2 channels */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x5A ) ; + + if ( XGINew_ReadWriteRest( 25 , 24 , pVBInfo ) == 1 ) + return ; + else + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x4A ) ; + } + } + break ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDRSizing340 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_DDRSizing340( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + int i ; + USHORT memsize , addr ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x15 , 0x00 ) ; /* noninterleaving */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x1C , 0x00 ) ; /* nontiling */ + XGINew_CheckChannel( HwDeviceExtension, pVBInfo ) ; + + + if ( HwDeviceExtension->jChipType >= XG20 ) + { + for( i = 0 ; i < 12 ; i++ ) + { + XGINew_SetDRAMSizingType( i , XGINew_DDRDRAM_TYPE20, pVBInfo ) ; + memsize = XGINew_SetDRAMSize20Reg( i , XGINew_DDRDRAM_TYPE20, pVBInfo ) ; + if ( memsize == 0 ) + continue ; + + addr = memsize + ( XGINew_ChannelAB - 2 ) + 20 ; + if ( ( HwDeviceExtension->ulVideoMemorySize - 1 ) < ( ULONG )( 1 << addr ) ) + continue ; + + if ( XGINew_ReadWriteRest( addr , 5, pVBInfo ) == 1 ) + return( 1 ) ; + } + } + else + { + for( i = 0 ; i < 4 ; i++ ) + { + XGINew_SetDRAMSizingType( i , XGINew_DDRDRAM_TYPE340, pVBInfo ) ; + memsize = XGINew_SetDRAMSizeReg( i , XGINew_DDRDRAM_TYPE340, pVBInfo ) ; + + if ( memsize == 0 ) + continue ; + + addr = memsize + ( XGINew_ChannelAB - 2 ) + 20 ; + if ( ( HwDeviceExtension->ulVideoMemorySize - 1 ) < ( ULONG )( 1 << addr ) ) + continue ; + + if ( XGINew_ReadWriteRest( addr , 9, pVBInfo ) == 1 ) + return( 1 ) ; + } + } + return( 0 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDRSizing */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int XGINew_DDRSizing(PVB_DEVICE_INFO pVBInfo) +{ + int i ; + UCHAR j ; + + for( i = 0 ; i < 4 ; i++ ) + { + XGINew_SetDRAMSizingType( i , XGINew_DDRDRAM_TYPE, pVBInfo ) ; + XGINew_DisableChannelInterleaving( i , XGINew_DDRDRAM_TYPE , pVBInfo) ; + for( j = 2 ; j > 0 ; j-- ) + { + XGINew_SetDDRChannel( i , j , XGINew_ChannelAB , XGINew_DDRDRAM_TYPE , pVBInfo ) ; + if ( !XGINew_SetRank( i , ( UCHAR )j , XGINew_ChannelAB , XGINew_DDRDRAM_TYPE, pVBInfo ) ) + continue ; + else + { + if ( XGINew_CheckDDRRanks( j , i , XGINew_DDRDRAM_TYPE, pVBInfo ) ) + return( 1 ) ; + } + } + } + return( 0 ) ; +} + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetMemoryClock */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetMemoryClock( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + + + XGINew_SetReg1( pVBInfo->P3c4 , 0x28 , pVBInfo->MCLKData[ XGINew_RAMType ].SR28 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x29 , pVBInfo->MCLKData[ XGINew_RAMType ].SR29 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2A , pVBInfo->MCLKData[ XGINew_RAMType ].SR2A ) ; + + + + XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , pVBInfo->ECLKData[ XGINew_RAMType ].SR2E ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , pVBInfo->ECLKData[ XGINew_RAMType ].SR2F ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x30 , pVBInfo->ECLKData[ XGINew_RAMType ].SR30 ) ; + + /* [Vicent] 2004/07/07, When XG42 ECLK = MCLK = 207MHz, Set SR32 D[1:0] = 10b */ + /* [Hsuan] 2004/08/20, Modify SR32 value, when MCLK=207MHZ, ELCK=250MHz, Set SR32 D[1:0] = 10b */ + if ( HwDeviceExtension->jChipType == XG42 ) + { + if ( ( pVBInfo->MCLKData[ XGINew_RAMType ].SR28 == 0x1C ) && ( pVBInfo->MCLKData[ XGINew_RAMType ].SR29 == 0x01 ) + && ( ( ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2E == 0x1C ) && ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2F == 0x01 ) ) + || ( ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2E == 0x22 ) && ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2F == 0x01 ) ) ) ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , ( ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x32 ) & 0xFC ) | 0x02 ) ; + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : ChkLFB */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN ChkLFB( PVB_DEVICE_INFO pVBInfo ) +{ + if ( LFBDRAMTrap & XGINew_GetReg1( pVBInfo->P3d4 , 0x78 ) ) + return( TRUE ) ; + else + return( FALSE ); +} + + +/* --------------------------------------------------------------------- */ +/* input : dx ,valid value : CR or second chip's CR */ +/* */ +/* SetPowerConsume : */ +/* Description: reduce 40/43 power consumption in first chip or */ +/* in second chip, assume CR A1 D[6]="1" in this case */ +/* output : none */ +/* --------------------------------------------------------------------- */ +void SetPowerConsume ( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG XGI_P3d4Port ) +{ + ULONG lTemp ; + UCHAR bTemp; + + HwDeviceExtension->pQueryVGAConfigSpace( HwDeviceExtension , 0x08 , 0 , &lTemp ) ; /* Get */ + if ((lTemp&0xFF)==0) + { + /* set CR58 D[5]=0 D[3]=0 */ + XGINew_SetRegAND( XGI_P3d4Port , 0x58 , 0xD7 ) ; + bTemp = (UCHAR) XGINew_GetReg1( XGI_P3d4Port , 0xCB ) ; + if (bTemp&0x20) + { + if (!(bTemp&0x10)) + { + XGINew_SetRegANDOR( XGI_P3d4Port , 0x58 , 0xD7 , 0x20 ) ; /* CR58 D[5]=1 D[3]=0 */ + } + else + { + XGINew_SetRegANDOR( XGI_P3d4Port , 0x58 , 0xD7 , 0x08 ) ; /* CR58 D[5]=0 D[3]=1 */ + } + + } + + } +} + + + +#if defined(LINUX_XF86)||defined(LINUX_KERNEL) +void XGINew_InitVBIOSData(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + + /* ULONG ROMAddr = (ULONG)HwDeviceExtension->pjVirtualRomBase; */ + pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ; + pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; + pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ; + pVBInfo->ISXPDOS = 0 ; + + pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ; + pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ; + pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ; + pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ; + pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ; + pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ; + pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ; + pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ; + pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ; + pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ; + pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ; + pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ; + pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ; + pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ; + pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ; + pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ; + pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ; + if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */ + XGI_GetVBType( pVBInfo ) ; /* Run XGI_GetVBType before InitTo330Pointer */ + + switch(HwDeviceExtension->jChipType) + { + case XG40: + case XG41: + case XG42: + case XG20: + case XG21: + default: + InitTo330Pointer(HwDeviceExtension->jChipType,pVBInfo); + return ; + } + +} +#endif /* For Linux */ + +/* --------------------------------------------------------------------- */ +/* Function : ReadVBIOSTablData */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo) +{ + PUCHAR volatile pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr ; + ULONG i ; + UCHAR j , k ; +#if 0 + ULONG ii , jj ; + i = pVideoMemory[ 0x1CF ] | ( pVideoMemory[ 0x1D0 ] << 8 ) ; /* UniROM */ + if ( i != 0 ) + UNIROM = 1 ; + + ii = 0x90 ; + for( jj = 0x00 ; jj < 0x08 ; jj++ ) + { + pVBInfo->MCLKData[ jj ].SR28 = pVideoMemory[ ii ] ; + pVBInfo->MCLKData[ jj ].SR29 = pVideoMemory[ ii + 1] ; + pVBInfo->MCLKData[ jj ].SR2A = pVideoMemory[ ii + 2] ; + pVBInfo->MCLKData[ jj ].CLOCK = pVideoMemory[ ii + 3 ] | ( pVideoMemory[ ii + 4 ] << 8 ) ; + ii += 0x05 ; + } + + ii = 0xB8 ; + for( jj = 0x00 ; jj < 0x08 ; jj++ ) + { + pVBInfo->ECLKData[ jj ].SR2E = pVideoMemory[ ii ] ; + pVBInfo->ECLKData[ jj ].SR2F=pVideoMemory[ ii + 1 ] ; + pVBInfo->ECLKData[ jj ].SR30= pVideoMemory[ ii + 2 ] ; + pVBInfo->ECLKData[ jj ].CLOCK= pVideoMemory[ ii + 3 ] | ( pVideoMemory[ ii + 4 ] << 8 ) ; + ii += 0x05 ; + } + + /* Volari customize data area start */ + /* if ( ChipType == XG40 ) */ + if ( ChipType >= XG40 ) + { + ii = 0xE0 ; + for( jj = 0x00 ; jj < 0x03 ; jj++ ) + { + pVBInfo->SR15[ jj ][ 0 ] = pVideoMemory[ ii ] ; /* SR13, SR14, and SR18 */ + pVBInfo->SR15[ jj ][ 1 ] = pVideoMemory[ ii + 1 ] ; + pVBInfo->SR15[ jj ][ 2 ] = pVideoMemory[ ii + 2 ] ; + pVBInfo->SR15[ jj ][ 3 ] = pVideoMemory[ ii + 3 ] ; + pVBInfo->SR15[ jj ][ 4 ] = pVideoMemory[ ii + 4 ] ; + pVBInfo->SR15[ jj ][ 5 ] = pVideoMemory[ ii + 5 ] ; + pVBInfo->SR15[ jj ][ 6 ] = pVideoMemory[ ii + 6 ] ; + pVBInfo->SR15[ jj ][ 7 ] = pVideoMemory[ ii + 7 ] ; + ii += 0x08 ; + } + ii = 0x110 ; + jj = 0x03 ; + pVBInfo->SR15[ jj ][ 0 ] = pVideoMemory[ ii ] ; /* SR1B */ + pVBInfo->SR15[ jj ][ 1 ] = pVideoMemory[ ii + 1 ] ; + pVBInfo->SR15[ jj ][ 2 ] = pVideoMemory[ ii + 2 ] ; + pVBInfo->SR15[ jj ][ 3 ] = pVideoMemory[ ii + 3 ] ; + pVBInfo->SR15[ jj ][ 4 ] = pVideoMemory[ ii + 4 ] ; + pVBInfo->SR15[ jj ][ 5 ] = pVideoMemory[ ii + 5 ] ; + pVBInfo->SR15[ jj ][ 6 ] = pVideoMemory[ ii + 6 ] ; + pVBInfo->SR15[ jj ][ 7 ] = pVideoMemory[ ii + 7 ] ; + + *pVBInfo->pSR07 = pVideoMemory[ 0x74 ] ; + *pVBInfo->pSR1F = pVideoMemory[ 0x75 ] ; + *pVBInfo->pSR21 = pVideoMemory[ 0x76 ] ; + *pVBInfo->pSR22 = pVideoMemory[ 0x77 ] ; + *pVBInfo->pSR23 = pVideoMemory[ 0x78 ] ; + *pVBInfo->pSR24 = pVideoMemory[ 0x79 ] ; + pVBInfo->SR25[ 0 ] = pVideoMemory[ 0x7A ] ; + *pVBInfo->pSR31 = pVideoMemory[ 0x7B ] ; + *pVBInfo->pSR32 = pVideoMemory[ 0x7C ] ; + *pVBInfo->pSR33 = pVideoMemory[ 0x7D ] ; + ii = 0xF8 ; + + for( jj = 0 ; jj < 3 ; jj++ ) + { + pVBInfo->CR40[ jj ][ 0 ] = pVideoMemory[ ii ] ; + pVBInfo->CR40[ jj ][ 1 ] = pVideoMemory[ ii + 1 ] ; + pVBInfo->CR40[ jj ][ 2 ] = pVideoMemory[ ii + 2 ] ; + pVBInfo->CR40[ jj ][ 3 ] = pVideoMemory[ ii + 3 ] ; + pVBInfo->CR40[ jj ][ 4 ] = pVideoMemory[ ii + 4 ] ; + pVBInfo->CR40[ jj ][ 5 ] = pVideoMemory[ ii + 5 ] ; + pVBInfo->CR40[ jj ][ 6 ] = pVideoMemory[ ii + 6 ] ; + pVBInfo->CR40[ jj ][ 7 ] = pVideoMemory[ ii + 7 ] ; + ii += 0x08 ; + } + + ii = 0x118 ; + for( j = 3 ; j < 24 ; j++ ) + { + pVBInfo->CR40[ j ][ 0 ] = pVideoMemory[ ii ] ; + pVBInfo->CR40[ j ][ 1 ] = pVideoMemory[ ii + 1 ] ; + pVBInfo->CR40[ j ][ 2 ] = pVideoMemory[ ii + 2 ] ; + pVBInfo->CR40[ j ][ 3 ] = pVideoMemory[ ii + 3 ] ; + pVBInfo->CR40[ j ][ 4 ] = pVideoMemory[ ii + 4 ] ; + pVBInfo->CR40[ j ][ 5 ] = pVideoMemory[ ii + 5 ] ; + pVBInfo->CR40[ j ][ 6 ] = pVideoMemory[ ii + 6 ] ; + pVBInfo->CR40[ j ][ 7 ] = pVideoMemory[ ii + 7 ] ; + ii += 0x08 ; + } + + i = pVideoMemory[ 0x1C0 ] | ( pVideoMemory[ 0x1C1 ] << 8 ) ; + + for( j = 0 ; j < 8 ; j++ ) + { + for( k = 0 ; k < 4 ; k++ ) + pVBInfo->CR6B[ j ][ k ] = pVideoMemory[ i + 4 * j + k ] ; + } + + i = pVideoMemory[ 0x1C2 ] | ( pVideoMemory[ 0x1C3 ] << 8 ) ; + + for( j = 0 ; j < 8 ; j++ ) + { + for( k = 0 ; k < 4 ; k++ ) + pVBInfo->CR6E[ j ][ k ] = pVideoMemory[ i + 4 * j + k ] ; + } + + i = pVideoMemory[ 0x1C4 ] | ( pVideoMemory[ 0x1C5 ] << 8 ) ; + for( j = 0 ; j < 8 ; j++ ) + { + for( k = 0 ; k < 32 ; k++ ) + pVBInfo->CR6F[ j ][ k ] = pVideoMemory[ i + 32 * j + k ] ; + } + + i = pVideoMemory[ 0x1C6 ] | ( pVideoMemory[ 0x1C7 ] << 8 ) ; + + for( j = 0 ; j < 8 ; j++ ) + { + for( k = 0 ; k < 2 ; k++ ) + pVBInfo->CR89[ j ][ k ] = pVideoMemory[ i + 2 * j + k ] ; + } + + i = pVideoMemory[ 0x1C8 ] | ( pVideoMemory[ 0x1C9 ] << 8 ) ; + for( j = 0 ; j < 12 ; j++ ) + pVBInfo->AGPReg[ j ] = pVideoMemory[ i + j ] ; + + i = pVideoMemory[ 0x1CF ] | ( pVideoMemory[ 0x1D0 ] << 8 ) ; + for( j = 0 ; j < 4 ; j++ ) + pVBInfo->SR16[ j ] = pVideoMemory[ i + j ] ; + + if ( ChipType == XG21 ) + { + if (pVideoMemory[ 0x67 ] & 0x80) + { + *pVBInfo->pDVOSetting = pVideoMemory[ 0x67 ]; + } + if ( (pVideoMemory[ 0x67 ] & 0xC0) == 0xC0 ) + { + *pVBInfo->pCR2E = pVideoMemory[ i + 4 ] ; + *pVBInfo->pCR2F = pVideoMemory[ i + 5 ] ; + *pVBInfo->pCR46 = pVideoMemory[ i + 6 ] ; + *pVBInfo->pCR47 = pVideoMemory[ i + 7 ] ; + } + } + + if ( ChipType == XG27 ) + { + jj = i+j; + for( i = 0 ; i <= 0xB ; i++,jj++ ) + pVBInfo->pCRD0[i] = pVideoMemory[ jj ] ; + for( i = 0x0 ; i <= 0x1 ; i++,jj++ ) + pVBInfo->pCRDE[i] = pVideoMemory[ jj ] ; + + *pVBInfo->pSR40 = pVideoMemory[ jj ] ; + jj++; + *pVBInfo->pSR41 = pVideoMemory[ jj ] ; + + if (pVideoMemory[ 0x67 ] & 0x80) + { + *pVBInfo->pDVOSetting = pVideoMemory[ 0x67 ]; + } + if ( (pVideoMemory[ 0x67 ] & 0xC0) == 0xC0 ) + { + jj++; + *pVBInfo->pCR2E = pVideoMemory[ jj ] ; + *pVBInfo->pCR2F = pVideoMemory[ jj + 1 ] ; + *pVBInfo->pCR46 = pVideoMemory[ jj + 2 ] ; + *pVBInfo->pCR47 = pVideoMemory[ jj + 3 ] ; + } + + } + + *pVBInfo->pCRCF = pVideoMemory[ 0x1CA ] ; + *pVBInfo->pXGINew_DRAMTypeDefinition = pVideoMemory[ 0x1CB ] ; + *pVBInfo->pXGINew_I2CDefinition = pVideoMemory[ 0x1D1 ] ; + if ( ChipType >= XG20 ) + { + *pVBInfo->pXGINew_CR97 = pVideoMemory[ 0x1D2 ] ; + if ( ChipType == XG27 ) + { + *pVBInfo->pSR36 = pVideoMemory[ 0x1D3 ] ; + *pVBInfo->pCR8F = pVideoMemory[ 0x1D5 ] ; + } + } + + } +#endif + /* Volari customize data area end */ + + if ( ChipType == XG21 ) + { + pVBInfo->IF_DEF_LVDS = 0 ; + if (pVideoMemory[ 0x65 ] & 0x1) + { + pVBInfo->IF_DEF_LVDS = 1 ; + i = pVideoMemory[ 0x316 ] | ( pVideoMemory[ 0x317 ] << 8 ); + j = pVideoMemory[ i-1 ] ; + if ( j != 0xff ) + { + k = 0; + do + { + pVBInfo->XG21_LVDSCapList[k].LVDS_Capability = pVideoMemory[ i ] | ( pVideoMemory[ i + 1 ] << 8 ); + pVBInfo->XG21_LVDSCapList[k].LVDSHT = pVideoMemory[ i + 2 ] | ( pVideoMemory[ i + 3 ] << 8 ) ; + pVBInfo->XG21_LVDSCapList[k].LVDSVT = pVideoMemory[ i + 4 ] | ( pVideoMemory[ i + 5 ] << 8 ); + pVBInfo->XG21_LVDSCapList[k].LVDSHDE = pVideoMemory[ i + 6 ] | ( pVideoMemory[ i + 7 ] << 8 ); + pVBInfo->XG21_LVDSCapList[k].LVDSVDE = pVideoMemory[ i + 8 ] | ( pVideoMemory[ i + 9 ] << 8 ); + pVBInfo->XG21_LVDSCapList[k].LVDSHFP = pVideoMemory[ i + 10 ] | ( pVideoMemory[ i + 11 ] << 8 ); + pVBInfo->XG21_LVDSCapList[k].LVDSVFP = pVideoMemory[ i + 12 ] | ( pVideoMemory[ i + 13 ] << 8 ); + pVBInfo->XG21_LVDSCapList[k].LVDSHSYNC = pVideoMemory[ i + 14 ] | ( pVideoMemory[ i + 15 ] << 8 ); + pVBInfo->XG21_LVDSCapList[k].LVDSVSYNC = pVideoMemory[ i + 16 ] | ( pVideoMemory[ i + 17 ] << 8 ); + pVBInfo->XG21_LVDSCapList[k].VCLKData1 = pVideoMemory[ i + 18 ] ; + pVBInfo->XG21_LVDSCapList[k].VCLKData2 = pVideoMemory[ i + 19 ] ; + pVBInfo->XG21_LVDSCapList[k].PSC_S1 = pVideoMemory[ i + 20 ] ; + pVBInfo->XG21_LVDSCapList[k].PSC_S2 = pVideoMemory[ i + 21 ] ; + pVBInfo->XG21_LVDSCapList[k].PSC_S3 = pVideoMemory[ i + 22 ] ; + pVBInfo->XG21_LVDSCapList[k].PSC_S4 = pVideoMemory[ i + 23 ] ; + pVBInfo->XG21_LVDSCapList[k].PSC_S5 = pVideoMemory[ i + 24 ] ; + i += 25; + j--; + k++; + } while ( (j>0) && ( k < (sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct)) ) ); + } + else + { + pVBInfo->XG21_LVDSCapList[0].LVDS_Capability = pVideoMemory[ i ] | ( pVideoMemory[ i + 1 ] << 8 ); + pVBInfo->XG21_LVDSCapList[0].LVDSHT = pVideoMemory[ i + 2 ] | ( pVideoMemory[ i + 3 ] << 8 ) ; + pVBInfo->XG21_LVDSCapList[0].LVDSVT = pVideoMemory[ i + 4 ] | ( pVideoMemory[ i + 5 ] << 8 ); + pVBInfo->XG21_LVDSCapList[0].LVDSHDE = pVideoMemory[ i + 6 ] | ( pVideoMemory[ i + 7 ] << 8 ); + pVBInfo->XG21_LVDSCapList[0].LVDSVDE = pVideoMemory[ i + 8 ] | ( pVideoMemory[ i + 9 ] << 8 ); + pVBInfo->XG21_LVDSCapList[0].LVDSHFP = pVideoMemory[ i + 10 ] | ( pVideoMemory[ i + 11 ] << 8 ); + pVBInfo->XG21_LVDSCapList[0].LVDSVFP = pVideoMemory[ i + 12 ] | ( pVideoMemory[ i + 13 ] << 8 ); + pVBInfo->XG21_LVDSCapList[0].LVDSHSYNC = pVideoMemory[ i + 14 ] | ( pVideoMemory[ i + 15 ] << 8 ); + pVBInfo->XG21_LVDSCapList[0].LVDSVSYNC = pVideoMemory[ i + 16 ] | ( pVideoMemory[ i + 17 ] << 8 ); + pVBInfo->XG21_LVDSCapList[0].VCLKData1 = pVideoMemory[ i + 18 ] ; + pVBInfo->XG21_LVDSCapList[0].VCLKData2 = pVideoMemory[ i + 19 ] ; + pVBInfo->XG21_LVDSCapList[0].PSC_S1 = pVideoMemory[ i + 20 ] ; + pVBInfo->XG21_LVDSCapList[0].PSC_S2 = pVideoMemory[ i + 21 ] ; + pVBInfo->XG21_LVDSCapList[0].PSC_S3 = pVideoMemory[ i + 22 ] ; + pVBInfo->XG21_LVDSCapList[0].PSC_S4 = pVideoMemory[ i + 23 ] ; + pVBInfo->XG21_LVDSCapList[0].PSC_S5 = pVideoMemory[ i + 24 ] ; + } + } + } +} + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_DDR1x_MRS_XG20 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_DDR1x_MRS_XG20( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo) +{ + + XGINew_SetReg1( P3c4 , 0x18 , 0x01 ) ; + XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + DelayUS( 60 ) ; + + XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; + DelayUS( 60 ) ; + XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */ + /* XGINew_SetReg1( P3c4 , 0x18 , 0x31 ) ; */ + XGINew_SetReg1( P3c4 , 0x19 , 0x01 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x03 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x83 ) ; + DelayUS( 1000 ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x03 ) ; + DelayUS( 500 ) ; + /* XGINew_SetReg1( P3c4 , 0x18 , 0x31 ) ; */ + XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */ + XGINew_SetReg1( P3c4 , 0x19 , 0x00 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x03 ) ; + XGINew_SetReg1( P3c4 , 0x16 , 0x83 ) ; + XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ; +} + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetDRAMModeRegister_XG20 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetDRAMModeRegister_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension ) +{ + VB_DEVICE_INFO VBINF; + PVB_DEVICE_INFO pVBInfo = &VBINF; + pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ; + pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; + pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ; + pVBInfo->ISXPDOS = 0 ; + + pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ; + pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ; + pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ; + pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ; + pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ; + pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ; + pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ; + pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ; + pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ; + pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ; + pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ; + pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ; + pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ; + pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ; + pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ; + pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ; + pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ; + + InitTo330Pointer(HwDeviceExtension->jChipType,pVBInfo); + + ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ; + + if ( XGINew_GetXG20DRAMType( HwDeviceExtension, pVBInfo) == 0 ) + XGINew_DDR1x_MRS_XG20( pVBInfo->P3c4, pVBInfo ) ; + else + XGINew_DDR2_MRS_XG20( HwDeviceExtension , pVBInfo->P3c4 , pVBInfo ) ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , 0x03 ) ; +} + +void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension ) +{ + VB_DEVICE_INFO VBINF; + PVB_DEVICE_INFO pVBInfo = &VBINF; + pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ; + pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; + pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ; + pVBInfo->ISXPDOS = 0 ; + + pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ; + pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ; + pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ; + pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ; + pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ; + pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ; + pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ; + pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ; + pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ; + pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ; + pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ; + pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ; + pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ; + pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ; + pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ; + pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ; + pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ; + + InitTo330Pointer(HwDeviceExtension->jChipType,pVBInfo); + + ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ; + + if ( XGINew_GetXG20DRAMType( HwDeviceExtension, pVBInfo) == 0 ) + XGINew_DDR1x_MRS_XG20( pVBInfo->P3c4, pVBInfo ) ; + else + //XGINew_DDR2_MRS_XG27( HwDeviceExtension , pVBInfo->P3c4 , pVBInfo ) ; + XGINew_DDRII_Bootup_XG27( HwDeviceExtension , pVBInfo->P3c4 , pVBInfo) ; + + //XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , 0x03 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , pVBInfo->SR15[ 3 ][ XGINew_RAMType ] ) ; /* SR1B */ + +} +/* +void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension ) +{ +#ifndef LINUX_XF86 + UCHAR data ; +#endif + VB_DEVICE_INFO VBINF; + PVB_DEVICE_INFO pVBInfo = &VBINF; + pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ; + pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; + pVBInfo->BaseAddr = HwDeviceExtension->pjIOAddress ; + pVBInfo->ISXPDOS = 0 ; + + pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ; + pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ; + pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ; + pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ; + pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ; + pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ; + pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ; + pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ; + pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ; + pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ; + pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ; + pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ; + pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ; + pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ; + pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ; + pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ; + pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ; + + InitTo330Pointer(HwDeviceExtension->jChipType,pVBInfo); + + ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ; + + if ( XGINew_GetXG20DRAMType( HwDeviceExtension, pVBInfo) == 0 ) + XGINew_DDR1x_MRS_XG20( pVBInfo->P3c4, pVBInfo ) ; + else + XGINew_DDR2_MRS_XG27( HwDeviceExtension , pVBInfo->P3c4 , pVBInfo ) ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , 0x03 ) ; +} +*/ +/* -------------------------------------------------------- */ +/* Function : XGINew_ChkSenseStatus */ +/* Input : */ +/* Output : */ +/* Description : */ +/* -------------------------------------------------------- */ +void XGINew_ChkSenseStatus ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempbx=0 , temp , tempcx , CR3CData; + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x32 ) ; + + if ( temp & Monitor1Sense ) + tempbx |= ActiveCRT1 ; + if ( temp & LCDSense ) + tempbx |= ActiveLCD ; + if ( temp & Monitor2Sense ) + tempbx |= ActiveCRT2 ; + if ( temp & TVSense ) + { + tempbx |= ActiveTV ; + if ( temp & AVIDEOSense ) + tempbx |= ( ActiveAVideo << 8 ); + if ( temp & SVIDEOSense ) + tempbx |= ( ActiveSVideo << 8 ); + if ( temp & SCARTSense ) + tempbx |= ( ActiveSCART << 8 ); + if ( temp & HiTVSense ) + tempbx |= ( ActiveHiTV << 8 ); + if ( temp & YPbPrSense ) + tempbx |= ( ActiveYPbPr << 8 ); + } + + tempcx = XGINew_GetReg1( pVBInfo->P3d4 , 0x3d ) ; + tempcx |= ( XGINew_GetReg1( pVBInfo->P3d4 , 0x3e ) << 8 ) ; + + if ( tempbx & tempcx ) + { + CR3CData = XGINew_GetReg1( pVBInfo->P3d4 , 0x3c ) ; + if ( !( CR3CData & DisplayDeviceFromCMOS ) ) + { + tempcx = 0x1FF0 ; + if ( *pVBInfo->pSoftSetting & ModeSoftSetting ) + { + tempbx = 0x1FF0 ; + } + } + } + else + { + tempcx = 0x1FF0 ; + if ( *pVBInfo->pSoftSetting & ModeSoftSetting ) + { + tempbx = 0x1FF0 ; + } + } + + tempbx &= tempcx ; + XGINew_SetReg1( pVBInfo->P3d4, 0x3d , ( tempbx & 0x00FF ) ) ; + XGINew_SetReg1( pVBInfo->P3d4, 0x3e , ( ( tempbx & 0xFF00 ) >> 8 )) ; +} +/* -------------------------------------------------------- */ +/* Function : XGINew_SetModeScratch */ +/* Input : */ +/* Output : */ +/* Description : */ +/* -------------------------------------------------------- */ +void XGINew_SetModeScratch ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) +{ + USHORT temp , tempcl = 0 , tempch = 0 , CR31Data , CR38Data; + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x3d ) ; + temp |= XGINew_GetReg1( pVBInfo->P3d4 , 0x3e ) << 8 ; + temp |= ( XGINew_GetReg1( pVBInfo->P3d4 , 0x31 ) & ( DriverMode >> 8) ) << 8 ; + + if ( pVBInfo->IF_DEF_CRT2Monitor == 1) + { + if ( temp & ActiveCRT2 ) + tempcl = SetCRT2ToRAMDAC ; + } + + if ( temp & ActiveLCD ) + { + tempcl |= SetCRT2ToLCD ; + if ( temp & DriverMode ) + { + if ( temp & ActiveTV ) + { + tempch = SetToLCDA | EnableDualEdge ; + temp ^= SetCRT2ToLCD ; + + if ( ( temp >> 8 ) & ActiveAVideo ) + tempcl |= SetCRT2ToAVIDEO ; + if ( ( temp >> 8 ) & ActiveSVideo ) + tempcl |= SetCRT2ToSVIDEO ; + if ( ( temp >> 8 ) & ActiveSCART ) + tempcl |= SetCRT2ToSCART ; + + if ( pVBInfo->IF_DEF_HiVision == 1 ) + { + if ( ( temp >> 8 ) & ActiveHiTV ) + tempcl |= SetCRT2ToHiVisionTV ; + } + + if ( pVBInfo->IF_DEF_YPbPr == 1 ) + { + if ( ( temp >> 8 ) & ActiveYPbPr ) + tempch |= SetYPbPr ; + } + } + } + } + else + { + if ( ( temp >> 8 ) & ActiveAVideo ) + tempcl |= SetCRT2ToAVIDEO ; + if ( ( temp >> 8 ) & ActiveSVideo ) + tempcl |= SetCRT2ToSVIDEO ; + if ( ( temp >> 8 ) & ActiveSCART ) + tempcl |= SetCRT2ToSCART ; + + if ( pVBInfo->IF_DEF_HiVision == 1 ) + { + if ( ( temp >> 8 ) & ActiveHiTV ) + tempcl |= SetCRT2ToHiVisionTV ; + } + + if ( pVBInfo->IF_DEF_YPbPr == 1 ) + { + if ( ( temp >> 8 ) & ActiveYPbPr ) + tempch |= SetYPbPr ; + } + } + + + tempcl |= SetSimuScanMode ; + if ( (!( temp & ActiveCRT1 )) && ( ( temp & ActiveLCD ) || ( temp & ActiveTV ) || ( temp & ActiveCRT2 ) ) ) + tempcl ^= ( SetSimuScanMode | SwitchToCRT2 ) ; + if ( ( temp & ActiveLCD ) && ( temp & ActiveTV ) ) + tempcl ^= ( SetSimuScanMode | SwitchToCRT2 ) ; + XGINew_SetReg1( pVBInfo->P3d4, 0x30 , tempcl ) ; + + CR31Data = XGINew_GetReg1( pVBInfo->P3d4 , 0x31 ) ; + CR31Data &= ~( SetNotSimuMode >> 8 ) ; + if ( !( temp & ActiveCRT1 ) ) + CR31Data |= ( SetNotSimuMode >> 8 ) ; + CR31Data &= ~( DisableCRT2Display >> 8 ) ; + if (!( ( temp & ActiveLCD ) || ( temp & ActiveTV ) || ( temp & ActiveCRT2 ) ) ) + CR31Data |= ( DisableCRT2Display >> 8 ) ; + XGINew_SetReg1( pVBInfo->P3d4, 0x31 , CR31Data ) ; + + CR38Data = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ; + CR38Data &= ~SetYPbPr ; + CR38Data |= tempch ; + XGINew_SetReg1( pVBInfo->P3d4, 0x38 , CR38Data ) ; + +} + +/* -------------------------------------------------------- */ +/* Function : XGINew_GetXG21Sense */ +/* Input : */ +/* Output : */ +/* Description : */ +/* -------------------------------------------------------- */ +void XGINew_GetXG21Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + UCHAR Temp; + PUCHAR volatile pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr ; + + pVBInfo->IF_DEF_LVDS = 0 ; + +#ifdef WIN2000 + pVBInfo->IF_DEF_CH7007 = 0 ; + if ( ( pVideoMemory[ 0x65 ] & 0x02 ) ) /* For XG21 CH7007 */ + { + /* VideoDebugPrint((0, "ReadVBIOSTablData: pVideoMemory[ 0x65 ] =%x\n",pVideoMemory[ 0x65 ])); */ + pVBInfo->IF_DEF_CH7007 = 1 ; /* [Billy] 07/05/03 */ + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0x60 ) ; /* CH7007 on chip */ + } + else +#endif +#if 1 + if (( pVideoMemory[ 0x65 ] & 0x01 ) ) /* For XG21 LVDS */ + { + pVBInfo->IF_DEF_LVDS = 1 ; + XGINew_SetRegOR( pVBInfo->P3d4 , 0x32 , LCDSense ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0xC0 ) ; /* LVDS on chip */ + } + else + { +#endif + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x03 , 0x03 ) ; /* Enable GPIOA/B read */ + Temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) & 0xC0; + if ( Temp == 0xC0 ) + { /* DVI & DVO GPIOA/B pull high */ + XGINew_SenseLCD( HwDeviceExtension, pVBInfo ) ; + XGINew_SetRegOR( pVBInfo->P3d4 , 0x32 , LCDSense ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x20 , 0x20 ) ; /* Enable read GPIOF */ + Temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) & 0x04 ; + if ( !Temp ) + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0x80 ) ; /* TMDS on chip */ + else + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0xA0 ) ; /* Only DVO on chip */ + XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x20 ) ; /* Disable read GPIOF */ + } +#if 1 + } +#endif +} + +/* -------------------------------------------------------- */ +/* Function : XGINew_GetXG27Sense */ +/* Input : */ +/* Output : */ +/* Description : */ +/* -------------------------------------------------------- */ +void XGINew_GetXG27Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + UCHAR Temp,bCR4A; + + pVBInfo->IF_DEF_LVDS = 0 ; + bCR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x07 , 0x07 ) ; /* Enable GPIOA/B/C read */ + Temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) & 0x07; + XGINew_SetReg1( pVBInfo->P3d4, 0x4A , bCR4A ) ; + + if ( Temp <= 0x02 ) + { + pVBInfo->IF_DEF_LVDS = 1 ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0xC0 ) ; /* LVDS setting */ + XGINew_SetReg1( pVBInfo->P3d4, 0x30 , 0x21 ) ; + } + else + { + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0xA0 ) ; /* TMDS/DVO setting */ + } + XGINew_SetRegOR( pVBInfo->P3d4 , 0x32 , LCDSense ) ; + +} + +UCHAR GetXG21FPBits(PVB_DEVICE_INFO pVBInfo) +{ + UCHAR CR38,CR4A,temp; + + CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x10 , 0x10 ) ; /* enable GPIOE read */ + CR38 = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ; + temp =0; + if ( ( CR38 & 0xE0 ) > 0x80 ) + { + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ; + temp &= 0x08; + temp >>= 3; + } + + XGINew_SetReg1( pVBInfo->P3d4, 0x4A , CR4A ) ; + + return temp; +} + +UCHAR GetXG27FPBits(PVB_DEVICE_INFO pVBInfo) +{ + UCHAR CR4A,temp; + + CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x03 , 0x03 ) ; /* enable GPIOA/B/C read */ + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ; + if ( temp <= 2 ) + { + temp &= 0x03; + } + else + { + temp = ((temp&0x04)>>1) || ((~temp)&0x01); + } + XGINew_SetReg1( pVBInfo->P3d4, 0x4A , CR4A ) ; + + return temp; +} + diff --git a/drivers/staging/xgifb/vb_init.h b/drivers/staging/xgifb/vb_init.h new file mode 100644 index 000000000000..1f39d9c74cdd --- /dev/null +++ b/drivers/staging/xgifb/vb_init.h @@ -0,0 +1,7 @@ +#ifndef _VBINIT_ +#define _VBINIT_ +extern BOOLEAN XGIInitNew( PXGI_HW_DEVICE_INFO HwDeviceExtension ) ; +extern XGI21_LVDSCapStruct XGI21_LCDCapList[13]; + +#endif + diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c new file mode 100644 index 000000000000..bd7f73898644 --- /dev/null +++ b/drivers/staging/xgifb/vb_setmode.c @@ -0,0 +1,10736 @@ +#include "osdef.h" + +#ifdef TC +#include <stdio.h> +#include <string.h> +#include <conio.h> +#include <dos.h> +#endif + + +#ifdef LINUX_XF86 +#include "xf86.h" +#include "xf86PciInfo.h" +#include "xgi.h" +#include "xgi_regs.h" +#endif + +#ifdef LINUX_KERNEL +#include <asm/io.h> +#include <linux/types.h> +#include <linux/version.h> +#include "XGIfb.h" +/*#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#include <video/XGIfb.h> +#else +#include <linux/XGIfb.h> +#endif*/ +#endif + +#ifdef WIN2000 +#include <dderror.h> +#include <devioctl.h> +#include <miniport.h> +#include <ntddvdeo.h> +#include <video.h> + +#include "xgiv.h" +#include "dd_i2c.h" +#include "tools.h" +#endif + +#include "vb_def.h" +#include "vgatypes.h" +#include "vb_struct.h" +#include "vb_util.h" +#include "vb_table.h" + + + +#define IndexMask 0xff +#ifndef XGI_MASK_DUAL_CHIP +#define XGI_MASK_DUAL_CHIP 0x04 /* SR3A */ +#endif + + + +BOOLEAN XGI_IsLCDDualLink(PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGI_SetCRT2Group301(USHORT ModeNo, PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGI_BacklightByDrv(PVB_DEVICE_INFO pVBInfo); + +BOOLEAN XGI_IsLCDON(PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGI_DisableChISLCD(PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGI_EnableChISLCD(PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGI_AjustCRT2Rate(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,USHORT *i, PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGI_SearchModeID( USHORT ModeNo,USHORT *ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGI_GetLCDInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo ) ; +BOOLEAN XGI_BridgeIsOn(PVB_DEVICE_INFO pVBInfo); +UCHAR XGI_GetModePtr( USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo); +USHORT XGI_GetOffset(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo); +USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo ); +USHORT XGI_GetResInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +USHORT XGI_GetColorDepth(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo); +USHORT XGI_GetVGAHT2(PVB_DEVICE_INFO pVBInfo); +USHORT XGI_GetVCLK2Ptr(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo); +void XGI_VBLongWait(PVB_DEVICE_INFO pVBInfo); +void XGI_SaveCRT2Info(USHORT ModeNo, PVB_DEVICE_INFO pVBInfo); +void XGI_GetCRT2Data(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_GetCRT2ResInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_PreSetGroup1(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetGroup1(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetLockRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetLCDRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetGroup2(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo); +void XGI_SetGroup3(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetGroup4(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo); +void XGI_SetGroup5(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +void* XGI_GetLcdPtr(USHORT BX, USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void* XGI_GetTVPtr(USHORT BX, USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_FirePWDEnable(PVB_DEVICE_INFO pVBInfo); +void XGI_EnableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo); +void XGI_DisableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo); +void XGI_SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo); +void XGI_SetPanelPower(USHORT tempah,USHORT tempbl, PVB_DEVICE_INFO pVBInfo); +void XGI_EnablePWD( PVB_DEVICE_INFO pVBInfo); +void XGI_DisablePWD( PVB_DEVICE_INFO pVBInfo); +void XGI_AutoThreshold( PVB_DEVICE_INFO pVBInfo); +void XGI_SetTap4Regs( PVB_DEVICE_INFO pVBInfo); + +void XGI_DisplayOn(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo); +void XGI_DisplayOff( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo ); +void XGI_SetCRT1Group(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo); +void XGI_SetXG21CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetXG21LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo); +void XGI_SetXG27CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetXG27LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo); +void XGI_UpdateXG21CRTC(USHORT ModeNo, PVB_DEVICE_INFO pVBInfo, USHORT RefreshRateTableIndex); +void XGI_WaitDisply(PVB_DEVICE_INFO pVBInfo); +void XGI_SenseCRT1(PVB_DEVICE_INFO pVBInfo); +void XGI_SetSeqRegs(USHORT ModeNo,USHORT StandTableIndex,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo); +void XGI_SetMiscRegs(USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetCRTCRegs(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetATTRegs(USHORT ModeNo,USHORT StandTableIndex,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo ); +void XGI_SetGRCRegs(USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_ClearExt1Regs(PVB_DEVICE_INFO pVBInfo); + +void XGI_SetSync(USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo); +void XGI_SetCRT1CRTC(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo,PXGI_HW_DEVICE_INFO HwDeviceExtension); +void XGI_SetCRT1Timing_H(PVB_DEVICE_INFO pVBInfo,PXGI_HW_DEVICE_INFO HwDeviceExtension); +void XGI_SetCRT1Timing_V(USHORT ModeIdIndex,USHORT ModeNo,PVB_DEVICE_INFO pVBInfo); +void XGI_SetCRT1DE(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo); +void XGI_SetCRT1VCLK(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetCRT1FIFO(USHORT ModeNo,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo); +void XGI_SetCRT1ModeRegs(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo); +void XGI_SetVCLKState(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo); + +void XGI_LoadDAC(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo); +void XGI_WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh, PVB_DEVICE_INFO pVBInfo); +/*void XGI_ClearBuffer(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,PVB_DEVICE_INFO pVBInfo);*/ +void XGI_SetLCDAGroup(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo); +void XGI_GetLVDSResInfo( USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo); +void XGI_GetLVDSData(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo); +void XGI_ModCRT1Regs(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo); +void XGI_SetLVDSRegs(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo); +void XGI_UpdateModeInfo(PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo); +void XGI_GetVGAType(PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo); +void XGI_GetVBType(PVB_DEVICE_INFO pVBInfo); +void XGI_GetVBInfo(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo); +void XGI_GetTVInfo(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo); +void XGI_SetCRT2ECLK( USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo); +void InitTo330Pointer(UCHAR,PVB_DEVICE_INFO pVBInfo); +void XGI_GetLCDSync(USHORT* HSyncWidth, USHORT* VSyncWidth, PVB_DEVICE_INFO pVBInfo); +void XGI_DisableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo); +void XGI_EnableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo); +void XGI_SetCRT2VCLK(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_OEM310Setting(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetDelayComp(PVB_DEVICE_INFO pVBInfo); +void XGI_SetLCDCap(PVB_DEVICE_INFO pVBInfo); +void XGI_SetLCDCap_A(USHORT tempcx,PVB_DEVICE_INFO pVBInfo); +void XGI_SetLCDCap_B(USHORT tempcx,PVB_DEVICE_INFO pVBInfo); +void SetSpectrum(PVB_DEVICE_INFO pVBInfo); +void XGI_SetAntiFlicker(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetEdgeEnhance(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_SetPhaseIncr(PVB_DEVICE_INFO pVBInfo); +void XGI_SetYFilter(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_GetTVPtrIndex2(USHORT* tempbx,UCHAR* tempcl,UCHAR* tempch, PVB_DEVICE_INFO pVBInfo); +USHORT XGI_GetTVPtrIndex( PVB_DEVICE_INFO pVBInfo ); +void XGI_SetCRT2ModeRegs(USHORT ModeNo,PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo ); +void XGI_CloseCRTC(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo); +void XGI_OpenCRTC(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo); +void XGI_GetRAMDAC2DATA(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_UnLockCRT2(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo); +void XGI_LockCRT2(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo); +void XGINew_EnableCRT2(PVB_DEVICE_INFO pVBInfo); +void XGINew_LCD_Wait_Time(UCHAR DelayTime, PVB_DEVICE_INFO pVBInfo); +void XGI_LongWait(PVB_DEVICE_INFO pVBInfo); +void XGI_SetCRT1Offset( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo ); +void XGI_GetLCDVCLKPtr(UCHAR* di_0,UCHAR *di_1, PVB_DEVICE_INFO pVBInfo); +UCHAR XGI_GetVCLKPtr(USHORT RefreshRateTableIndex,USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); +void XGI_GetVCLKLen(UCHAR tempal,UCHAR* di_0,UCHAR* di_1, PVB_DEVICE_INFO pVBInfo); +USHORT XGI_GetLCDCapPtr(PVB_DEVICE_INFO pVBInfo); +USHORT XGI_GetLCDCapPtr1(PVB_DEVICE_INFO pVBInfo); +XGI301C_Tap4TimingStruct* XGI_GetTap4Ptr(USHORT tempcx, PVB_DEVICE_INFO pVBInfo); +void XGI_SetXG21FPBits(PVB_DEVICE_INFO pVBInfo); +void XGI_SetXG27FPBits(PVB_DEVICE_INFO pVBInfo); +UCHAR XGI_XG21GetPSCValue(PVB_DEVICE_INFO pVBInfo); +UCHAR XGI_XG27GetPSCValue(PVB_DEVICE_INFO pVBInfo); +void XGI_XG21BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo); +void XGI_XG27BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo); +void XGI_XG21SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo); +BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ); +void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ); +void XGI_SetXG27LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ); +UCHAR XGI_SetDefaultVCLK( PVB_DEVICE_INFO pVBInfo ); + +extern void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo); +#ifdef WIN2000 +/* [Billy] 2007/05/17 For CH7007 */ +extern UCHAR CH7007TVReg_UNTSC[][8],CH7007TVReg_ONTSC[][8],CH7007TVReg_UPAL[][8],CH7007TVReg_OPAL[][8]; +extern UCHAR CH7007TVCRT1UNTSC_H[][10],CH7007TVCRT1ONTSC_H[][10],CH7007TVCRT1UPAL_H[][10],CH7007TVCRT1OPAL_H[][10] ; +extern UCHAR CH7007TVCRT1UNTSC_V[][10],CH7007TVCRT1ONTSC_V[][10],CH7007TVCRT1UPAL_V[][10],CH7007TVCRT1OPAL_V[][10] ; +extern UCHAR XGI7007_CHTVVCLKUNTSC[],XGI7007_CHTVVCLKONTSC[],XGI7007_CHTVVCLKUPAL[],XGI7007_CHTVVCLKOPAL[]; + +extern BOOLEAN XGI_XG21CheckCH7007TVMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) ; +extern void SetCH7007Regs(PXGI_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) ; +extern VP_STATUS TurnOnCH7007(PHW_DEVICE_EXTENSION pHWDE) ; +extern VP_STATUS TurnOffCH7007(PHW_DEVICE_EXTENSION pHWDE) ; +extern BOOLEAN IsCH7007TVMode(PVB_DEVICE_INFO pVBInfo) ; +#endif + +/* USHORT XGINew_flag_clearbuffer; 0: no clear frame buffer 1:clear frame buffer */ + + + + + +USHORT XGINew_MDA_DAC[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F}; + +USHORT XGINew_CGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F}; + +USHORT XGINew_EGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, + 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, + 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, + 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, + 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, + 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, + 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F}; + +USHORT XGINew_VGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, + 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, + 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, + 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, + + 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, + 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, + 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, + 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, + 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, + 0x0B,0x0C,0x0D,0x0F,0x10}; + + +/* --------------------------------------------------------------------- */ +/* Function : InitTo330Pointer */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void InitTo330Pointer( UCHAR ChipType ,PVB_DEVICE_INFO pVBInfo) +{ + pVBInfo->SModeIDTable = (XGI_StStruct *) XGI330_SModeIDTable ; + pVBInfo->StandTable = (XGI_StandTableStruct *) XGI330_StandTable ; + pVBInfo->EModeIDTable = (XGI_ExtStruct *) XGI330_EModeIDTable ; + pVBInfo->RefIndex = (XGI_Ext2Struct *) XGI330_RefIndex ; + pVBInfo->XGINEWUB_CRT1Table = (XGI_CRT1TableStruct *) XGI_CRT1Table ; + + /* add for new UNIVGABIOS */ + /* XGINew_UBLCDDataTable = (XGI_LCDDataTablStruct *) XGI_LCDDataTable ; */ + /* XGINew_UBTVDataTable = (XGI_TVDataTablStruct *) XGI_TVDataTable ; */ + + + if ( ChipType >= XG40 ) + { + pVBInfo->MCLKData = (XGI_MCLKDataStruct *) XGI340New_MCLKData ; + pVBInfo->ECLKData = (XGI_ECLKDataStruct *) XGI340_ECLKData ; + } + else + { + pVBInfo->MCLKData = (XGI_MCLKDataStruct *) XGI330New_MCLKData ; + pVBInfo->ECLKData = (XGI_ECLKDataStruct *) XGI330_ECLKData ; + } + + pVBInfo->VCLKData = (XGI_VCLKDataStruct *) XGI_VCLKData ; + pVBInfo->VBVCLKData = (XGI_VBVCLKDataStruct *) XGI_VBVCLKData ; + pVBInfo->ScreenOffset = XGI330_ScreenOffset ; + pVBInfo->StResInfo = (XGI_StResInfoStruct *) XGI330_StResInfo ; + pVBInfo->ModeResInfo = (XGI_ModeResInfoStruct *) XGI330_ModeResInfo ; + + pVBInfo->pOutputSelect = &XGI330_OutputSelect ; + pVBInfo->pSoftSetting = &XGI330_SoftSetting ; + pVBInfo->pSR07 = &XGI330_SR07 ; + pVBInfo->LCDResInfo = 0 ; + pVBInfo->LCDTypeInfo = 0 ; + pVBInfo->LCDInfo = 0 ; + pVBInfo->VBInfo = 0 ; + pVBInfo->TVInfo = 0; + + + pVBInfo->SR15 = XGI340_SR13 ; + pVBInfo->CR40 = XGI340_cr41 ; + pVBInfo->SR25 = XGI330_sr25 ; + pVBInfo->pSR31 = &XGI330_sr31 ; + pVBInfo->pSR32 = &XGI330_sr32 ; + pVBInfo->CR6B = XGI340_CR6B ; + pVBInfo->CR6E = XGI340_CR6E ; + pVBInfo->CR6F = XGI340_CR6F ; + pVBInfo->CR89 = XGI340_CR89 ; + pVBInfo->AGPReg = XGI340_AGPReg ; + pVBInfo->SR16 = XGI340_SR16 ; + pVBInfo->pCRCF = &XG40_CRCF ; + pVBInfo->pXGINew_DRAMTypeDefinition = &XG40_DRAMTypeDefinition ; + + + pVBInfo->CR49 = XGI330_CR49 ; + pVBInfo->pSR1F = &XGI330_SR1F ; + pVBInfo->pSR21 = &XGI330_SR21 ; + pVBInfo->pSR22 = &XGI330_SR22 ; + pVBInfo->pSR23 = &XGI330_SR23 ; + pVBInfo->pSR24 = &XGI330_SR24 ; + pVBInfo->pSR33 = &XGI330_SR33 ; + + + + pVBInfo->pCRT2Data_1_2 = &XGI330_CRT2Data_1_2 ; + pVBInfo->pCRT2Data_4_D = &XGI330_CRT2Data_4_D ; + pVBInfo->pCRT2Data_4_E = &XGI330_CRT2Data_4_E ; + pVBInfo->pCRT2Data_4_10 = &XGI330_CRT2Data_4_10 ; + pVBInfo->pRGBSenseData = &XGI330_RGBSenseData ; + pVBInfo->pVideoSenseData = &XGI330_VideoSenseData ; + pVBInfo->pYCSenseData = &XGI330_YCSenseData ; + pVBInfo->pRGBSenseData2 = &XGI330_RGBSenseData2 ; + pVBInfo->pVideoSenseData2 = &XGI330_VideoSenseData2 ; + pVBInfo->pYCSenseData2 = &XGI330_YCSenseData2 ; + + pVBInfo->NTSCTiming = XGI330_NTSCTiming ; + pVBInfo->PALTiming = XGI330_PALTiming ; + pVBInfo->HiTVExtTiming = XGI330_HiTVExtTiming ; + pVBInfo->HiTVSt1Timing = XGI330_HiTVSt1Timing ; + pVBInfo->HiTVSt2Timing = XGI330_HiTVSt2Timing ; + pVBInfo->HiTVTextTiming = XGI330_HiTVTextTiming ; + pVBInfo->YPbPr750pTiming = XGI330_YPbPr750pTiming ; + pVBInfo->YPbPr525pTiming = XGI330_YPbPr525pTiming ; + pVBInfo->YPbPr525iTiming = XGI330_YPbPr525iTiming ; + pVBInfo->HiTVGroup3Data = XGI330_HiTVGroup3Data ; + pVBInfo->HiTVGroup3Simu = XGI330_HiTVGroup3Simu ; + pVBInfo->HiTVGroup3Text = XGI330_HiTVGroup3Text ; + pVBInfo->Ren525pGroup3 = XGI330_Ren525pGroup3 ; + pVBInfo->Ren750pGroup3 = XGI330_Ren750pGroup3 ; + + + pVBInfo->TimingH = (XGI_TimingHStruct *) XGI_TimingH ; + pVBInfo->TimingV = (XGI_TimingVStruct *) XGI_TimingV ; + pVBInfo->UpdateCRT1 = (XGI_XG21CRT1Struct *) XGI_UpdateCRT1Table ; + + pVBInfo->CHTVVCLKUNTSC = XGI330_CHTVVCLKUNTSC ; + pVBInfo->CHTVVCLKONTSC = XGI330_CHTVVCLKONTSC ; + pVBInfo->CHTVVCLKUPAL = XGI330_CHTVVCLKUPAL ; + pVBInfo->CHTVVCLKOPAL = XGI330_CHTVVCLKOPAL ; + + /* 310 customization related */ + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + pVBInfo->LCDCapList = XGI_LCDDLCapList ; + else + pVBInfo->LCDCapList = XGI_LCDCapList ; + + if ( ( ChipType == XG21 ) || ( ChipType == XG27 ) ) + pVBInfo->XG21_LVDSCapList = XGI21_LCDCapList ; + + pVBInfo->XGI_TVDelayList = XGI301TVDelayList ; + pVBInfo->XGI_TVDelayList2 = XGI301TVDelayList2 ; + + + pVBInfo->pXGINew_I2CDefinition = &XG40_I2CDefinition ; + + if ( ChipType >= XG20 ) + pVBInfo->pXGINew_CR97 = &XG20_CR97 ; + + if ( ChipType == XG27 ) + { + pVBInfo->MCLKData = (XGI_MCLKDataStruct *) XGI27New_MCLKData ; + pVBInfo->CR40 = XGI27_cr41 ; + pVBInfo->pXGINew_CR97 = &XG27_CR97 ; + pVBInfo->pSR36 = &XG27_SR36 ; + pVBInfo->pCR8F = &XG27_CR8F ; + pVBInfo->pCRD0 = XG27_CRD0 ; + pVBInfo->pCRDE = XG27_CRDE ; + pVBInfo->pSR40 = &XG27_SR40 ; + pVBInfo->pSR41 = &XG27_SR41 ; + + } + + if ( ChipType >= XG20 ) + { + pVBInfo->pDVOSetting = &XG21_DVOSetting ; + pVBInfo->pCR2E = &XG21_CR2E ; + pVBInfo->pCR2F = &XG21_CR2F ; + pVBInfo->pCR46 = &XG21_CR46 ; + pVBInfo->pCR47 = &XG21_CR47 ; + } + +} + + + + + + +/* --------------------------------------------------------------------- */ +/* Function : XGISetModeNew */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo ) +{ + USHORT ModeIdIndex ; + /* PUCHAR pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; */ + VB_DEVICE_INFO VBINF; + PVB_DEVICE_INFO pVBInfo = &VBINF; + pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ; + pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ; + pVBInfo->IF_DEF_LVDS = 0 ; + pVBInfo->IF_DEF_CH7005 = 0 ; + pVBInfo->IF_DEF_LCDA = 1 ; + pVBInfo->IF_DEF_CH7017 = 0 ; + pVBInfo->IF_DEF_CH7007 = 0 ; /* [Billy] 2007/05/14 */ + pVBInfo->IF_DEF_VideoCapture = 0 ; + pVBInfo->IF_DEF_ScaleLCD = 0 ; + pVBInfo->IF_DEF_OEMUtil = 0 ; + pVBInfo->IF_DEF_PWD = 0 ; + + + if ( HwDeviceExtension->jChipType >= XG20 ) /* kuku 2004/06/25 */ + { + pVBInfo->IF_DEF_YPbPr = 0 ; + pVBInfo->IF_DEF_HiVision = 0 ; + pVBInfo->IF_DEF_CRT2Monitor = 0 ; + pVBInfo->VBType = 0 ; /*set VBType default 0*/ + } + else if ( HwDeviceExtension->jChipType >= XG40 ) + { + pVBInfo->IF_DEF_YPbPr = 1 ; + pVBInfo->IF_DEF_HiVision = 1 ; + pVBInfo->IF_DEF_CRT2Monitor = 1 ; + } + else + { + pVBInfo->IF_DEF_YPbPr = 1 ; + pVBInfo->IF_DEF_HiVision = 1 ; + pVBInfo->IF_DEF_CRT2Monitor = 0 ; + } + + pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ; + pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ; + pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ; + pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ; + pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ; + pVBInfo->P3cc = pVBInfo->BaseAddr + 0x1C ; + pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ; + pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ; + pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ; + pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ; + pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ; + pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ; + pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ; + pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ; + pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ; + pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ; + pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ; + pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ; + + if ( HwDeviceExtension->jChipType == XG21 ) /* for x86 Linux, XG21 LVDS */ + { + if ( ( XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) & 0xE0 ) == 0xC0 ) + { + pVBInfo->IF_DEF_LVDS = 1 ; + } + } + if ( HwDeviceExtension->jChipType == XG27 ) + { + if ( ( XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) & 0xE0 ) == 0xC0 ) + { + if ( XGINew_GetReg1( pVBInfo->P3d4 , 0x30 ) & 0x20 ) + { + pVBInfo->IF_DEF_LVDS = 1 ; + } + } + } + + if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */ + XGI_GetVBType( pVBInfo ) ; + + InitTo330Pointer( HwDeviceExtension->jChipType, pVBInfo ) ; +#ifdef WIN2000 + ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ; +#endif + if ( ModeNo & 0x80 ) + { + ModeNo = ModeNo & 0x7F ; +/* XGINew_flag_clearbuffer = 0 ; */ + } +/* else + { + XGINew_flag_clearbuffer = 1 ; + } +*/ + XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ; + + if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 1.Openkey */ + XGI_UnLockCRT2( HwDeviceExtension , pVBInfo ) ; + + XGI_SearchModeID( ModeNo , &ModeIdIndex, pVBInfo ) ; + + XGI_GetVGAType(HwDeviceExtension, pVBInfo) ; + + if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */ + { + XGI_GetVBInfo(ModeNo , ModeIdIndex , HwDeviceExtension, pVBInfo ) ; + XGI_GetTVInfo(ModeNo , ModeIdIndex, pVBInfo ) ; + XGI_GetLCDInfo(ModeNo , ModeIdIndex, pVBInfo ) ; + XGI_DisableBridge( HwDeviceExtension,pVBInfo ) ; +/* XGI_OpenCRTC( HwDeviceExtension, pVBInfo ) ; */ + + if ( pVBInfo->VBInfo & ( SetSimuScanMode | SetCRT2ToLCDA ) ) + { + XGI_SetCRT1Group(HwDeviceExtension , ModeNo , ModeIdIndex, pVBInfo ) ; + + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + { + XGI_SetLCDAGroup(ModeNo , ModeIdIndex , HwDeviceExtension, pVBInfo ) ; + } + } + else + { + if ( !( pVBInfo->VBInfo & SwitchToCRT2) ) + { + XGI_SetCRT1Group( HwDeviceExtension , ModeNo , ModeIdIndex, pVBInfo ) ; + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + { + XGI_SetLCDAGroup( ModeNo , ModeIdIndex , HwDeviceExtension, pVBInfo ) ; + } + } + } + + if ( pVBInfo->VBInfo & ( SetSimuScanMode | SwitchToCRT2 ) ) + { + switch( HwDeviceExtension->ujVBChipID ) + { + case VB_CHIP_301: + XGI_SetCRT2Group301( ModeNo , HwDeviceExtension, pVBInfo ) ; /*add for CRT2 */ + break ; + + case VB_CHIP_302: + XGI_SetCRT2Group301(ModeNo , HwDeviceExtension, pVBInfo ) ; /*add for CRT2 */ + break ; + + default: + break ; + } + } + + XGI_SetCRT2ModeRegs( ModeNo, HwDeviceExtension,pVBInfo ) ; + XGI_OEM310Setting( ModeNo, ModeIdIndex,pVBInfo ) ; /*0212*/ + XGI_CloseCRTC( HwDeviceExtension, pVBInfo ) ; + XGI_EnableBridge( HwDeviceExtension ,pVBInfo) ; + } /* !XG20 */ + else + { +#ifdef WIN2000 + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + + VideoDebugPrint((0, "XGISetModeNew: pVBIfo->IF_DEF_CH7007==1\n")); + pVBInfo->VBType = VB_CH7007 ; + XGI_GetVBInfo(ModeNo , ModeIdIndex , HwDeviceExtension, pVBInfo ) ; + XGI_GetTVInfo(ModeNo , ModeIdIndex, pVBInfo ) ; + XGI_GetLCDInfo(ModeNo , ModeIdIndex, pVBInfo ) ; + if( !(XGI_XG21CheckCH7007TVMode(ModeNo, ModeIdIndex, pVBInfo )) ) + { + return FALSE; + } + } +#endif + + + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + if ( !XGI_XG21CheckLVDSMode(ModeNo , ModeIdIndex, pVBInfo) ) + { + return FALSE; + } + } + + if ( ModeNo <= 0x13 ) + { + pVBInfo->ModeType = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag & ModeInfoFlag; + } + else + { + pVBInfo->ModeType = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag & ModeInfoFlag; + } + + pVBInfo->SetFlag = 0 ; + if ( pVBInfo->IF_DEF_CH7007 != 1 ) + { + pVBInfo->VBInfo = DisableCRT2Display ; + } + + + XGI_DisplayOff(HwDeviceExtension, pVBInfo) ; + + XGI_SetCRT1Group(HwDeviceExtension , ModeNo , ModeIdIndex, pVBInfo ) ; + + XGI_DisplayOn( HwDeviceExtension, pVBInfo ) ; + /* + if( HwDeviceExtension->jChipType == XG21 ) + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x09 , ~0x80 , 0x80 ) ; + */ + } + + +/* + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + } + pVBInfo->ModeType = modeflag&ModeInfoFlag ; + pVBInfo->SetFlag = 0x00 ; + pVBInfo->VBInfo = DisableCRT2Display ; + temp = XGINew_CheckMemorySize( HwDeviceExtension , ModeNo , ModeIdIndex, pVBInfo ) ; + + if ( temp == 0 ) + return( 0 ) ; + + XGI_DisplayOff( HwDeviceExtension, pVBInfo) ; + XGI_SetCRT1Group( HwDeviceExtension , ModeNo , ModeIdIndex, pVBInfo ) ; + XGI_DisplayOn( HwDeviceExtension, pVBInfo) ; +*/ + + XGI_UpdateModeInfo( HwDeviceExtension, pVBInfo ) ; + + if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */ +{ + XGI_LockCRT2( HwDeviceExtension, pVBInfo ) ; +} + + return( TRUE ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT1Group */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT1Group( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT StandTableIndex , + RefreshRateTableIndex , + b3CC , + temp ; + + USHORT XGINew_P3cc = pVBInfo->P3cc; + + /* XGINew_CRT1Mode = ModeNo ; // SaveModeID */ + StandTableIndex = XGI_GetModePtr( ModeNo , ModeIdIndex, pVBInfo ) ; + /* XGI_SetBIOSData(ModeNo , ModeIdIndex ) ; */ + /* XGI_ClearBankRegs( ModeNo , ModeIdIndex ) ; */ + XGI_SetSeqRegs( ModeNo , StandTableIndex , ModeIdIndex, pVBInfo ) ; + XGI_SetMiscRegs( StandTableIndex, pVBInfo ) ; + XGI_SetCRTCRegs( HwDeviceExtension , StandTableIndex, pVBInfo) ; + XGI_SetATTRegs( ModeNo , StandTableIndex , ModeIdIndex, pVBInfo ) ; + XGI_SetGRCRegs( StandTableIndex, pVBInfo ) ; + XGI_ClearExt1Regs(pVBInfo) ; + +/* if ( pVBInfo->IF_DEF_ExpLink ) */ + if ( HwDeviceExtension->jChipType == XG27 ) + { + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + XGI_SetDefaultVCLK( pVBInfo ) ; + } + } + + temp = ~ProgrammingCRT2 ; + pVBInfo->SetFlag &= temp ; + pVBInfo->SelectCRT2Rate = 0 ; + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( pVBInfo->VBInfo & ( SetSimuScanMode | SetCRT2ToLCDA | SetInSlaveMode ) ) + { + pVBInfo->SetFlag |= ProgrammingCRT2 ; + } + } + + RefreshRateTableIndex = XGI_GetRatePtrCRT2( HwDeviceExtension, ModeNo , ModeIdIndex, pVBInfo ) ; + if ( RefreshRateTableIndex != 0xFFFF ) + { + XGI_SetSync( RefreshRateTableIndex, pVBInfo ) ; + XGI_SetCRT1CRTC( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo, HwDeviceExtension ) ; + XGI_SetCRT1DE( HwDeviceExtension , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + XGI_SetCRT1Offset( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ; + XGI_SetCRT1VCLK( ModeNo , ModeIdIndex , HwDeviceExtension , RefreshRateTableIndex, pVBInfo ) ; + } + + if ( ( HwDeviceExtension->jChipType >= XG20 )&& + ( HwDeviceExtension->jChipType < XG27 ) ) /* fix H/W DCLK/2 bug */ + { + if ( ( ModeNo == 0x00 ) | (ModeNo == 0x01) ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , 0x4E) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , 0xE9) ; + b3CC =(UCHAR) XGINew_GetReg2(XGINew_P3cc) ; + XGINew_SetReg3(XGINew_P3cc , (b3CC |= 0x0C) ) ; + } + else if ( ( ModeNo == 0x04) | ( ModeNo == 0x05) | ( ModeNo == 0x0D) ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , 0x1B) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , 0xE3) ; + b3CC = (UCHAR)XGINew_GetReg2(XGINew_P3cc) ; + XGINew_SetReg3(XGINew_P3cc , (b3CC |= 0x0C) ) ; + } + } + + if ( HwDeviceExtension->jChipType >= XG21 ) + { + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ; + if ( temp & 0xA0 ) + { + + /*XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x20 ) ;*/ /* Enable write GPIOF */ + /*XGINew_SetRegAND( pVBInfo->P3d4 , 0x48 , ~0x20 ) ;*/ /* P. DWN */ + /* XG21 CRT1 Timing */ + if ( HwDeviceExtension->jChipType == XG27 ) + XGI_SetXG27CRTC( ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo ); + else + XGI_SetXG21CRTC( ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo ); + + XGI_UpdateXG21CRTC( ModeNo , pVBInfo , RefreshRateTableIndex) ; + + if ( HwDeviceExtension->jChipType == XG27 ) + XGI_SetXG27LCD( pVBInfo , RefreshRateTableIndex , ModeNo ); + else + XGI_SetXG21LCD( pVBInfo , RefreshRateTableIndex , ModeNo ); + + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + if ( HwDeviceExtension->jChipType == XG27 ) + XGI_SetXG27LVDSPara(ModeNo,ModeIdIndex, pVBInfo ); + else + XGI_SetXG21LVDSPara(ModeNo,ModeIdIndex, pVBInfo ); + } + /*XGINew_SetRegOR( pVBInfo->P3d4 , 0x48 , 0x20 ) ;*/ /* P. ON */ + } + } + + pVBInfo->SetFlag &= ( ~ProgrammingCRT2 ) ; + XGI_SetCRT1FIFO( ModeNo , HwDeviceExtension, pVBInfo ) ; + XGI_SetCRT1ModeRegs( HwDeviceExtension , ModeNo , ModeIdIndex , RefreshRateTableIndex , pVBInfo) ; + + + /* XGI_LoadCharacter(); //dif ifdef TVFont */ + + XGI_LoadDAC( ModeNo , ModeIdIndex, pVBInfo ) ; + /* XGI_ClearBuffer( HwDeviceExtension , ModeNo, pVBInfo ) ; */ +#ifdef WIN2000 + if ( pVBInfo->IF_DEF_CH7007 == 1 ) /* [Billy] 2007/05/14 */ + { + VideoDebugPrint((0, "XGI_SetCRT1Group: VBInfo->IF_DEF_CH7007==1\n")); + SetCH7007Regs(HwDeviceExtension, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo ) ; /* 07/05/28 */ + } +#endif +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetModePtr */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +UCHAR XGI_GetModePtr( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR index ; + + if ( ModeNo <= 0x13 ) + index = pVBInfo->SModeIDTable[ ModeIdIndex ].St_StTableIndex ; + else + { + if ( pVBInfo->ModeType <= 0x02 ) + index = 0x1B ; /* 02 -> ModeEGA */ + else + index = 0x0F ; + } + return( index ) ; /* Get pVBInfo->StandTable index */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetBIOSData */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +/*UCHAR XGI_SetBIOSData( USHORT ModeNo , USHORT ModeIdIndex ) +{ + return( 0 ) ; +} +*/ + +/* --------------------------------------------------------------------- */ +/* Function : XGI_ClearBankRegs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +/*UCHAR XGI_ClearBankRegs( USHORT ModeNo , USHORT ModeIdIndex ) +{ + return( 0 ) ; +} +*/ + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetSeqRegs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetSeqRegs( USHORT ModeNo , USHORT StandTableIndex , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR tempah , + SRdata ; + + USHORT i , + modeflag ; + + if ( ModeNo <= 0x13 ) + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + else + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x00 , 0x03 ) ; /* Set SR0 */ + tempah=pVBInfo->StandTable[ StandTableIndex ].SR[ 0 ] ; + + i = SetCRT2ToLCDA ; + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + { + tempah |= 0x01 ; + } + else + { + if ( pVBInfo->VBInfo & ( SetCRT2ToTV | SetCRT2ToLCD ) ) + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + tempah |= 0x01 ; + } + } + + tempah |= 0x20 ; /* screen off */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , tempah ) ; /* Set SR1 */ + + for( i = 02 ; i <= 04 ; i++ ) + { + SRdata = pVBInfo->StandTable[ StandTableIndex ].SR[ i - 1 ] ; /* Get SR2,3,4 from file */ + XGINew_SetReg1( pVBInfo->P3c4 , i , SRdata ) ; /* Set SR2 3 4 */ + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetMiscRegs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetMiscRegs( USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR Miscdata ; + + Miscdata = pVBInfo->StandTable[ StandTableIndex ].MISC ; /* Get Misc from file */ +/* + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + { + Miscdata |= 0x0C ; + } + } +*/ + + XGINew_SetReg3( pVBInfo->P3c2 , Miscdata ) ; /* Set Misc(3c2) */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRTCRegs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRTCRegs( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR CRTCdata ; + USHORT i ; + + CRTCdata = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ; + CRTCdata &= 0x7f ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , CRTCdata ) ; /* Unlock CRTC */ + + for( i = 0 ; i <= 0x18 ; i++ ) + { + CRTCdata = pVBInfo->StandTable[ StandTableIndex ].CRTC[ i ] ; /* Get CRTC from file */ + XGINew_SetReg1( pVBInfo->P3d4 , i , CRTCdata ) ; /* Set CRTC( 3d4 ) */ + } +/* + if ( ( HwDeviceExtension->jChipType == XGI_630 )&& ( HwDeviceExtension->jChipRevision == 0x30 ) ) + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToTV ) ) + { + XGINew_SetReg1( pVBInfo->P3d4 , 0x18 , 0xFE ) ; + } + } + } +*/ +} + + +/* --------------------------------------------------------------------- */ +/* Function : */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetATTRegs( USHORT ModeNo , USHORT StandTableIndex , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR ARdata ; + USHORT i , + modeflag ; + + if ( ModeNo <= 0x13 ) + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + else + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + + for( i = 0 ; i <= 0x13 ; i++ ) + { + ARdata = pVBInfo->StandTable[ StandTableIndex ].ATTR[ i ] ; + if ( modeflag & Charx8Dot ) /* ifndef Dot9 */ + { + if ( i == 0x13 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + ARdata = 0 ; + else + { + if ( pVBInfo->VBInfo & ( SetCRT2ToTV | SetCRT2ToLCD ) ) + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + ARdata = 0 ; + } + } + } + } + + XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */ + XGINew_SetReg3( pVBInfo->P3c0 , i ) ; /* set index */ + XGINew_SetReg3( pVBInfo->P3c0 , ARdata ) ; /* set data */ + } + + XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */ + XGINew_SetReg3( pVBInfo->P3c0 , 0x14 ) ; /* set index */ + XGINew_SetReg3( pVBInfo->P3c0 , 0x00 ) ; /* set data */ + XGINew_GetReg2( pVBInfo->P3da ) ; /* Enable Attribute */ + XGINew_SetReg3( pVBInfo->P3c0 , 0x20 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetGRCRegs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetGRCRegs( USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR GRdata ; + USHORT i ; + + for( i = 0 ; i <= 0x08 ; i++ ) + { + GRdata = pVBInfo->StandTable[ StandTableIndex ].GRC[ i ] ; /* Get GR from file */ + XGINew_SetReg1( pVBInfo->P3ce , i , GRdata ) ; /* Set GR(3ce) */ + } + + if ( pVBInfo->ModeType > ModeVGA ) + { + GRdata = ( UCHAR )XGINew_GetReg1( pVBInfo->P3ce , 0x05 ) ; + GRdata &= 0xBF ; /* 256 color disable */ + XGINew_SetReg1( pVBInfo->P3ce , 0x05 , GRdata ) ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_ClearExt1Regs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_ClearExt1Regs(PVB_DEVICE_INFO pVBInfo) +{ + USHORT i ; + + for( i = 0x0A ; i <= 0x0E ; i++ ) + XGINew_SetReg1( pVBInfo->P3c4 , i , 0x00 ) ; /* Clear SR0A-SR0E */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetDefaultVCLK */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +UCHAR XGI_SetDefaultVCLK( PVB_DEVICE_INFO pVBInfo ) +{ + + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x31 , ~0x30 , 0x20 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->VCLKData[ 0 ].SR2B ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->VCLKData[ 0 ].SR2C ) ; + + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x31 , ~0x30 , 0x10 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->VCLKData[ 1 ].SR2B ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->VCLKData[ 1 ].SR2C ) ; + + XGINew_SetRegAND( pVBInfo->P3c4 , 0x31 , ~0x30 ) ; + return( 0 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetRatePtrCRT2 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + SHORT LCDRefreshIndex[] = { 0x00 , 0x00 , 0x03 , 0x01 } , + LCDARefreshIndex[] = { 0x00 , 0x00 , 0x03 , 0x01 , 0x01 , 0x01 , 0x01 } ; + + USHORT RefreshRateTableIndex , i , + modeflag , index , temp ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + } + + if ( pVBInfo->IF_DEF_CH7005 == 1 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + if ( modeflag & HalfDCLK ) + return( 0 ) ; + } + } + + if ( ModeNo < 0x14 ) + return( 0xFFFF ) ; + + index = XGINew_GetReg1( pVBInfo->P3d4 , 0x33 ) ; + index = index >> pVBInfo->SelectCRT2Rate ; + index &= 0x0F ; + + if ( pVBInfo->LCDInfo & LCDNonExpanding ) + index = 0 ; + + if ( index > 0 ) + index-- ; + + if ( pVBInfo->SetFlag & ProgrammingCRT2 ) + { + if ( pVBInfo->IF_DEF_CH7005 == 1 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + index = 0 ; + } + } + + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + if( pVBInfo->IF_DEF_LVDS == 0 ) + { + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + temp = LCDARefreshIndex[ pVBInfo->LCDResInfo & 0x0F ] ; /* 301b */ + else + temp = LCDRefreshIndex[ pVBInfo->LCDResInfo & 0x0F ] ; + + if ( index > temp ) + { + index = temp ; + } + } + else + { + index = 0 ; + } + } + } + + RefreshRateTableIndex = pVBInfo->EModeIDTable[ ModeIdIndex ].REFindex ; + ModeNo = pVBInfo->RefIndex[ RefreshRateTableIndex ].ModeID ; + if ( pXGIHWDE->jChipType >= XG20 ) /* for XG20, XG21, XG27 */ + { + /* + if ( pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag & XG2xNotSupport ) + { + index++; + } + */ + if ( ( pVBInfo->RefIndex[ RefreshRateTableIndex ].XRes == 800 ) && + ( pVBInfo->RefIndex[ RefreshRateTableIndex ].YRes == 600 ) ) + { + index++; + } +/* Alan 10/19/2007; do the similiar adjustment like XGISearchCRT1Rate() */ + if ( ( pVBInfo->RefIndex[ RefreshRateTableIndex ].XRes == 1024 ) && + ( pVBInfo->RefIndex[ RefreshRateTableIndex ].YRes == 768 ) ) + { + index++; + } + if ( ( pVBInfo->RefIndex[ RefreshRateTableIndex ].XRes == 1280 ) && + ( pVBInfo->RefIndex[ RefreshRateTableIndex ].YRes == 1024 ) ) + { + index++; + } + } + + i = 0 ; + do + { + if ( pVBInfo->RefIndex[ RefreshRateTableIndex + i ].ModeID != ModeNo ) + break ; + temp = pVBInfo->RefIndex[ RefreshRateTableIndex + i ].Ext_InfoFlag ; + temp &= ModeInfoFlag ; + if ( temp < pVBInfo->ModeType ) + break ; + i++ ; + index-- ; + + } while( index != 0xFFFF ) ; + if ( !( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) ) + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + temp = pVBInfo->RefIndex[ RefreshRateTableIndex + i - 1 ].Ext_InfoFlag ; + if ( temp & InterlaceMode ) + { + i++ ; + } + } + } + i-- ; + if ( ( pVBInfo->SetFlag & ProgrammingCRT2 ) ) + { + temp = XGI_AjustCRT2Rate( ModeNo , ModeIdIndex , RefreshRateTableIndex , &i, pVBInfo) ; + } + return( RefreshRateTableIndex + i ) ; /*return(0x01|(temp1<<1)); */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_AjustCRT2Rate */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_AjustCRT2Rate( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , USHORT *i, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempax , + tempbx , + resinfo , + modeflag , + infoflag ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ModeFlag */ + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + } + + resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; + tempbx = pVBInfo->RefIndex[ RefreshRateTableIndex + ( *i ) ].ModeID ; + tempax = 0 ; + + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) + { + tempax |= SupportRAMDAC2 ; + + if ( pVBInfo->VBType & VB_XGI301C ) + tempax |= SupportCRT2in301C ; + } + + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) /* 301b */ + { + tempax |= SupportLCD ; + + if ( pVBInfo->LCDResInfo != Panel1280x1024 ) + { + if ( pVBInfo->LCDResInfo != Panel1280x960 ) + { + if ( pVBInfo->LCDInfo & LCDNonExpanding ) + { + if ( resinfo >= 9 ) + { + tempax = 0 ; + return( 0 ) ; + } + } + } + } + } + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) /* for HiTV */ + { + if ( ( pVBInfo->VBType & VB_XGI301LV ) && ( pVBInfo->VBExtInfo == VB_YPbPr1080i ) ) + { + tempax |= SupportYPbPr ; + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( resinfo == 4 ) + return( 0 ) ; + + if ( resinfo == 3 ) + return( 0 ) ; + + if ( resinfo > 7 ) + return( 0 ) ; + } + } + else + { + tempax |= SupportHiVisionTV ; + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( resinfo == 4 ) + return( 0 ) ; + + if ( resinfo == 3 ) + { + if ( pVBInfo->SetFlag & TVSimuMode ) + return( 0 ) ; + } + + if ( resinfo > 7 ) + return( 0 ) ; + } + } + } + else + { + if ( pVBInfo->VBInfo & ( SetCRT2ToAVIDEO | SetCRT2ToSVIDEO | SetCRT2ToSCART | SetCRT2ToYPbPr | SetCRT2ToHiVisionTV ) ) + { + tempax |= SupportTV ; + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + tempax |= SupportTV1024 ; + } + + if ( !( pVBInfo->VBInfo & SetPALTV ) ) + { + if ( modeflag & NoSupportSimuTV ) + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( !( pVBInfo->VBInfo & SetNotSimuMode ) ) + { + return( 0 ) ; + } + } + } + } + } + } + } + else /* for LVDS */ + { + if ( pVBInfo->IF_DEF_CH7005 == 1 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + tempax |= SupportCHTV ; + } + } + + if ( pVBInfo->VBInfo & SetCRT2ToLCD ) + { + tempax |= SupportLCD ; + + if ( resinfo > 0x08 ) + return( 0 ) ; /* 1024x768 */ + + if ( pVBInfo->LCDResInfo < Panel1024x768 ) + { + if ( resinfo > 0x07 ) + return( 0 ) ; /* 800x600 */ + + if ( resinfo == 0x04 ) + return( 0 ) ; /* 512x384 */ + } + } + } + + for( ; pVBInfo->RefIndex[ RefreshRateTableIndex + ( *i ) ].ModeID == tempbx ; ( *i )-- ) + { + infoflag = pVBInfo->RefIndex[ RefreshRateTableIndex + ( *i ) ].Ext_InfoFlag ; + if ( infoflag & tempax ) + { + return( 1 ) ; + } + if ( ( *i ) == 0 ) + break ; + } + + for( ( *i ) = 0 ; ; ( *i )++ ) + { + infoflag = pVBInfo->RefIndex[ RefreshRateTableIndex + ( *i ) ].Ext_InfoFlag ; + if ( pVBInfo->RefIndex[ RefreshRateTableIndex + ( *i ) ].ModeID != tempbx ) + { + return( 0 ) ; + } + + if ( infoflag & tempax ) + { + return( 1 ) ; + } + } + return( 1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetSync */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetSync(USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT sync , + temp ; + + sync = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag >> 8 ; /* di+0x00 */ + sync &= 0xC0 ; + temp = 0x2F ; + temp |= sync ; + XGINew_SetReg3( pVBInfo->P3c2 , temp ) ; /* Set Misc(3c2) */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT1CRTC */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT1CRTC( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo, PXGI_HW_DEVICE_INFO HwDeviceExtension ) +{ + UCHAR index , + data ; + + USHORT i ; + + index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ; /* Get index */ + index = index&IndexMask ; + + data =( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ; + data &= 0x7F ; + XGINew_SetReg1(pVBInfo->P3d4,0x11,data); /* Unlock CRTC */ + + for( i = 0 ; i < 8 ; i++ ) + pVBInfo->TimingH[ 0 ].data[ i ] = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ i ] ; + + for( i = 0 ; i < 7 ; i++ ) + pVBInfo->TimingV[ 0 ].data[ i ] = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ i + 8 ] ; + + XGI_SetCRT1Timing_H( pVBInfo, HwDeviceExtension ) ; + + + + XGI_SetCRT1Timing_V( ModeIdIndex , ModeNo, pVBInfo ) ; + + + if( pVBInfo->ModeType > 0x03 ) + XGINew_SetReg1( pVBInfo->P3d4 , 0x14 , 0x4F ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT1Timing_H */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT1Timing_H( PVB_DEVICE_INFO pVBInfo, PXGI_HW_DEVICE_INFO HwDeviceExtension ) +{ + UCHAR data , data1, pushax; + USHORT i , j ; + + /* XGINew_SetReg1( pVBInfo->P3d4 , 0x51 , 0 ) ; */ + /* XGINew_SetReg1( pVBInfo->P3d4 , 0x56 , 0 ) ; */ + /* XGINew_SetRegANDOR( pVBInfo->P3d4 ,0x11 , 0x7f , 0x00 ) ; */ + + data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ; /* unlock cr0-7 */ + data &= 0x7F ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , data ) ; + + data = pVBInfo->TimingH[ 0 ].data[ 0 ] ; + XGINew_SetReg1( pVBInfo->P3d4 , 0 , data ) ; + + for( i = 0x01 ; i <= 0x04 ; i++ ) + { + data = pVBInfo->TimingH[ 0 ].data[ i ] ; + XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 1 ) , data ) ; + } + + for( i = 0x05 ; i <= 0x06 ; i++ ) + { + data = pVBInfo->TimingH[ 0 ].data[ i ]; + XGINew_SetReg1( pVBInfo->P3c4 ,( USHORT )( i + 6 ) , data ) ; + } + + j = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0e ) ; + j &= 0x1F ; + data = pVBInfo->TimingH[ 0 ].data[ 7 ] ; + data &= 0xE0 ; + data |= j ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x0e , data ) ; + + if ( HwDeviceExtension->jChipType >= XG20 ) + { + data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x04 ) ; + data = data - 1 ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x04 , data ) ; + data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x05 ) ; + data1 = data ; + data1 &= 0xE0 ; + data &= 0x1F ; + if ( data == 0 ) + { + pushax = data ; + data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0c ) ; + data &= 0xFB ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x0c , data ) ; + data = pushax ; + } + data = data - 1 ; + data |= data1 ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x05 , data ) ; + data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0e ) ; + data = data >> 5 ; + data = data + 3 ; + if ( data > 7 ) + data = data - 7 ; + data = data << 5 ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0e , ~0xE0 , data ) ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT1Timing_V */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT1Timing_V( USHORT ModeIdIndex , USHORT ModeNo,PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR data ; + USHORT i , j ; + + /* XGINew_SetReg1( pVBInfo->P3d4 , 0x51 , 0 ) ; */ + /* XGINew_SetReg1( pVBInfo->P3d4 , 0x56 , 0 ) ; */ + /* XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x11 , 0x7f , 0x00 ) ; */ + + for( i = 0x00 ; i <= 0x01 ; i++ ) + { + data = pVBInfo->TimingV[ 0 ].data[ i ] ; + XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 6 ) , data ) ; + } + + for( i = 0x02 ; i <= 0x03 ; i++ ) + { + data = pVBInfo->TimingV[ 0 ].data[ i ] ; + XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 0x0e ) , data ) ; + } + + for( i = 0x04 ; i <= 0x05 ; i++ ) + { + data = pVBInfo->TimingV[ 0 ].data[ i ] ; + XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 0x11 ) , data ) ; + } + + j = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0a ) ; + j &= 0xC0 ; + data = pVBInfo->TimingV[ 0 ].data[ 6 ] ; + data &= 0x3F ; + data |= j ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x0a , data ) ; + + data = pVBInfo->TimingV[ 0 ].data[ 6 ] ; + data &= 0x80 ; + data = data >> 2 ; + + if ( ModeNo <= 0x13 ) + i = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + else + i = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + + i &= DoubleScanMode ; + if ( i ) + data |= 0x80 ; + + j = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x09 ) ; + j &= 0x5F ; + data |= j ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x09 , data ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetXG21CRTC */ +/* Input : Stand or enhance CRTC table */ +/* Output : Fill CRT Hsync/Vsync to SR2E/SR2F/SR30/SR33/SR34/SR3F */ +/* Description : Set LCD timing */ +/* --------------------------------------------------------------------- */ +void XGI_SetXG21CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo) +{ + UCHAR StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx ; + USHORT Temp1, Temp2, Temp3 ; + + if ( ModeNo <= 0x13 ) + { + StandTableIndex = XGI_GetModePtr( ModeNo , ModeIdIndex, pVBInfo ) ; + Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 4 ] ; /* CR04 HRS */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , Tempax ) ; /* SR2E [7:0]->HRS */ + Tempbx = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 5 ] ; /* Tempbx: CR05 HRE */ + Tempbx &= 0x1F ; /* Tempbx: HRE[4:0] */ + Tempcx = Tempax ; + Tempcx &= 0xE0 ; /* Tempcx: HRS[7:5] */ + Tempdx = Tempcx | Tempbx ; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */ + if ( Tempbx < ( Tempax & 0x1F ) ) /* IF HRE < HRS */ + Tempdx |= 0x20 ; /* Tempdx: HRE = HRE + 0x20 */ + Tempdx <<= 2 ; /* Tempdx << 2 */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , Tempdx ) ; /* SR2F [7:2]->HRE */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , 0xE3 , 00 ) ; + + Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 16 ] ; /* Tempax: CR16 VRS */ + Tempbx = Tempax ; /* Tempbx=Tempax */ + Tempax &= 0x01 ; /* Tempax: VRS[0] */ + XGINew_SetRegOR( pVBInfo->P3c4 , 0x33 , Tempax ) ; /* SR33[0]->VRS */ + Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 7 ] ; /* Tempax: CR7 VRS */ + Tempdx = Tempbx >> 1 ; /* Tempdx: VRS[7:1] */ + Tempcx = Tempax & 0x04 ; /* Tempcx: CR7[2] */ + Tempcx <<= 5 ; /* Tempcx[7]: VRS[8] */ + Tempdx |= Tempcx ; /* Tempdx: VRS[8:1] */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , Tempdx ) ; /* SR34[7:0]: VRS[8:1] */ + + Temp1 = Tempcx << 1 ; /* Temp1[8]: VRS[8] UCHAR -> USHORT */ + Temp1 |= Tempbx ; /* Temp1[8:0]: VRS[8:0] */ + Tempax &= 0x80 ; /* Tempax[7]: CR7[7] */ + Temp2 = Tempax << 2 ; /* Temp2[9]: VRS[9] */ + Temp1 |= Temp2 ; /* Temp1[9:0]: VRS[9:0] */ + + Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 17 ] ; /* CR16 VRE */ + Tempax &= 0x0F ; /* Tempax[3:0]: VRE[3:0] */ + Temp2 = Temp1 & 0x3F0 ; /* Temp2[9:4]: VRS[9:4] */ + Temp2 |= Tempax ; /* Temp2[9:0]: VRE[9:0] */ + Temp3 = Temp1 & 0x0F ; /* Temp3[3:0]: VRS[3:0] */ + if ( Tempax < Temp3 ) /* VRE[3:0]<VRS[3:0] */ + Temp2 |= 0x10 ; /* Temp2: VRE + 0x10 */ + Temp2 &= 0xFF ; /* Temp2[7:0]: VRE[7:0] */ + Tempax = (UCHAR)Temp2 ; /* Tempax[7:0]: VRE[7:0] */ + Tempax <<= 2 ; /* Tempax << 2: VRE[5:0] */ + Temp1 &= 0x600 ; /* Temp1[10:9]: VRS[10:9] */ + Temp1 >>= 9 ; /* [10:9]->[1:0] */ + Tempbx = (UCHAR)Temp1 ; /* Tempbx[1:0]: VRS[10:9] */ + Tempax |= Tempbx ; /* VRE[5:0]VRS[10:9] */ + Tempax &= 0x7F ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x3F , Tempax ) ; /* SR3F D[7:2]->VRE D[1:0]->VRS */ + } + else + { + index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ; + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 3 ] ; /* Tempax: CR4 HRS */ + Tempcx = Tempax ; /* Tempcx: HRS */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , Tempax ) ; /* SR2E[7:0]->HRS */ + + Tempdx = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 5 ] ; /* SRB */ + Tempdx &= 0xC0 ; /* Tempdx[7:6]: SRB[7:6] */ + Temp1 = Tempdx ; /* Temp1[7:6]: HRS[9:8] */ + Temp1 <<= 2 ; /* Temp1[9:8]: HRS[9:8] */ + Temp1 |= Tempax ; /* Temp1[9:0]: HRS[9:0] */ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 4 ] ; /* CR5 HRE */ + Tempax &= 0x1F ; /* Tempax[4:0]: HRE[4:0] */ + + Tempbx = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 6 ] ; /* SRC */ + Tempbx &= 0x04 ; /* Tempbx[2]: HRE[5] */ + Tempbx <<= 3 ; /* Tempbx[5]: HRE[5] */ + Tempax |= Tempbx ; /* Tempax[5:0]: HRE[5:0] */ + + Temp2 = Temp1 & 0x3C0 ; /* Temp2[9:6]: HRS[9:6] */ + Temp2 |= Tempax ; /* Temp2[9:0]: HRE[9:0] */ + + Tempcx &= 0x3F ; /* Tempcx[5:0]: HRS[5:0] */ + if( Tempax < Tempcx ) /* HRE < HRS */ + Temp2 |= 0x40 ; /* Temp2 + 0x40 */ + + Temp2 &= 0xFF ; + Tempax = (UCHAR)Temp2 ; /* Tempax: HRE[7:0] */ + Tempax <<= 2 ; /* Tempax[7:2]: HRE[5:0] */ + Tempdx >>= 6 ; /* Tempdx[7:6]->[1:0] HRS[9:8] */ + Tempax |= Tempdx ; /* HRE[5:0]HRS[9:8] */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , Tempax ) ; /* SR2F D[7:2]->HRE, D[1:0]->HRS */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , 0xE3 , 00 ) ; + + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 10 ] ; /* CR10 VRS */ + Tempbx = Tempax ; /* Tempbx: VRS */ + Tempax &= 0x01 ; /* Tempax[0]: VRS[0] */ + XGINew_SetRegOR( pVBInfo->P3c4 , 0x33 , Tempax ) ; /* SR33[0]->VRS[0] */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 9 ] ; /* CR7[2][7] VRE */ + Tempcx = Tempbx >> 1 ; /* Tempcx[6:0]: VRS[7:1] */ + Tempdx = Tempax & 0x04 ; /* Tempdx[2]: CR7[2] */ + Tempdx <<= 5 ; /* Tempdx[7]: VRS[8] */ + Tempcx |= Tempdx ; /* Tempcx[7:0]: VRS[8:1] */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , Tempcx ) ; /* SR34[8:1]->VRS */ + + Temp1 = Tempdx ; /* Temp1[7]: Tempdx[7] */ + Temp1 <<= 1 ; /* Temp1[8]: VRS[8] */ + Temp1 |= Tempbx ; /* Temp1[8:0]: VRS[8:0] */ + Tempax &= 0x80 ; + Temp2 = Tempax << 2 ; /* Temp2[9]: VRS[9] */ + Temp1 |= Temp2 ; /* Temp1[9:0]: VRS[9:0] */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 14 ] ; /* Tempax: SRA */ + Tempax &= 0x08 ; /* Tempax[3]: VRS[3] */ + Temp2 = Tempax ; + Temp2 <<= 7 ; /* Temp2[10]: VRS[10] */ + Temp1 |= Temp2 ; /* Temp1[10:0]: VRS[10:0] */ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 11 ] ; /* Tempax: CR11 VRE */ + Tempax &= 0x0F ; /* Tempax[3:0]: VRE[3:0] */ + Tempbx = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 14 ] ; /* Tempbx: SRA */ + Tempbx &= 0x20 ; /* Tempbx[5]: VRE[5] */ + Tempbx >>= 1 ; /* Tempbx[4]: VRE[4] */ + Tempax |= Tempbx ; /* Tempax[4:0]: VRE[4:0] */ + Temp2 = Temp1 & 0x7E0 ; /* Temp2[10:5]: VRS[10:5] */ + Temp2 |= Tempax ; /* Temp2[10:5]: VRE[10:5] */ + + Temp3 = Temp1 & 0x1F ; /* Temp3[4:0]: VRS[4:0] */ + if ( Tempax < Temp3 ) /* VRE < VRS */ + Temp2 |= 0x20 ; /* VRE + 0x20 */ + + Temp2 &= 0xFF ; + Tempax = (UCHAR)Temp2 ; /* Tempax: VRE[7:0] */ + Tempax <<= 2 ; /* Tempax[7:0]; VRE[5:0]00 */ + Temp1 &= 0x600 ; /* Temp1[10:9]: VRS[10:9] */ + Temp1 >>= 9 ; /* Temp1[1:0]: VRS[10:9] */ + Tempbx = (UCHAR)Temp1 ; + Tempax |= Tempbx ; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */ + Tempax &= 0x7F ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x3F , Tempax ) ; /* SR3F D[7:2]->VRE D[1:0]->VRS */ + } +} + +void XGI_SetXG27CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo) +{ + USHORT StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx ; + + if ( ModeNo <= 0x13 ) + { + StandTableIndex = XGI_GetModePtr( ModeNo , ModeIdIndex, pVBInfo ) ; + Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 4 ] ; /* CR04 HRS */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , Tempax ) ; /* SR2E [7:0]->HRS */ + Tempbx = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 5 ] ; /* Tempbx: CR05 HRE */ + Tempbx &= 0x1F ; /* Tempbx: HRE[4:0] */ + Tempcx = Tempax ; + Tempcx &= 0xE0 ; /* Tempcx: HRS[7:5] */ + Tempdx = Tempcx | Tempbx ; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */ + if ( Tempbx < ( Tempax & 0x1F ) ) /* IF HRE < HRS */ + Tempdx |= 0x20 ; /* Tempdx: HRE = HRE + 0x20 */ + Tempdx <<= 2 ; /* Tempdx << 2 */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , Tempdx ) ; /* SR2F [7:2]->HRE */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , 0xE3 , 00 ) ; + + Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 16 ] ; /* Tempax: CR10 VRS */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , Tempax ) ; /* SR34[7:0]->VRS */ + Tempcx = Tempax ; /* Tempcx=Tempax=VRS[7:0] */ + Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 7 ] ; /* Tempax[7][2]: CR7[7][2] VRS[9][8] */ + Tempbx = Tempax ; /* Tempbx=CR07 */ + Tempax &= 0x04 ; /* Tempax[2]: CR07[2] VRS[8] */ + Tempax >>= 2; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x01, Tempax ) ; /* SR35 D[0]->VRS D[8] */ + Tempcx |= (Tempax << 8) ; /* Tempcx[8] |= VRS[8] */ + Tempcx |= (Tempbx & 0x80)<<2; /* Tempcx[9] |= VRS[9] */ + + + Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 17 ] ; /* CR11 VRE */ + Tempax &= 0x0F ; /* Tempax: VRE[3:0] */ + Tempbx = Tempcx ; /* Tempbx=Tempcx=VRS[9:0] */ + Tempbx &= 0x3F0 ; /* Tempbx[9:4]: VRS[9:4] */ + Tempbx |= Tempax ; /* Tempbx[9:0]: VRE[9:0] */ + if ( Tempax <= (Tempcx & 0x0F) ) /* VRE[3:0]<=VRS[3:0] */ + Tempbx |= 0x10 ; /* Tempbx: VRE + 0x10 */ + Tempax = (UCHAR)Tempbx & 0xFF; /* Tempax[7:0]: VRE[7:0] */ + Tempax <<= 2 ; /* Tempax << 2: VRE[5:0] */ + Tempcx = (Tempcx&0x600)>>8; /* Tempcx VRS[10:9] */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0xFC, Tempax ) ; /* SR3F D[7:2]->VRE D[5:0] */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x06, Tempcx ) ; /* SR35 D[2:1]->VRS[10:9] */ + } + else + { + index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ; + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 3 ] ; /* Tempax: CR4 HRS */ + Tempbx = Tempax ; /* Tempbx: HRS[7:0] */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , Tempax ) ; /* SR2E[7:0]->HRS */ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 5 ] ; /* SR0B */ + Tempax &= 0xC0 ; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/ + Tempbx |= (Tempax << 2); /* Tempbx: HRS[9:0] */ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 4 ] ; /* CR5 HRE */ + Tempax &= 0x1F ; /* Tempax[4:0]: HRE[4:0] */ + Tempcx = Tempax ; /* Tempcx: HRE[4:0] */ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 6 ] ; /* SRC */ + Tempax &= 0x04 ; /* Tempax[2]: HRE[5] */ + Tempax <<= 3 ; /* Tempax[5]: HRE[5] */ + Tempcx |= Tempax ; /* Tempcx[5:0]: HRE[5:0] */ + + Tempbx = Tempbx & 0x3C0 ; /* Tempbx[9:6]: HRS[9:6] */ + Tempbx |= Tempcx ; /* Tempbx: HRS[9:6]HRE[5:0] */ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 3 ] ; /* Tempax: CR4 HRS */ + Tempax &= 0x3F ; /* Tempax: HRS[5:0] */ + if( Tempcx <= Tempax ) /* HRE[5:0] < HRS[5:0] */ + Tempbx += 0x40 ; /* Tempbx= Tempbx + 0x40 : HRE[9:0]*/ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 5 ] ; /* SR0B */ + Tempax &= 0xC0 ; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/ + Tempax >>= 6; /* Tempax[1:0]: HRS[9:8]*/ + Tempax |= ((Tempbx << 2) & 0xFF); /* Tempax[7:2]: HRE[5:0] */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , Tempax ) ; /* SR2F [7:2][1:0]: HRE[5:0]HRS[9:8] */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , 0xE3 , 00 ) ; + + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 10 ] ; /* CR10 VRS */ + XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , Tempax ) ; /* SR34[7:0]->VRS[7:0] */ + + Tempcx = Tempax ; /* Tempcx <= VRS[7:0] */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 9 ] ; /* CR7[7][2] VRS[9][8] */ + Tempbx = Tempax ; /* Tempbx <= CR07[7:0] */ + Tempax = Tempax & 0x04 ; /* Tempax[2]: CR7[2]: VRS[8] */ + Tempax >>= 2 ; /* Tempax[0]: VRS[8] */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x01 , Tempax ) ; /* SR35[0]: VRS[8] */ + Tempcx |= (Tempax<<8) ; /* Tempcx <= VRS[8:0] */ + Tempcx |= ((Tempbx&0x80)<<2) ; /* Tempcx <= VRS[9:0] */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 14 ] ; /* Tempax: SR0A */ + Tempax &= 0x08; /* SR0A[3] VRS[10] */ + Tempcx |= (Tempax<<7) ; /* Tempcx <= VRS[10:0] */ + + + Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 11 ] ; /* Tempax: CR11 VRE */ + Tempax &= 0x0F ; /* Tempax[3:0]: VRE[3:0] */ + Tempbx = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 14 ] ; /* Tempbx: SR0A */ + Tempbx &= 0x20 ; /* Tempbx[5]: SR0A[5]: VRE[4] */ + Tempbx >>= 1 ; /* Tempbx[4]: VRE[4] */ + Tempax |= Tempbx ; /* Tempax[4:0]: VRE[4:0] */ + Tempbx = Tempcx ; /* Tempbx: VRS[10:0] */ + Tempbx &= 0x7E0 ; /* Tempbx[10:5]: VRS[10:5] */ + Tempbx |= Tempax ; /* Tempbx: VRS[10:5]VRE[4:0] */ + + if ( Tempbx <= Tempcx ) /* VRE <= VRS */ + Tempbx |= 0x20 ; /* VRE + 0x20 */ + + Tempax = (Tempbx<<2) & 0xFF ; /* Tempax: Tempax[7:0]; VRE[5:0]00 */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0xFC , Tempax ) ; /* SR3F[7:2]:VRE[5:0] */ + Tempax = Tempcx >> 8; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x07 , Tempax ) ; /* SR35[2:0]:VRS[10:8] */ + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetXG21LCD */ +/* Input : */ +/* Output : FCLK duty cycle, FCLK delay compensation */ +/* Description : All values set zero */ +/* --------------------------------------------------------------------- */ +void XGI_SetXG21LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo) +{ + USHORT Data , Temp , b3CC ; + USHORT XGI_P3cc ; + + XGI_P3cc = pVBInfo->P3cc ; + + XGINew_SetReg1( pVBInfo->P3d4 , 0x2E , 0x00 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x2F , 0x00 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x46 , 0x00 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x47 , 0x00 ) ; + if ( ((*pVBInfo->pDVOSetting)&0xC0) == 0xC0 ) + { + XGINew_SetReg1( pVBInfo->P3d4 , 0x2E , *pVBInfo->pCR2E ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x2F , *pVBInfo->pCR2F ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x46 , *pVBInfo->pCR46 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x47 , *pVBInfo->pCR47 ) ; + } + + Temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ; + + if ( Temp & 0x01 ) + { + XGINew_SetRegOR( pVBInfo->P3c4 , 0x06 , 0x40 ) ; /* 18 bits FP */ + XGINew_SetRegOR( pVBInfo->P3c4 , 0x09 , 0x40 ) ; + } + + XGINew_SetRegOR( pVBInfo->P3c4 , 0x1E , 0x01 ) ; /* Negative blank polarity */ + + XGINew_SetRegAND( pVBInfo->P3c4 , 0x30 , ~0x20 ) ; + XGINew_SetRegAND( pVBInfo->P3c4 , 0x35 , ~0x80 ) ; + + if ( ModeNo <= 0x13 ) + { + b3CC = (UCHAR) XGINew_GetReg2( XGI_P3cc ) ; + if ( b3CC & 0x40 ) + XGINew_SetRegOR( pVBInfo->P3c4 , 0x30 , 0x20 ) ; /* Hsync polarity */ + if ( b3CC & 0x80 ) + XGINew_SetRegOR( pVBInfo->P3c4 , 0x35 , 0x80 ) ; /* Vsync polarity */ + } + else + { + Data = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ; + if ( Data & 0x4000 ) + XGINew_SetRegOR( pVBInfo->P3c4 , 0x30 , 0x20 ) ; /* Hsync polarity */ + if ( Data & 0x8000 ) + XGINew_SetRegOR( pVBInfo->P3c4 , 0x35 , 0x80 ) ; /* Vsync polarity */ + } +} + +void XGI_SetXG27LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo) +{ + USHORT Data , Temp , b3CC ; + USHORT XGI_P3cc ; + + XGI_P3cc = pVBInfo->P3cc ; + + XGINew_SetReg1( pVBInfo->P3d4 , 0x2E , 0x00 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x2F , 0x00 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x46 , 0x00 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x47 , 0x00 ) ; + + Temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ; + if ( ( Temp & 0x03 ) == 0 ) /* dual 12 */ + { + XGINew_SetReg1( pVBInfo->P3d4 , 0x46 , 0x13 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x47 , 0x13 ) ; + } + + if ( ((*pVBInfo->pDVOSetting)&0xC0) == 0xC0 ) + { + XGINew_SetReg1( pVBInfo->P3d4 , 0x2E , *pVBInfo->pCR2E ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x2F , *pVBInfo->pCR2F ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x46 , *pVBInfo->pCR46 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x47 , *pVBInfo->pCR47 ) ; + } + + XGI_SetXG27FPBits(pVBInfo); + + XGINew_SetRegOR( pVBInfo->P3c4 , 0x1E , 0x01 ) ; /* Negative blank polarity */ + + XGINew_SetRegAND( pVBInfo->P3c4 , 0x30 , ~0x20 ) ; /* Hsync polarity */ + XGINew_SetRegAND( pVBInfo->P3c4 , 0x35 , ~0x80 ) ; /* Vsync polarity */ + + if ( ModeNo <= 0x13 ) + { + b3CC = (UCHAR) XGINew_GetReg2( XGI_P3cc ) ; + if ( b3CC & 0x40 ) + XGINew_SetRegOR( pVBInfo->P3c4 , 0x30 , 0x20 ) ; /* Hsync polarity */ + if ( b3CC & 0x80 ) + XGINew_SetRegOR( pVBInfo->P3c4 , 0x35 , 0x80 ) ; /* Vsync polarity */ + } + else + { + Data = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ; + if ( Data & 0x4000 ) + XGINew_SetRegOR( pVBInfo->P3c4 , 0x30 , 0x20 ) ; /* Hsync polarity */ + if ( Data & 0x8000 ) + XGINew_SetRegOR( pVBInfo->P3c4 , 0x35 , 0x80 ) ; /* Vsync polarity */ + } +} + +/* --------------------------------------------------------------------- */ +/* Function : XGI_UpdateXG21CRTC */ +/* Input : */ +/* Output : CRT1 CRTC */ +/* Description : Modify CRT1 Hsync/Vsync to fix LCD mode timing */ +/* --------------------------------------------------------------------- */ +void XGI_UpdateXG21CRTC( USHORT ModeNo , PVB_DEVICE_INFO pVBInfo , USHORT RefreshRateTableIndex ) +{ + int i , index = -1; + + XGINew_SetRegAND( pVBInfo->P3d4 , 0x11 , 0x7F ) ; /* Unlock CR0~7 */ + if ( ModeNo <= 0x13 ) + { + for( i = 0 ; i < 12 ; i++ ) + { + if ( ModeNo == pVBInfo->UpdateCRT1[ i ].ModeID ) + index = i ; + } + } + else + { + if ( ModeNo == 0x2E && ( pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC == RES640x480x60 ) ) + index = 12 ; + else if ( ModeNo == 0x2E && ( pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC == RES640x480x72 ) ) + index = 13 ; + else if ( ModeNo == 0x2F ) + index = 14 ; + else if ( ModeNo == 0x50 ) + index = 15 ; + else if ( ModeNo == 0x59 ) + index = 16 ; + } + + if( index != -1 ) + { + XGINew_SetReg1( pVBInfo->P3d4 , 0x02 , pVBInfo->UpdateCRT1[ index ].CR02 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x03 , pVBInfo->UpdateCRT1[ index ].CR03 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x15 , pVBInfo->UpdateCRT1[ index ].CR15 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x16 , pVBInfo->UpdateCRT1[ index ].CR16 ) ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT1DE */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT1DE( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo,USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT resindex , + tempax , + tempbx , + tempcx , + temp , + modeflag ; + + UCHAR data ; + + resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + tempax = pVBInfo->StResInfo[ resindex ].HTotal ; + tempbx = pVBInfo->StResInfo[ resindex ].VTotal ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + tempax = pVBInfo->ModeResInfo[ resindex ].HTotal ; + tempbx = pVBInfo->ModeResInfo[ resindex ].VTotal ; + } + + if ( modeflag & HalfDCLK ) + tempax = tempax >> 1 ; + + if ( ModeNo > 0x13 ) + { + if ( modeflag & HalfDCLK ) + tempax = tempax << 1 ; + + temp = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ; + + if ( temp & InterlaceMode ) + tempbx = tempbx >> 1 ; + + if ( modeflag & DoubleScanMode ) + tempbx = tempbx << 1 ; + } + + tempcx = 8 ; + + /* if ( !( modeflag & Charx8Dot ) ) */ + /* tempcx = 9 ; */ + + tempax /= tempcx ; + tempax -= 1 ; + tempbx -= 1 ; + tempcx = tempax ; + temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ; + data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ; + data &= 0x7F ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , data ) ; /* Unlock CRTC */ + XGINew_SetReg1( pVBInfo->P3d4 , 0x01 , ( USHORT )( tempcx & 0xff ) ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x0b , ~0x0c , ( USHORT )( ( tempcx & 0x0ff00 ) >> 10 ) ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x12 , ( USHORT )( tempbx & 0xff ) ) ; + tempax = 0 ; + tempbx = tempbx >> 8 ; + + if ( tempbx & 0x01 ) + tempax |= 0x02 ; + + if ( tempbx & 0x02 ) + tempax |= 0x40 ; + + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x42 , tempax ) ; + data =( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x07 ) ; + data &= 0xFF ; + tempax = 0 ; + + if ( tempbx & 0x04 ) + tempax |= 0x02 ; + + XGINew_SetRegANDOR( pVBInfo->P3d4 ,0x0a , ~0x02 , tempax ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , temp ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetResInfo */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGI_GetResInfo(USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT resindex ; + + if ( ModeNo <= 0x13 ) + { + resindex = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; /* si+St_ResInfo */ + } + else + { + resindex = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; /* si+Ext_ResInfo */ + } + return( resindex ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT1Offset */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT1Offset( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT temp , + ah , + al , + temp2 , + i , + DisplayUnit ; + + /* GetOffset */ + temp = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeInfo ; + temp = temp >> 8 ; + temp = pVBInfo->ScreenOffset[ temp ] ; + + temp2 = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ; + temp2 &= InterlaceMode ; + + if ( temp2 ) + temp = temp << 1; + + temp2 = pVBInfo->ModeType - ModeEGA ; + + switch( temp2 ) + { + case 0: + temp2 = 1 ; + break ; + case 1: + temp2 = 2 ; + break ; + case 2: + temp2 = 4 ; + break ; + case 3: + temp2 = 4 ; + break ; + case 4: + temp2 = 6 ; + break; + case 5: + temp2 = 8 ; + break ; + default: + break ; + } + + if ( ( ModeNo >= 0x26 ) && ( ModeNo <= 0x28 ) ) + temp = temp * temp2 + temp2 / 2 ; + else + temp *= temp2 ; + + /* SetOffset */ + DisplayUnit = temp ; + temp2 = temp ; + temp = temp >> 8 ; /* ah */ + temp &= 0x0F ; + i = XGINew_GetReg1( pVBInfo->P3c4 , 0x0E ) ; + i &= 0xF0 ; + i |= temp ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x0E , i ) ; + + temp =( UCHAR )temp2 ; + temp &= 0xFF ; /* al */ + XGINew_SetReg1( pVBInfo->P3d4 , 0x13 , temp ) ; + + /* SetDisplayUnit */ + temp2 = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ; + temp2 &= InterlaceMode ; + if ( temp2 ) + DisplayUnit >>= 1 ; + + DisplayUnit = DisplayUnit << 5 ; + ah = ( DisplayUnit & 0xff00 ) >> 8 ; + al = DisplayUnit & 0x00ff ; + if ( al == 0 ) + ah += 1 ; + else + ah += 2 ; + + if ( HwDeviceExtension->jChipType >= XG20 ) + if ( ( ModeNo == 0x4A ) | (ModeNo == 0x49 ) ) + ah -= 1 ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x10 , ah ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT1VCLK */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT1VCLK( USHORT ModeNo , USHORT ModeIdIndex , + PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR index , data ; + USHORT vclkindex ; + + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRTVCLK ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x31 ) & 0xCF ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , data ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->VCLKData[ index ].SR2B ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->VCLKData[ index ].SR2C ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2D , 0x01 ) ; + } + else if ( ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) && ( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) + { + vclkindex = XGI_GetVCLK2Ptr( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x31 ) & 0xCF ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , data ) ; + data = pVBInfo->VBVCLKData[ vclkindex ].Part4_A ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , data ) ; + data = pVBInfo->VBVCLKData[ vclkindex ].Part4_B ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , data ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2D , 0x01 ) ; + } + else + { + index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRTVCLK ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x31 ) & 0xCF ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , data ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->VCLKData[ index ].SR2B ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->VCLKData[ index ].SR2C ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2D , 0x01 ) ; + } + + if ( HwDeviceExtension->jChipType >= XG20 ) + { + if ( pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag & HalfDCLK ) + { + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x2B ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , data ) ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x2C ) ; + index = data ; + index &= 0xE0 ; + data &= 0x1F ; + data = data << 1 ; + data += 1 ; + data |= index ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , data ) ; + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT1FIFO */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT1FIFO( USHORT ModeNo , PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo ) +{ + USHORT data ; + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x3D ) ; + data &= 0xfe ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x3D , data ) ; /* diable auto-threshold */ + + if ( ModeNo > 0x13 ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x08 , 0x34 ) ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x09 ) ; + data &= 0xC0 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x09 , data | 0x30) ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x3D ) ; + data |= 0x01 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x3D , data ) ; + } + else + { + if (HwDeviceExtension->jChipType == XG27) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x08 , 0x0E ) ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x09 ) ; + data &= 0xC0 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x09 , data | 0x20 ) ; + } + else + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x08 , 0xAE ) ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x09 ) ; + data &= 0xF0 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x09 , data ) ; + } + } + + if (HwDeviceExtension->jChipType == XG21) + { + XGI_SetXG21FPBits(pVBInfo); /* Fix SR9[7:6] can't read back */ + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT1ModeRegs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT1ModeRegs( PXGI_HW_DEVICE_INFO HwDeviceExtension , + USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo ) +{ + USHORT data , + data2 , + data3 , + infoflag = 0 , + modeflag , + resindex , + xres ; + + if ( ModeNo > 0x13 ) + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + infoflag = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ; + } + else + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ModeFlag */ + + if ( XGINew_GetReg1( pVBInfo->P3d4 , 0x31 ) & 0x01 ) + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x1F , 0x3F , 0x00 ) ; + + if ( ModeNo > 0x13 ) + data = infoflag ; + else + data = 0 ; + + data2 = 0 ; + + if ( ModeNo > 0x13 ) + { + if ( pVBInfo->ModeType > 0x02 ) + { + data2 |= 0x02 ; + data3 = pVBInfo->ModeType - ModeVGA ; + data3 = data3 << 2 ; + data2 |= data3 ; + } + } + + data &= InterlaceMode ; + + if ( data ) + data2 |= 0x20 ; + + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x06 , ~0x3F , data2 ) ; + /* XGINew_SetReg1(pVBInfo->P3c4,0x06,data2); */ + resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ; + if ( ModeNo <= 0x13 ) + xres = pVBInfo->StResInfo[ resindex ].HTotal ; + else + xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */ + + data = 0x0000 ; + if ( infoflag & InterlaceMode ) + { + if ( xres == 1024 ) + data = 0x0035 ; + else if ( xres == 1280 ) + data = 0x0048 ; + } + + data2 = data & 0x00FF ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x19 , 0xFF , data2 ) ; + data2 = ( data & 0xFF00 ) >> 8 ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x19 , 0xFC , data2 ) ; + + if( modeflag & HalfDCLK ) + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x01 , 0xF7 , 0x08 ) ; + + data2 = 0 ; + + if ( modeflag & LineCompareOff ) + data2 |= 0x08 ; + + if ( ModeNo > 0x13 ) + { + if ( pVBInfo->ModeType == ModeEGA ) + data2 |= 0x40 ; + } + + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0F , ~0x48 , data2 ) ; + data = 0x60 ; + if ( pVBInfo->ModeType != ModeText ) + { + data = data ^ 0x60 ; + if ( pVBInfo->ModeType != ModeEGA ) + { + data = data ^ 0xA0 ; + } + } + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x21 , 0x1F , data ) ; + + XGI_SetVCLKState( HwDeviceExtension , ModeNo , RefreshRateTableIndex, pVBInfo) ; + + /* if(modeflag&HalfDCLK)//030305 fix lowresolution bug */ + /* if(XGINew_IF_DEF_NEW_LOWRES) */ + /* XGI_VesaLowResolution(ModeNo,ModeIdIndex);//030305 fix lowresolution bug */ + + data=XGINew_GetReg1( pVBInfo->P3d4 , 0x31 ) ; + + if (HwDeviceExtension->jChipType == XG27 ) + { + if ( data & 0x40 ) + data = 0x2c ; + else + data = 0x6c ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x52 , data ) ; + XGINew_SetRegOR( pVBInfo->P3d4 , 0x51 , 0x10 ) ; + } + else + if (HwDeviceExtension->jChipType >= XG20 ) + { + if ( data & 0x40 ) + data = 0x33 ; + else + data = 0x73 ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x52 , data ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x51 , 0x02 ) ; + } + else + { + if ( data & 0x40 ) + data = 0x2c ; + else + data = 0x6c ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x52 , data ) ; + } + +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetVCLKState */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetVCLKState( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo , USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo ) +{ + USHORT data , + data2 = 0 ; + SHORT VCLK ; + + UCHAR index ; + + if ( ModeNo <= 0x13 ) + VCLK = 0 ; + else + { + index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRTVCLK ; + index &= IndexMask ; + VCLK = pVBInfo->VCLKData[ index ].CLOCK ; + } + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x32 ) ; + data &= 0xf3 ; + if ( VCLK >= 200 ) + data |= 0x0c ; /* VCLK > 200 */ + + if ( HwDeviceExtension->jChipType >= XG20 ) + data &= ~0x04 ; /* 2 pixel mode */ + + XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , data ) ; + + if ( HwDeviceExtension->jChipType < XG20 ) + { + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1F ) ; + data &= 0xE7 ; + if ( VCLK < 200 ) + data |= 0x10 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x1F , data ) ; + } + +/* Jong for Adavantech LCD ripple issue + if ( ( VCLK >= 0 ) && ( VCLK < 135 ) ) + data2 = 0x03 ; + else if ( ( VCLK >= 135 ) && ( VCLK < 160 ) ) + data2 = 0x02 ; + else if ( ( VCLK >= 160 ) && ( VCLK < 260 ) ) + data2 = 0x01 ; + else if ( VCLK > 260 ) + data2 = 0x00 ; +*/ + data2 = 0x00 ; + + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x07 , 0xFC , data2 ) ; + if (HwDeviceExtension->jChipType >= XG27 ) + { + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x40 , 0xFC , data2&0x03 ) ; + } + + +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_VesaLowResolution */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +/*void XGI_VesaLowResolution( USHORT ModeNo , USHORT ModeIdIndex ,PVB_DEVICE_INFO pVBInfo) +{ + USHORT modeflag; + + if ( ModeNo > 0x13 ) + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + else + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + + if ( ModeNo > 0x13 ) + { + if ( modeflag & DoubleScanMode ) + { + if ( modeflag & HalfDCLK ) + { + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( !( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) ) + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x01 , 0xf7 , 0x00 ) ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0f , 0x7f , 0x00 ) ; + return ; + } + } + } + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0f , 0xff , 0x80 ) ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x01 , 0xf7 , 0x00 ) ; + return ; + } + } + } + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0f , 0x7f , 0x00 ) ; +} +*/ + +/* --------------------------------------------------------------------- */ +/* Function : XGI_LoadDAC */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_LoadDAC( USHORT ModeNo , USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo ) +{ + USHORT data , data2 , time , + i , j , k , m , n , o , + si , di , bx , dl , al , ah , dh , + *table = NULL ; + + if ( ModeNo <= 0x13 ) + data = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + else + data = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + + data &= DACInfoFlag ; + time = 64 ; + + if ( data == 0x00 ) + table = XGINew_MDA_DAC ; + else if ( data == 0x08 ) + table = XGINew_CGA_DAC ; + else if ( data == 0x10 ) + table = XGINew_EGA_DAC ; + else if ( data == 0x18 ) + { + time = 256 ; + table = XGINew_VGA_DAC ; + } + + if ( time == 256 ) + j = 16 ; + else + j = time ; + + XGINew_SetReg3( pVBInfo->P3c6 , 0xFF ) ; + XGINew_SetReg3( pVBInfo->P3c8 , 0x00 ) ; + + for( i = 0 ; i < j ; i++ ) + { + data = table[ i ] ; + + for( k = 0 ; k < 3 ; k++ ) + { + data2 = 0 ; + + if ( data & 0x01 ) + data2 = 0x2A ; + + if ( data & 0x02 ) + data2 += 0x15 ; + + XGINew_SetReg3( pVBInfo->P3c9 , data2 ) ; + data = data >> 2 ; + } + } + + if ( time == 256 ) + { + for( i = 16 ; i < 32 ; i++ ) + { + data = table[ i ] ; + + for( k = 0 ; k < 3 ; k++ ) + XGINew_SetReg3( pVBInfo->P3c9 , data ) ; + } + + si = 32 ; + + for( m = 0 ; m < 9 ; m++ ) + { + di = si ; + bx = si + 0x04 ; + dl = 0 ; + + for( n = 0 ; n < 3 ; n++ ) + { + for( o = 0 ; o < 5 ; o++ ) + { + dh = table[ si ] ; + ah = table[ di ] ; + al = table[ bx ] ; + si++ ; + XGI_WriteDAC( dl , ah , al , dh, pVBInfo ) ; + } + + si -= 2 ; + + for( o = 0 ; o < 3 ; o++ ) + { + dh = table[ bx ] ; + ah = table[ di ] ; + al = table[ si ] ; + si-- ; + XGI_WriteDAC( dl , ah , al , dh, pVBInfo ) ; + } + + dl++ ; + } + + si += 5 ; + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_WriteDAC */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_WriteDAC( USHORT dl , USHORT ah , USHORT al , USHORT dh,PVB_DEVICE_INFO pVBInfo ) +{ + USHORT temp , bh , bl ; + + bh = ah ; + bl = al ; + + if ( dl != 0 ) + { + temp = bh ; + bh = dh ; + dh = temp ; + if ( dl == 1 ) + { + temp = bl ; + bl = dh ; + dh = temp ; + } + else + { + temp = bl ; + bl = bh ; + bh = temp ; + } + } + XGINew_SetReg3( pVBInfo->P3c9 , ( USHORT )dh ) ; + XGINew_SetReg3( pVBInfo->P3c9 , ( USHORT )bh ) ; + XGINew_SetReg3( pVBInfo->P3c9 , ( USHORT )bl ) ; +} + +#if 0 +/* --------------------------------------------------------------------- */ +/* Function : XGI_ClearBuffer */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_ClearBuffer( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo, PVB_DEVICE_INFO pVBInfo) +{ + PVOID VideoMemoryAddress = ( PVOID )HwDeviceExtension->pjVideoMemoryAddress ; + ULONG AdapterMemorySize = ( ULONG )HwDeviceExtension->ulVideoMemorySize ; + PUSHORT pBuffer ; +#ifndef LINUX_XF86 + int i ; +#endif + + if ( pVBInfo->ModeType >= ModeEGA ) + { + if ( ModeNo > 0x13 ) + { + AdapterMemorySize = 0x40000 ; /* clear 256k */ + /* GetDRAMSize( HwDeviceExtension ) ; */ + XGI_SetMemory( VideoMemoryAddress , AdapterMemorySize , 0 ) ; + } + else + { +/* + pBuffer = VideoMemoryAddress ; + for( i = 0 ; i < 0x4000 ; i++ ) + pBuffer[ i ] = 0x0000 ; +*/ + } + } + else + { + pBuffer = VideoMemoryAddress ; + if ( pVBInfo->ModeType < ModeCGA ) + { +/* + for ( i = 0 ; i < 0x4000 ; i++ ) + pBuffer[ i ] = 0x0720 ; +*/ + } + else + XGI_SetMemory( VideoMemoryAddress , 0x8000 , 0 ) ; + } +} + +#endif +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetLCDAGroup */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetLCDAGroup( USHORT ModeNo , USHORT ModeIdIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT RefreshRateTableIndex ; + /* USHORT temp ; */ + + /* pVBInfo->SelectCRT2Rate = 0 ; */ + + pVBInfo->SetFlag |= ProgrammingCRT2 ; + RefreshRateTableIndex = XGI_GetRatePtrCRT2( HwDeviceExtension, ModeNo , ModeIdIndex, pVBInfo ) ; + XGI_GetLVDSResInfo( ModeNo , ModeIdIndex, pVBInfo ) ; + XGI_GetLVDSData( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo); + XGI_ModCRT1Regs( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ; + XGI_SetLVDSRegs( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + XGI_SetCRT2ECLK( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetLVDSResInfo */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetLVDSResInfo( USHORT ModeNo , USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo ) +{ + USHORT resindex , xres , yres , modeflag ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; /* si+St_ResInfo */ + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; /* si+Ext_ResInfo */ + } + + + /* if ( ModeNo > 0x13 ) */ + /* modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; */ + /* else */ + /* modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; */ + + if ( ModeNo <= 0x13 ) + { + resindex = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; /* si+St_ResInfo */ + } + else + { + resindex = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; /* si+Ext_ResInfo */ + } + + /* resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ; */ + + if ( ModeNo <= 0x13 ) + { + xres = pVBInfo->StResInfo[ resindex ].HTotal ; + yres = pVBInfo->StResInfo[ resindex ].VTotal ; + } + else + { + xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; + yres = pVBInfo->ModeResInfo[ resindex ].VTotal ; + } + if ( ModeNo > 0x13 ) + { + if ( modeflag & HalfDCLK ) + xres = xres << 1 ; + + if ( modeflag & DoubleScanMode ) + yres = yres << 1 ; + } + /* if ( modeflag & Charx8Dot ) */ + /* { */ + + if ( xres == 720 ) + xres = 640 ; + + /* } */ + pVBInfo->VGAHDE = xres ; + pVBInfo->HDE = xres ; + pVBInfo->VGAVDE = yres ; + pVBInfo->VDE = yres ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetLVDSData */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetLVDSData( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempbx ; + XGI330_LVDSDataStruct *LCDPtr = NULL ; + XGI330_CHTVDataStruct *TVPtr = NULL ; + + tempbx = 2 ; + + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + LCDPtr = ( XGI330_LVDSDataStruct * )XGI_GetLcdPtr( tempbx, ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo) ; + pVBInfo->VGAHT = LCDPtr->VGAHT ; + pVBInfo->VGAVT = LCDPtr->VGAVT ; + pVBInfo->HT = LCDPtr->LCDHT ; + pVBInfo->VT = LCDPtr->LCDVT ; + } + if ( pVBInfo->IF_DEF_CH7017 == 1 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + TVPtr = ( XGI330_CHTVDataStruct * )XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + pVBInfo->VGAHT = TVPtr->VGAHT ; + pVBInfo->VGAVT = TVPtr->VGAVT ; + pVBInfo->HT = TVPtr->LCDHT ; + pVBInfo->VT = TVPtr->LCDVT ; + } + } + + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + if ( !( pVBInfo->LCDInfo & ( SetLCDtoNonExpanding | EnableScalingLCD ) ) ) + { + if ( ( pVBInfo->LCDResInfo == Panel1024x768 ) || ( pVBInfo->LCDResInfo == Panel1024x768x75 ) ) + { + pVBInfo->HDE = 1024 ; + pVBInfo->VDE = 768 ; + } + else if ( ( pVBInfo->LCDResInfo == Panel1280x1024 ) || ( pVBInfo->LCDResInfo == Panel1280x1024x75 ) ) + { + pVBInfo->HDE = 1280 ; + pVBInfo->VDE = 1024 ; + } + else if ( pVBInfo->LCDResInfo == Panel1400x1050 ) + { + pVBInfo->HDE = 1400 ; + pVBInfo->VDE = 1050 ; + } + else + { + pVBInfo->HDE = 1600 ; + pVBInfo->VDE = 1200 ; + } + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_ModCRT1Regs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_ModCRT1Regs( USHORT ModeNo , USHORT ModeIdIndex , + USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR index ; + USHORT tempbx , i ; + XGI_LVDSCRT1HDataStruct *LCDPtr = NULL ; + XGI_LVDSCRT1VDataStruct *LCDPtr1 =NULL ; + /* XGI330_CHTVDataStruct *TVPtr = NULL ; */ + XGI_CH7007TV_TimingHStruct *CH7007TV_TimingHPtr = NULL; + XGI_CH7007TV_TimingVStruct *CH7007TV_TimingVPtr = NULL; + + if( ModeNo <= 0x13 ) + index = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ; + else + index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + + index= index & IndexMask ; + + if ( ( pVBInfo->IF_DEF_ScaleLCD == 0 ) || ( ( pVBInfo->IF_DEF_ScaleLCD == 1 ) && ( !( pVBInfo->LCDInfo & EnableScalingLCD ) ) ) ) + { + tempbx = 0 ; + + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + LCDPtr = ( XGI_LVDSCRT1HDataStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + + for( i = 0 ; i < 8 ; i++ ) + pVBInfo->TimingH[ 0 ].data[ i ] = LCDPtr[ 0 ].Reg[ i ] ; + } + + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + CH7007TV_TimingHPtr = ( XGI_CH7007TV_TimingHStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + + for( i = 0 ; i < 8 ; i++ ) + pVBInfo->TimingH[ 0 ].data[ i ] = CH7007TV_TimingHPtr[ 0 ].data[ i ] ; + } + } + + /* if ( pVBInfo->IF_DEF_CH7017 == 1 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + TVPtr = ( XGI330_CHTVDataStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + } */ + + XGI_SetCRT1Timing_H(pVBInfo,HwDeviceExtension) ; + + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , CH7007TV_TimingHPtr[ 0 ].data[ 8 ] ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , CH7007TV_TimingHPtr[ 0 ].data[ 9 ] ) ; + } + + tempbx = 1 ; + + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + LCDPtr1 = ( XGI_LVDSCRT1VDataStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + for( i = 0 ; i < 7 ; i++ ) + pVBInfo->TimingV[ 0 ].data[ i ] = LCDPtr1[ 0 ].Reg[ i ] ; + } + + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + CH7007TV_TimingVPtr = ( XGI_CH7007TV_TimingVStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + + for( i = 0 ; i < 7 ; i++ ) + pVBInfo->TimingV[ 0 ].data[ i ] = CH7007TV_TimingVPtr[ 0 ].data[ i ] ; + } + } + /* if ( pVBInfo->IF_DEF_CH7017 == 1 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + TVPtr = ( XGI330_CHTVDataStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + } */ + + XGI_SetCRT1Timing_V( ModeIdIndex , ModeNo , pVBInfo) ; + + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x33 , ~0x01 , CH7007TV_TimingVPtr[ 0 ].data[ 7 ]&0x01 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , CH7007TV_TimingVPtr[ 0 ].data[8 ] ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x3F , CH7007TV_TimingVPtr[ 0 ].data[9 ] ) ; + + } + } +} + + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetLVDSRegs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempbx , tempax , tempcx , tempdx , push1 , push2 , modeflag ; + unsigned long temp , temp1 , temp2 , temp3 , push3 ; + XGI330_LCDDataDesStruct *LCDPtr = NULL ; + XGI330_LCDDataDesStruct2 *LCDPtr1 = NULL ; + + if ( ModeNo > 0x13 ) + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + else + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + + if ( !( pVBInfo->SetFlag & Win9xDOSMode ) ) + { + if ( ( pVBInfo->IF_DEF_CH7017 == 0 ) || ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) ) + { + if ( pVBInfo->IF_DEF_OEMUtil == 1 ) + { + tempbx = 8 ; + LCDPtr = ( XGI330_LCDDataDesStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + } + + if ( ( pVBInfo->IF_DEF_OEMUtil == 0 ) || ( LCDPtr == 0 ) ) + { + tempbx = 3 ; + if ( pVBInfo->LCDInfo & EnableScalingLCD ) + LCDPtr1 = ( XGI330_LCDDataDesStruct2 * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + else + LCDPtr = ( XGI330_LCDDataDesStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + } + + XGI_GetLCDSync( &tempax , &tempbx ,pVBInfo) ; + push1 = tempbx ; + push2 = tempax ; + + /* GetLCDResInfo */ + if ( ( pVBInfo->LCDResInfo == Panel1024x768 ) || ( pVBInfo->LCDResInfo == Panel1024x768x75 ) ) + { + tempax = 1024 ; + tempbx = 768 ; + } + else if ( ( pVBInfo->LCDResInfo == Panel1280x1024 ) || ( pVBInfo->LCDResInfo == Panel1280x1024x75 ) ) + { + tempax = 1280 ; + tempbx = 1024 ; + } + else if ( pVBInfo->LCDResInfo == Panel1400x1050 ) + { + tempax = 1400 ; + tempbx = 1050 ; + } + else + { + tempax = 1600 ; + tempbx = 1200 ; + } + + if ( pVBInfo->LCDInfo & SetLCDtoNonExpanding ) + { + pVBInfo->HDE=tempax; + pVBInfo->VDE=tempbx; + pVBInfo->VGAHDE=tempax; + pVBInfo->VGAVDE=tempbx; + } + + if ( ( pVBInfo->IF_DEF_ScaleLCD == 1 ) && ( pVBInfo->LCDInfo & EnableScalingLCD ) ) + { + tempax=pVBInfo->HDE; + tempbx=pVBInfo->VDE; + } + + tempax = pVBInfo->HT ; + + if ( pVBInfo->LCDInfo & EnableScalingLCD ) + tempbx = LCDPtr1->LCDHDES ; + else + tempbx = LCDPtr->LCDHDES ; + + tempcx = pVBInfo->HDE ; + tempbx = tempbx & 0x0fff ; + tempcx += tempbx ; + + if ( tempcx >= tempax ) + tempcx -= tempax ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x1A , tempbx & 0x07 ) ; + + tempcx = tempcx >> 3 ; + tempbx = tempbx >> 3 ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x16 , ( USHORT )( tempbx & 0xff ) ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x17 , ( USHORT )( tempcx & 0xff ) ) ; + + tempax = pVBInfo->HT ; + + if ( pVBInfo->LCDInfo & EnableScalingLCD ) + tempbx = LCDPtr1->LCDHRS ; + else + tempbx = LCDPtr->LCDHRS ; + + tempcx = push2 ; + + if ( pVBInfo->LCDInfo & EnableScalingLCD ) + tempcx = LCDPtr1->LCDHSync ; + + tempcx += tempbx ; + + if ( tempcx >= tempax ) + tempcx -= tempax ; + + tempax = tempbx & 0x07 ; + tempax = tempax >> 5 ; + tempcx = tempcx >> 3 ; + tempbx = tempbx >> 3 ; + + tempcx &= 0x1f ; + tempax |= tempcx ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x15 , tempax ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x14 , ( USHORT )( tempbx & 0xff ) ) ; + + tempax = pVBInfo->VT ; + if ( pVBInfo->LCDInfo & EnableScalingLCD ) + tempbx = LCDPtr1->LCDVDES ; + else + tempbx = LCDPtr->LCDVDES ; + tempcx = pVBInfo->VDE ; + + tempbx = tempbx & 0x0fff ; + tempcx += tempbx ; + if ( tempcx >= tempax ) + tempcx -= tempax ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x1b , ( USHORT )( tempbx & 0xff ) ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x1c , ( USHORT )( tempcx & 0xff ) ) ; + + tempbx = ( tempbx >> 8 ) & 0x07 ; + tempcx = ( tempcx >> 8 ) & 0x07 ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x1d , ( USHORT )( ( tempcx << 3 ) | tempbx ) ) ; + + tempax = pVBInfo->VT ; + if ( pVBInfo->LCDInfo & EnableScalingLCD ) + tempbx = LCDPtr1->LCDVRS ; + else + tempbx = LCDPtr->LCDVRS ; + + /* tempbx = tempbx >> 4 ; */ + tempcx = push1 ; + + if ( pVBInfo->LCDInfo & EnableScalingLCD ) + tempcx = LCDPtr1->LCDVSync ; + + tempcx += tempbx ; + if ( tempcx >= tempax ) + tempcx -= tempax ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x18 , ( USHORT )( tempbx & 0xff ) ) ; + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , ~0x0f , ( USHORT )( tempcx & 0x0f ) ) ; + + tempax = ( ( tempbx >> 8 ) & 0x07 ) << 3 ; + + tempbx = pVBInfo->VGAVDE ; + if ( tempbx != pVBInfo->VDE ) + tempax |= 0x40 ; + + if ( pVBInfo->LCDInfo & EnableLVDSDDA ) + tempax |= 0x40 ; + + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x1a , 0x07 , tempax ) ; + + tempcx = pVBInfo->VGAVT ; + tempbx = pVBInfo->VDE ; + tempax = pVBInfo->VGAVDE ; + tempcx -= tempax ; + + temp = tempax ; /* 0430 ylshieh */ + temp1 = ( temp << 18 ) / tempbx ; + + tempdx = ( USHORT )( ( temp << 18 ) % tempbx ) ; + + if ( tempdx != 0 ) + temp1 += 1 ; + + temp2 = temp1 ; + push3 = temp2 ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x37 , ( USHORT )( temp2 & 0xff ) ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x36 , ( USHORT )( ( temp2 >> 8 ) & 0xff ) ) ; + + tempbx = ( USHORT )( temp2 >> 16 ) ; + tempax = tempbx & 0x03 ; + + tempbx = pVBInfo->VGAVDE ; + if ( tempbx == pVBInfo->VDE ) + tempax |= 0x04 ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x35 , tempax ) ; + + if ( pVBInfo->VBType & VB_XGI301C ) + { + temp2 = push3 ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x3c , ( USHORT )( temp2 & 0xff ) ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x3b , ( USHORT )( ( temp2 >> 8 ) & 0xff ) ) ; + tempbx = ( USHORT )( temp2 >> 16 ) ; + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x3a , ~0xc0 , ( USHORT )( ( tempbx & 0xff ) << 6 ) ) ; + + tempcx = pVBInfo->VGAVDE ; + if ( tempcx == pVBInfo->VDE ) + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x30 , ~0x0c , 0x00 ) ; + else + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x30 , ~0x0c , 0x08 ) ; + } + + tempcx = pVBInfo->VGAHDE ; + tempbx = pVBInfo->HDE ; + + temp1 = tempcx << 16 ; + + tempax = ( USHORT )( temp1 / tempbx ) ; + + if ( ( tempbx & 0xffff ) == ( tempcx & 0xffff ) ) + tempax = 65535 ; + + temp3 = tempax ; + temp1 = pVBInfo->VGAHDE << 16 ; + + temp1 /= temp3 ; + temp3 = temp3 << 16 ; + temp1 -= 1 ; + + temp3 = ( temp3 & 0xffff0000 ) + ( temp1 & 0xffff ) ; + + tempax = ( USHORT )( temp3 & 0xff ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x1f , tempax ) ; + + temp1 = pVBInfo->VGAVDE << 18 ; + temp1 = temp1 / push3 ; + tempbx = ( USHORT )( temp1 & 0xffff ) ; + + if ( pVBInfo->LCDResInfo == Panel1024x768 ) + tempbx -= 1 ; + + tempax = ( ( tempbx >> 8 ) & 0xff ) << 3 ; + tempax |= ( USHORT )( ( temp3 >> 8 ) & 0x07 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x20 , ( USHORT )( tempax & 0xff ) ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x21 , ( USHORT )( tempbx & 0xff ) ) ; + + temp3 = temp3 >> 16 ; + + if ( modeflag & HalfDCLK ) + temp3 = temp3 >> 1 ; + + XGINew_SetReg1(pVBInfo->Part1Port , 0x22 , ( USHORT )( ( temp3 >> 8 ) & 0xff ) ) ; + XGINew_SetReg1(pVBInfo->Part1Port , 0x23 , ( USHORT )( temp3 & 0xff ) ) ; + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT2ECLK */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT2ECLK( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR di_0 , di_1 , tempal ; + int i ; + + tempal = XGI_GetVCLKPtr( RefreshRateTableIndex , ModeNo , ModeIdIndex, pVBInfo ) ; + XGI_GetVCLKLen( tempal , &di_0 , &di_1, pVBInfo ) ; + XGI_GetLCDVCLKPtr( &di_0 , &di_1, pVBInfo ) ; + + for( i = 0 ; i < 4 ; i++ ) + { + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x31 , ~0x30 , ( USHORT )( 0x10 * i ) ) ; + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x2b , di_0 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2c , di_1 ) ; + } + else if ( ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) && ( !( pVBInfo->VBInfo & SetInSlaveMode ) ) ) + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x2e , di_0 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2f , di_1 ) ; + } + else + { + XGINew_SetReg1( pVBInfo->P3c4 , 0x2b , di_0 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2c , di_1 ) ; + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_UpdateModeInfo */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_UpdateModeInfo( PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempcl , + tempch , + temp , + tempbl , + tempax ; + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + tempcl = 0 ; + tempch = 0 ; + temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x01 ) ; + + if ( !( temp & 0x20 ) ) + { + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x17 ) ; + if ( temp & 0x80 ) + { + if ( ( HwDeviceExtension->jChipType >= XG20 ) || ( HwDeviceExtension->jChipType >= XG40 ) ) + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x53 ) ; + else + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x63 ) ; + + if ( !( temp & 0x40 ) ) + tempcl |= ActiveCRT1 ; + } + } + + temp = XGINew_GetReg1( pVBInfo->Part1Port , 0x2e ) ; + temp &= 0x0f ; + + if ( !( temp == 0x08 ) ) + { + tempax = XGINew_GetReg1( pVBInfo->Part1Port , 0x13 ) ; /* Check ChannelA by Part1_13 [2003/10/03] */ + if ( tempax & 0x04 ) + tempcl = tempcl | ActiveLCD ; + + temp &= 0x05 ; + + if ( !( tempcl & ActiveLCD ) ) + if ( temp == 0x01 ) + tempcl |= ActiveCRT2 ; + + if ( temp == 0x04 ) + tempcl |= ActiveLCD ; + + if ( temp == 0x05 ) + { + temp = XGINew_GetReg1( pVBInfo->Part2Port , 0x00 ) ; + + if( !( temp & 0x08 ) ) + tempch |= ActiveAVideo ; + + if ( !( temp & 0x04 ) ) + tempch |= ActiveSVideo ; + + if ( temp & 0x02 ) + tempch |= ActiveSCART ; + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + if ( temp & 0x01 ) + tempch |= ActiveHiTV ; + } + + if ( pVBInfo->VBInfo & SetCRT2ToYPbPr ) + { + temp = XGINew_GetReg1( pVBInfo->Part2Port , 0x4d ) ; + + if ( temp & 0x10 ) + tempch |= ActiveYPbPr ; + } + + if ( tempch != 0 ) + tempcl |= ActiveTV ; + } + } + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x3d ) ; + if ( tempcl & ActiveLCD ) + { + if ( ( pVBInfo->SetFlag & ReserveTVOption ) ) + { + if ( temp & ActiveTV ) + tempcl |= ActiveTV ; + } + } + temp = tempcl ; + tempbl = ~ModeSwitchStatus ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x3d , tempbl , temp ) ; + + if ( !( pVBInfo->SetFlag & ReserveTVOption ) ) + XGINew_SetReg1( pVBInfo->P3d4 , 0x3e , tempch ) ; + } + else + { + return ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetVGAType */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetVGAType( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + /* + if ( HwDeviceExtension->jChipType >= XG20 ) + { + pVBInfo->Set_VGAType = XG20; + } + else if ( HwDeviceExtension->jChipType >= XG40 ) + { + pVBInfo->Set_VGAType = VGA_XGI340 ; + } + */ + pVBInfo->Set_VGAType = HwDeviceExtension->jChipType; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetVBType */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetVBType(PVB_DEVICE_INFO pVBInfo) +{ + USHORT flag , tempbx , tempah ; + + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + pVBInfo->VBType = VB_CH7007 ; + return; + } + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + tempbx = VB_XGI302B ; + flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x00 ) ; + if ( flag != 0x02 ) + { + tempbx = VB_XGI301 ; + flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) ; + if ( flag >= 0xB0 ) + { + tempbx = VB_XGI301B ; + if ( flag >= 0xC0 ) + { + tempbx = VB_XGI301C ; + if ( flag >= 0xD0 ) + { + tempbx = VB_XGI301LV ; + if ( flag >= 0xE0 ) + { + tempbx = VB_XGI302LV ; + tempah = XGINew_GetReg1( pVBInfo->Part4Port , 0x39 ) ; + if ( tempah != 0xFF ) + tempbx = VB_XGI301C ; + } + } + } + + if ( tempbx & ( VB_XGI301B | VB_XGI302B ) ) + { + flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x23 ) ; + + if ( !( flag & 0x02 ) ) + tempbx = tempbx | VB_NoLCD ; + } + } + } + pVBInfo->VBType = tempbx ; + } +/* + else if ( pVBInfo->IF_DEF_CH7017 == 1 ) + pVBInfo->VBType = VB_CH7017 ; + else //LVDS + pVBInfo->VBType = VB_LVDS_NS ; +*/ + +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetVBInfo */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetVBInfo( USHORT ModeNo , USHORT ModeIdIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempax , + push , + tempbx , + temp , + modeflag ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + } + + pVBInfo->SetFlag = 0 ; + pVBInfo->ModeType = modeflag & ModeInfoFlag ; + tempbx = 0 ; + + if ( pVBInfo->VBType & 0xFFFF ) + { + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x30 ) ; /* Check Display Device */ + tempbx = tempbx | temp ; + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x31 ) ; + push = temp ; + push = push << 8 ; + tempax = temp << 8 ; + tempbx = tempbx | tempax ; + temp = ( SetCRT2ToDualEdge | SetCRT2ToYPbPr | SetCRT2ToLCDA | SetInSlaveMode | DisableCRT2Display ) ; + temp = 0xFFFF ^ temp ; + tempbx &= temp ; + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ; + + if ( pVBInfo->IF_DEF_LCDA == 1 ) + { + + if ( ( pVBInfo->Set_VGAType >= XG20 ) || ( pVBInfo->Set_VGAType >= XG40 )) + { + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + /* if ( ( pVBInfo->VBType & VB_XGI302B ) || ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) || ( pVBInfo->VBType & VB_XGI301C ) ) */ + if ( pVBInfo->VBType & ( VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( temp & EnableDualEdge ) + { + tempbx |= SetCRT2ToDualEdge ; + + if ( temp & SetToLCDA ) + tempbx |= SetCRT2ToLCDA ; + } + } + } + else if ( pVBInfo->IF_DEF_CH7017 == 1 ) + { + if ( pVBInfo->VBType & VB_CH7017 ) + { + if ( temp & EnableDualEdge ) + { + tempbx |= SetCRT2ToDualEdge ; + + if ( temp & SetToLCDA ) + tempbx |= SetCRT2ToLCDA ; + } + } + } + } + } + + if ( pVBInfo->IF_DEF_YPbPr == 1 ) + { + if ( ( ( pVBInfo->IF_DEF_LVDS == 0 ) && ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) || ( pVBInfo->VBType & VB_XGI301C ) ) ) + || ( ( pVBInfo->IF_DEF_CH7017 == 1 ) && ( pVBInfo->VBType&VB_CH7017 ) ) || ( (pVBInfo->IF_DEF_CH7007 == 1) && (pVBInfo->VBType&VB_CH7007) ) ) /* [Billy] 07/05/04 */ + { + if ( temp & SetYPbPr ) /* temp = CR38 */ + { + if ( pVBInfo->IF_DEF_HiVision == 1 ) + { + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x35 ) ; /* shampoo add for new scratch */ + temp &= YPbPrMode ; + tempbx |= SetCRT2ToHiVisionTV ; + + if ( temp != YPbPrMode1080i ) { + tempbx &= ( ~SetCRT2ToHiVisionTV ) ; + tempbx |= SetCRT2ToYPbPr ; } + } + + /* tempbx |= SetCRT2ToYPbPr ; */ + } + } + } + + tempax = push ; /* restore CR31 */ + + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + if ( pVBInfo->IF_DEF_YPbPr == 1 ) + { + if ( pVBInfo->IF_DEF_HiVision == 1 ) + temp = 0x09FC ; + else + temp = 0x097C ; + } + else + { + if ( pVBInfo->IF_DEF_HiVision == 1 ) + temp = 0x01FC ; + else + temp = 0x017C ; + } + } + else /* 3nd party chip */ + { + if ( pVBInfo->IF_DEF_CH7017 == 1 ) + temp = ( SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA ) ; + else if ( pVBInfo->IF_DEF_CH7007 == 1 ) /* [Billy] 07/05/03 */ + { + temp = SetCRT2ToTV ; + } + else + temp = SetCRT2ToLCD ; + } + + if ( !( tempbx & temp ) ) + { + tempax |= DisableCRT2Display ; + tempbx = 0 ; + } + + if ( pVBInfo->IF_DEF_LCDA == 1 ) /* Select Display Device */ + { + if ( !( pVBInfo->VBType & VB_NoLCD ) ) + { + if ( tempbx & SetCRT2ToLCDA ) + { + if ( tempbx & SetSimuScanMode ) + tempbx &= ( ~( SetCRT2ToLCD | SetCRT2ToRAMDAC | SwitchToCRT2 ) ) ; + else + tempbx &= ( ~( SetCRT2ToLCD | SetCRT2ToRAMDAC | SetCRT2ToTV | SwitchToCRT2 ) ) ; + } + } + } + + /* shampoo add */ + if ( !( tempbx & ( SwitchToCRT2 | SetSimuScanMode ) ) ) /* for driver abnormal */ + { + if ( pVBInfo->IF_DEF_CRT2Monitor == 1 ) + { + if ( tempbx & SetCRT2ToRAMDAC ) + { + tempbx &= ( 0xFF00 | SetCRT2ToRAMDAC | SwitchToCRT2 | SetSimuScanMode ) ; + tempbx &= ( 0x00FF | ( ~SetCRT2ToYPbPr ) ) ; + } + } + else + tempbx &= ( ~( SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV ) ) ; + } + + if ( !( pVBInfo->VBType & VB_NoLCD ) ) + { + if ( tempbx & SetCRT2ToLCD ) + { + tempbx &= ( 0xFF00 | SetCRT2ToLCD | SwitchToCRT2 | SetSimuScanMode ) ; + tempbx &= ( 0x00FF | ( ~SetCRT2ToYPbPr ) ) ; + } + } + + if ( tempbx & SetCRT2ToSCART ) + { + tempbx &= ( 0xFF00 | SetCRT2ToSCART | SwitchToCRT2 | SetSimuScanMode ) ; + tempbx &= ( 0x00FF | ( ~SetCRT2ToYPbPr ) ) ; + } + + if ( pVBInfo->IF_DEF_YPbPr == 1 ) + { + if ( tempbx & SetCRT2ToYPbPr ) + tempbx &= ( 0xFF00 | SwitchToCRT2 | SetSimuScanMode ) ; + } + + if ( pVBInfo->IF_DEF_HiVision == 1 ) + { + if ( tempbx & SetCRT2ToHiVisionTV ) + tempbx &= ( 0xFF00 | SetCRT2ToHiVisionTV | SwitchToCRT2 | SetSimuScanMode ) ; + } + + if ( tempax & DisableCRT2Display ) /* Set Display Device Info */ + { + if ( !( tempbx & ( SwitchToCRT2 | SetSimuScanMode ) ) ) + tempbx = DisableCRT2Display ; + } + + if ( !( tempbx & DisableCRT2Display ) ) + { + if ( ( !( tempbx & DriverMode ) ) || ( !( modeflag & CRT2Mode ) ) ) + { + if ( pVBInfo->IF_DEF_LCDA == 1 ) + { + if ( !( tempbx & SetCRT2ToLCDA ) ) + tempbx |= ( SetInSlaveMode | SetSimuScanMode ) ; + } + + if ( pVBInfo->IF_DEF_VideoCapture == 1 ) + { + if ( ( ( HwDeviceExtension->jChipType == XG40 ) && ( pVBInfo->Set_VGAType == XG40 ) ) + || ( ( HwDeviceExtension->jChipType == XG41 ) && ( pVBInfo->Set_VGAType == XG41 ) ) + || ( ( HwDeviceExtension->jChipType == XG42 ) && ( pVBInfo->Set_VGAType == XG42 ) ) + || ( ( HwDeviceExtension->jChipType == XG45 ) && ( pVBInfo->Set_VGAType == XG45 ) ) ) + { + if ( ModeNo <= 13 ) + { + if ( !( tempbx & SetCRT2ToRAMDAC ) ) /*CRT2 not need to support*/ + { + tempbx &= ( 0x00FF | ( ~SetInSlaveMode ) ) ; + pVBInfo->SetFlag |= EnableVCMode ; + } + } + } + } + } + + /*LCD+TV can't support in slave mode (Force LCDA+TV->LCDB)*/ + if ( ( tempbx & SetInSlaveMode ) && ( tempbx & SetCRT2ToLCDA ) ) + { + tempbx ^= ( SetCRT2ToLCD | SetCRT2ToLCDA | SetCRT2ToDualEdge ) ; + pVBInfo->SetFlag |= ReserveTVOption ; + } + } + } + + pVBInfo->VBInfo = tempbx ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetTVInfo */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetTVInfo( USHORT ModeNo , USHORT ModeIdIndex ,PVB_DEVICE_INFO pVBInfo ) +{ + USHORT temp , + tempbx = 0 , + resinfo = 0 , + modeflag , + index1 ; + + tempbx = 0 ; + resinfo = 0 ; + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ModeFlag */ + resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; /* si+St_ResInfo */ + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; /* si+Ext_ResInfo */ + } + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x35 ) ; + tempbx = temp; + if ( tempbx & SetPALTV ) + { + tempbx &= ( SetCHTVOverScan | SetPALMTV | SetPALNTV | SetPALTV ) ; + if ( tempbx & SetPALMTV ) + tempbx &= ~SetPALTV ; /* set to NTSC if PAL-M */ + } + else + tempbx &= ( SetCHTVOverScan | SetNTSCJ | SetPALTV ) ; +/* + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + index1 = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ; //PAL-M/PAL-N Info + temp2 = ( index1 & 0xC0 ) >> 5 ; //00:PAL, 01:PAL-M, 10:PAL-N + tempbx |= temp2 ; + if ( temp2 & 0x02 ) //PAL-M + tempbx &= ( ~SetPALTV ) ; + } +*/ + } + + if ( pVBInfo->IF_DEF_CH7017 == 1 ) + { + tempbx = XGINew_GetReg1( pVBInfo->P3d4 , 0x35 ) ; + + if ( tempbx & TVOverScan ) + tempbx |= SetCHTVOverScan ; + } + + if ( pVBInfo->IF_DEF_CH7007 == 1 ) /* [Billy] 07/05/04 */ + { + tempbx = XGINew_GetReg1( pVBInfo->P3d4 , 0x35 ) ; + + if ( tempbx & TVOverScan ) + { + tempbx |= SetCHTVOverScan ; + } + } + + + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToSCART ) + tempbx |= SetPALTV ; + } + + if ( pVBInfo->IF_DEF_YPbPr == 1 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToYPbPr ) + { + index1 = XGINew_GetReg1( pVBInfo->P3d4 , 0x35 ) ; + index1 &= YPbPrMode ; + + if ( index1 == YPbPrMode525i ) + tempbx |= SetYPbPrMode525i ; + + if ( index1 == YPbPrMode525p ) + tempbx = tempbx | SetYPbPrMode525p; + if ( index1 == YPbPrMode750p) + tempbx = tempbx | SetYPbPrMode750p; + } + } + + if ( pVBInfo->IF_DEF_HiVision == 1 ) + { + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + tempbx = tempbx | SetYPbPrMode1080i | SetPALTV ; + } + } + + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { /* shampoo */ + if ( ( pVBInfo->VBInfo & SetInSlaveMode ) && ( !( pVBInfo->VBInfo & SetNotSimuMode ) ) ) + tempbx |= TVSimuMode ; + + if ( !( tempbx & SetPALTV ) && ( modeflag > 13 ) && ( resinfo == 8 ) ) /* NTSC 1024x768, */ + tempbx |= NTSC1024x768 ; + + tempbx |= RPLLDIV2XO ; + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + tempbx &=( ~RPLLDIV2XO ) ; + } + else + { + if ( tempbx & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) + tempbx &= ( ~RPLLDIV2XO ) ; + else if ( !( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) ) + { + if ( tempbx & TVSimuMode ) + tempbx &= ( ~RPLLDIV2XO ) ; + } + } + } + } + pVBInfo->TVInfo = tempbx ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetLCDInfo */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_GetLCDInfo( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo) +{ + USHORT temp , + tempax , + tempbx , + modeflag , + resinfo = 0 , + LCDIdIndex ; + + pVBInfo->LCDResInfo = 0 ; + pVBInfo->LCDTypeInfo = 0 ; + pVBInfo->LCDInfo = 0 ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ModeFlag // */ + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; /* si+Ext_ResInfo// */ + } + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x36 ) ; /* Get LCD Res.Info */ + tempbx = temp & 0x0F ; + + if ( tempbx == 0 ) + tempbx = Panel1024x768 ; /* default */ + + /* LCD75 [2003/8/22] Vicent */ + if ( ( tempbx == Panel1024x768 ) || ( tempbx == Panel1280x1024 ) ) + { + if ( pVBInfo->VBInfo & DriverMode ) + { + tempax = XGINew_GetReg1( pVBInfo->P3d4 , 0x33 ) ; + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + tempax &= 0x0F ; + else + tempax = tempax >> 4 ; + + if ( ( resinfo == 6 ) || ( resinfo == 9 ) ) + { + if ( tempax >= 3 ) + tempbx |= PanelRef75Hz ; + } + else if ( ( resinfo == 7 ) || ( resinfo == 8 ) ) + { + if ( tempax >= 4 ) + tempbx |= PanelRef75Hz ; + } + } + } + + pVBInfo->LCDResInfo = tempbx ; + + /* End of LCD75 */ + + if( pVBInfo->IF_DEF_OEMUtil == 1 ) + { + pVBInfo->LCDTypeInfo = ( temp & 0xf0 ) >> 4 ; + } + + if ( !( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) ) + { + return 0; + } + + tempbx = 0 ; + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ; + + temp &= ( ScalingLCD | LCDNonExpanding | LCDSyncBit | SetPWDEnable ) ; + + if ( ( pVBInfo->IF_DEF_ScaleLCD == 1 ) && ( temp & LCDNonExpanding ) ) + temp &= ~EnableScalingLCD ; + + tempbx |= temp ; + + LCDIdIndex = XGI_GetLCDCapPtr1(pVBInfo) ; + + tempax = pVBInfo->LCDCapList[ LCDIdIndex ].LCD_Capability ; + + if ( pVBInfo->IF_DEF_LVDS == 0 ) /* shampoo */ + { + if ( ( ( pVBInfo->VBType & VB_XGI302LV ) || ( pVBInfo->VBType & VB_XGI301C ) ) && ( tempax & LCDDualLink ) ) + { + tempbx |= SetLCDDualLink ; + } + } + + if ( pVBInfo->IF_DEF_CH7017 == 1 ) + { + if ( tempax & LCDDualLink ) + { + tempbx |= SetLCDDualLink ; + } + } + + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + if ( ( pVBInfo->LCDResInfo == Panel1400x1050 ) && ( pVBInfo->VBInfo & SetCRT2ToLCD ) && ( ModeNo > 0x13 ) && ( resinfo == 9 ) && ( !( tempbx & EnableScalingLCD ) ) ) + tempbx |= SetLCDtoNonExpanding ; /* set to center in 1280x1024 LCDB for Panel1400x1050 */ + } + +/* + if ( tempax & LCDBToA ) + { + tempbx |= SetLCDBToA ; + } +*/ + + if ( pVBInfo->IF_DEF_ExpLink == 1 ) + { + if ( modeflag & HalfDCLK ) + { + /* if ( !( pVBInfo->LCDInfo&LCDNonExpanding ) ) */ + if ( !( tempbx & SetLCDtoNonExpanding ) ) + { + tempbx |= EnableLVDSDDA ; + } + else + { + if ( ModeNo > 0x13 ) + { + if ( pVBInfo->LCDResInfo == Panel1024x768 ) + { + if ( resinfo == 4 ) + { /* 512x384 */ + tempbx |= EnableLVDSDDA ; + } + } + } + } + } + } + + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( pVBInfo->VBInfo & SetNotSimuMode ) + { + tempbx |= LCDVESATiming ; + } + } + else + { + tempbx |= LCDVESATiming ; + } + + pVBInfo->LCDInfo = tempbx ; + + if ( pVBInfo->IF_DEF_PWD == 1 ) + { + if ( pVBInfo->LCDInfo & SetPWDEnable ) + { + if ( ( pVBInfo->VBType & VB_XGI302LV ) || ( pVBInfo->VBType & VB_XGI301C ) ) + { + if ( !( tempax & PWDEnable ) ) + { + pVBInfo->LCDInfo &= ~SetPWDEnable ; + } + } + } + } + + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + if ( tempax & ( LockLCDBToA | StLCDBToA ) ) + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( !( tempax & LockLCDBToA ) ) + { + if ( ModeNo <= 0x13 ) + { + pVBInfo->VBInfo &= ~( SetSimuScanMode | SetInSlaveMode | SetCRT2ToLCD ) ; + pVBInfo->VBInfo |= SetCRT2ToLCDA | SetCRT2ToDualEdge ; + } + } + } + } + } + +/* + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + if ( tempax & ( LockLCDBToA | StLCDBToA ) ) + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( !( ( !( tempax & LockLCDBToA ) ) && ( ModeNo > 0x13 ) ) ) + { + pVBInfo->VBInfo&=~(SetSimuScanMode|SetInSlaveMode|SetCRT2ToLCD); + pVBInfo->VBInfo|=SetCRT2ToLCDA|SetCRT2ToDualEdge; + } + } + } + } +*/ + + return( 1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SearchModeID */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_SearchModeID( USHORT ModeNo , USHORT *ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + +#ifdef TC + + if ( ModeNo <= 5 ) + ModeNo |= 1 ; + + if ( ModeNo <= 0x13 ) + { + /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->SModeIDTable)/sizeof(XGI_StStruct);(*ModeIdIndex)++) */ + for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ ) + { + if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == ModeNo ) + break ; + if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == 0xFF ) + return( FALSE ) ; + } + + VGA_INFO = ( PUCHAR )MK_FP( 0 , 0x489 ) ; + + if ( ModeNo == 0x07 ) + { + if ( ( *VGA_INFO & 0x10 ) != 0 ) + ( *ModeIdIndex )++ ; /* 400 lines */ + /* else 350 lines */ + } + + if ( ModeNo <= 3 ) + { + if ( ( *VGA_INFO & 0x80 ) == 0 ) + { + ( *ModeIdIndex )++ ; + if ( ( *VGA_INFO & 0x10 ) != 0 ) + ( *ModeIdIndex )++ ; /* 400 lines */ + /* else 350 lines */ + } + /* else 200 lines */ + } + } + else + { + /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->EModeIDTable)/sizeof(XGI_ExtStruct);(*ModeIdIndex)++) */ + for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ ) + { + if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == ModeNo ) + break ; + if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == 0xFF ) + return( FALSE ) ; + } + } + + +#endif + +#ifdef WIN2000 + + if ( ModeNo <= 5 ) + ModeNo |= 1 ; + if ( ModeNo <= 0x13 ) + { + /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->SModeIDTable)/sizeof(XGI_StStruct);(*ModeIdIndex)++) */ + for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ ) + { + if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == ModeNo ) + break ; + if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == 0xFF ) + return( FALSE ) ; + } + + if ( ModeNo == 0x07 ) + ( *ModeIdIndex )++ ; /* 400 lines */ + + if ( ModeNo <=3 ) + ( *ModeIdIndex ) += 2 ; /* 400 lines */ + /* else 350 lines */ + } + else + { + /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->EModeIDTable)/sizeof(XGI_ExtStruct);(*ModeIdIndex)++) */ + for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ ) + { + if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == ModeNo ) + break ; + if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == 0xFF ) + return( FALSE ) ; + } + } + +#endif + +#ifdef LINUX /* chiawen for linux solution */ + + if ( ModeNo <= 5 ) + ModeNo |= 1 ; + if ( ModeNo <= 0x13 ) + { + /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->SModeIDTable)/sizeof(XGI_StStruct);(*ModeIdIndex)++) */ + for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ ) + { + if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == ModeNo ) + break ; + if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == 0xFF ) + return( FALSE ) ; + } + + if ( ModeNo == 0x07 ) + ( *ModeIdIndex )++ ; /* 400 lines */ + + if ( ModeNo <= 3 ) + ( *ModeIdIndex ) += 2 ; /* 400 lines */ + /* else 350 lines */ + } + else + { + /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->EModeIDTable)/sizeof(XGI_ExtStruct);(*ModeIdIndex)++) */ + for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ ) + { + if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == ModeNo ) + break ; + if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == 0xFF ) + return( FALSE ) ; + } + } + +#endif + + return( TRUE ) ; +} + + + + +/* win2000 MM adapter not support standard mode! */ + +/* --------------------------------------------------------------------- */ +/* Function : */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGINew_CheckMemorySize(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo) +{ + USHORT memorysize , + modeflag , + temp , + temp1 , + tmp ; + +/* if ( ( HwDeviceExtension->jChipType == XGI_650 ) || + ( HwDeviceExtension->jChipType == XGI_650M ) ) + { + return( TRUE ) ; + } */ + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + } + else { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + } + + /* ModeType = modeflag&ModeInfoFlag ; // Get mode type */ + + memorysize = modeflag & MemoryInfoFlag ; + memorysize = memorysize > MemorySizeShift ; + memorysize++ ; /* Get memory size */ + + temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ; /* Get DRAM Size */ + tmp = temp ; + + if ( HwDeviceExtension->jChipType == XG40 ) + { + temp = 1 << ( ( temp & 0x0F0 ) >> 4 ) ; /* memory size per channel SR14[7:4] */ + if ( ( tmp & 0x0c ) == 0x0C ) /* Qual channels */ + { + temp <<= 2 ; + } + else if ( ( tmp & 0x0c ) == 0x08 ) /* Dual channels */ + { + temp <<= 1 ; + } + } + else if ( HwDeviceExtension->jChipType == XG42 ) + { + temp = 1 << ( ( temp & 0x0F0 ) >> 4 ) ; /* memory size per channel SR14[7:4] */ + if ( ( tmp & 0x04 ) == 0x04 ) /* Dual channels */ + { + temp <<= 1 ; + } + } + else if ( HwDeviceExtension->jChipType == XG45 ) + { + temp = 1 << ( ( temp & 0x0F0 ) >> 4 ) ; /* memory size per channel SR14[7:4] */ + if ( ( tmp & 0x0c ) == 0x0C ) /* Qual channels */ + { + temp <<= 2 ; + } + else if ( ( tmp & 0x0c ) == 0x08 ) /* triple channels */ + { + temp1 = temp ; + temp <<= 1 ; + temp += temp1 ; + } + else if ( ( tmp & 0x0c ) == 0x04 ) /* Dual channels */ + { + temp <<= 1 ; + } + } + if ( temp < memorysize ) + return( FALSE ) ; + else + return( TRUE ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_IsLowResolution */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +/*void XGINew_IsLowResolution( USHORT ModeNo , USHORT ModeIdIndex, BOOLEAN XGINew_CheckMemorySize(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo) +{ + USHORT data ; + USHORT ModeFlag ; + + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x0F ) ; + data &= 0x7F ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x0F , data ) ; + + if ( ModeNo > 0x13 ) + { + ModeFlag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + if ( ( ModeFlag & HalfDCLK ) && ( ModeFlag & DoubleScanMode ) ) + { + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x0F ) ; + data |= 0x80 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x0F , data ) ; + data = XGINew_GetReg1( pVBInfo->P3c4 , 0x01 ) ; + data &= 0xF7 ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , data ) ; + } + } +} + +*/ + +/* --------------------------------------------------------------------- */ +/* Function : XGI_DisplayOn */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_DisplayOn( PXGI_HW_DEVICE_INFO pXGIHWDE , PVB_DEVICE_INFO pVBInfo ) +{ + + XGINew_SetRegANDOR(pVBInfo->P3c4,0x01,0xDF,0x00); + if ( pXGIHWDE->jChipType == XG21 ) + { + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + if (!(XGI_XG21GetPSCValue( pVBInfo )&0x1)) + { + XGI_XG21BLSignalVDD( 0x01 , 0x01, pVBInfo ) ; /* LVDS VDD on */ + XGI_XG21SetPanelDelay( 2,pVBInfo ) ; + } + if (!(XGI_XG21GetPSCValue( pVBInfo )&0x20)) + { + XGI_XG21BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* LVDS signal on */ + } + XGI_XG21SetPanelDelay( 3,pVBInfo ) ; + XGI_XG21BLSignalVDD( 0x02 , 0x02, pVBInfo ) ; /* LVDS backlight on */ + } + else + { + XGI_XG21BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* DVO/DVI signal on */ + } + + } + + if (pVBInfo->IF_DEF_CH7007 == 1) /* [Billy] 07/05/23 For CH7007 */ + { +#ifdef WIN2000 + if ( IsCH7007TVMode( pVBInfo ) ) + { + TurnOnCH7007(pXGIHWDE->pDevice) ; /* 07/05/28 */ + } +#endif + + } + + + if ( pXGIHWDE->jChipType == XG27 ) + { + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + if (!(XGI_XG27GetPSCValue( pVBInfo )&0x1)) + { + XGI_XG27BLSignalVDD( 0x01 , 0x01, pVBInfo ) ; /* LVDS VDD on */ + XGI_XG21SetPanelDelay( 2,pVBInfo ) ; + } + if (!(XGI_XG27GetPSCValue( pVBInfo )&0x20)) + { + XGI_XG27BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* LVDS signal on */ + } + XGI_XG21SetPanelDelay( 3,pVBInfo ) ; + XGI_XG27BLSignalVDD( 0x02 , 0x02, pVBInfo ) ; /* LVDS backlight on */ + } + else + { + XGI_XG27BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* DVO/DVI signal on */ + } + + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_DisplayOff */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_DisplayOff( PXGI_HW_DEVICE_INFO pXGIHWDE , PVB_DEVICE_INFO pVBInfo ) +{ + + if ( pXGIHWDE->jChipType == XG21 ) + { + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + XGI_XG21BLSignalVDD( 0x02 , 0x00, pVBInfo ) ; /* LVDS backlight off */ + XGI_XG21SetPanelDelay( 3,pVBInfo ) ; + } + else + { + XGI_XG21BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* DVO/DVI signal off */ + } + } + + if (pVBInfo->IF_DEF_CH7007 == 1) /*[Billy] 07/05/23 For CH7007 */ + { + /* if( IsCH7007TVMode( pVBInfo ) == 0 ) */ + { +#ifdef WIN2000 + TurnOffCH7007(pXGIHWDE->pDevice) ; /* 07/05/28 */ +#endif + } + } + + + if ( pXGIHWDE->jChipType == XG27 ) + { + if ((XGI_XG27GetPSCValue( pVBInfo )&0x2)) + { + XGI_XG27BLSignalVDD( 0x02 , 0x00, pVBInfo ) ; /* LVDS backlight off */ + XGI_XG21SetPanelDelay( 3,pVBInfo ) ; + } + + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + XGI_XG27BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* DVO/DVI signal off */ + } + } + + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x01 , 0xDF , 0x20 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_WaitDisply */ +/* Input : */ +/* Output : */ +/* Description : chiawen for sensecrt1 */ +/* --------------------------------------------------------------------- */ +void XGI_WaitDisply( PVB_DEVICE_INFO pVBInfo ) +{ + while( ( XGINew_GetReg2( pVBInfo->P3da ) & 0x01 ) ) + break ; + + while( !( XGINew_GetReg2( pVBInfo->P3da ) & 0x01 ) ) + break ; +} + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SenseCRT1 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ + +void XGI_SenseCRT1( PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR CRTCData[ 17 ] = { 0x5F , 0x4F , 0x50 , 0x82 , 0x55 , 0x81 , + 0x0B , 0x3E , 0xE9 , 0x0B , 0xDF , 0xE7 , + 0x04 , 0x00 , 0x00 , 0x05 , 0x00 } ; + + UCHAR SR01 = 0 , SR1F = 0 , SR07 = 0 , SR06 = 0 ; + + UCHAR CR17 , CR63 , SR31 ; + USHORT temp ; + UCHAR DAC_TEST_PARMS[ 3 ] = { 0x0F , 0x0F , 0x0F } ; + + int i ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ; + + /* [2004/05/06] Vicent to fix XG42 single LCD sense to CRT+LCD */ + XGINew_SetReg1( pVBInfo->P3d4 , 0x57 , 0x4A ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x53 , ( UCHAR )( XGINew_GetReg1( pVBInfo->P3d4 , 0x53 ) | 0x02 ) ) ; + + SR31 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x31 ) ; + CR63 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x63 ) ; + SR01 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x01 ) ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , ( UCHAR )( SR01 & 0xDF ) ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x63 , ( UCHAR )( CR63 & 0xBF ) ) ; + + CR17 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x17 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x17 , ( UCHAR )( CR17 | 0x80 ) ) ; + + SR1F = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x1F ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x1F , ( UCHAR )( SR1F | 0x04 ) ) ; + + SR07 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x07 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x07 , ( UCHAR )( SR07 & 0xFB ) ) ; + SR06 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x06 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x06 , ( UCHAR )( SR06 & 0xC3 ) ) ; + + XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , 0x00 ) ; + + for( i = 0 ; i < 8 ; i++ ) + XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )i , CRTCData[ i ] ) ; + + for( i = 8 ; i < 11 ; i++ ) + XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 8 ) , CRTCData[ i ] ) ; + + for( i = 11 ; i < 13 ; i++ ) + XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 4 ) , CRTCData[ i ] ) ; + + for( i = 13 ; i < 16 ; i++ ) + XGINew_SetReg1( pVBInfo->P3c4 , ( USHORT )( i - 3 ) , CRTCData[ i ] ) ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x0E , ( UCHAR )( CRTCData[ 16 ] & 0xE0 ) ) ; + + XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , 0x00 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , 0x1B ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , 0xE1 ) ; + + XGINew_SetReg3( pVBInfo->P3c8 , 0x00 ) ; + + for( i = 0 ; i < 256 ; i++ ) + { + XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , ( UCHAR )DAC_TEST_PARMS[ 0 ] ) ; + XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , ( UCHAR )DAC_TEST_PARMS[ 1 ] ) ; + XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , ( UCHAR )DAC_TEST_PARMS[ 2 ] ) ; + } + + XGI_VBLongWait( pVBInfo ) ; + XGI_VBLongWait( pVBInfo ) ; + XGI_VBLongWait( pVBInfo ) ; + + XGINew_LCD_Wait_Time( 0x01 , pVBInfo ) ; + + XGI_WaitDisply( pVBInfo ) ; + temp = XGINew_GetReg2( pVBInfo->P3c2 ) ; + + if( temp & 0x10 ) + { + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , 0xDF , 0x20 ) ; + } + else + { + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , 0xDF , 0x00 ) ; + } + + /* alan, avoid display something, set BLACK DAC if not restore DAC */ + XGINew_SetReg3( pVBInfo->P3c8 , 0x00 ) ; + + for( i = 0 ; i < 256 ; i++ ) + { + XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , 0 ) ; + XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , 0 ) ; + XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , 0 ) ; + } + + XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , SR01 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x63 , CR63 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , SR31 ) ; + + /* [2004/05/11] Vicent */ + XGINew_SetReg1( pVBInfo->P3d4 , 0x53 , ( UCHAR )( XGINew_GetReg1( pVBInfo->P3d4 , 0x53 ) & 0xFD ) ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x1F , ( UCHAR ) SR1F ) ; +} + + + + + +#ifdef TC +/* --------------------------------------------------------------------- */ +/* Function : INT1AReturnCode */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +int INT1AReturnCode( union REGS regs ) +{ + if ( regs.x.cflag ) + { + /* printf( "Error to find pci device!\n" ) ; */ + return( 1 ) ; + } + + switch(regs.h.ah) + { + case 0: return 0; + break ; + case 0x81: + printf( "Function not support\n" ) ; + break ; + case 0x83: + printf( "bad vendor id\n" ) ; + break ; + case 0x86: + printf( "device not found\n" ) ; + break ; + case 0x87: + printf( "bad register number\n" ) ; + break ; + case 0x88: + printf( "set failed\n" ) ; + break ; + case 0x89: + printf( "buffer too small" ) ; + break ; + default: + break ; + } + return( 1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : FindPCIIOBase */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +unsigned FindPCIIOBase( unsigned index , unsigned deviceid ) +{ + union REGS regs ; + + regs.h.ah = 0xb1 ; /* PCI_FUNCTION_ID */ + regs.h.al = 0x02 ; /* FIND_PCI_DEVICE */ + regs.x.cx = deviceid ; + regs.x.dx = 0x1039 ; + regs.x.si = index ; /* find n-th device */ + + int86( 0x1A , ®s , ®s ) ; + + if ( INT1AReturnCode( regs ) != 0 ) + return( 0 ) ; + + /* regs.h.bh bus number */ + /* regs.h.bl device number */ + regs.h.ah = 0xb1 ; /* PCI_FUNCTION_ID */ + regs.h.al = 0x09 ; /* READ_CONFIG_WORD */ + regs.x.cx = deviceid ; + regs.x.dx = 0x1039 ; + regs.x.di = 0x18 ; /* register number */ + int86( 0x1A , ®s , ®s ) ; + + if ( INT1AReturnCode( regs ) != 0 ) + return( 0 ) ; + + return( regs.x.cx ) ; +} + +#endif + + + +#ifdef TC +/* --------------------------------------------------------------------- */ +/* Function : main */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void main(int argc, char *argv[]) +{ + XGI_HW_DEVICE_INFO HwDeviceExtension ; + USHORT temp ; + USHORT ModeNo ; + + /* HwDeviceExtension.pjVirtualRomBase =(PUCHAR) MK_FP(0xC000,0); */ + /* HwDeviceExtension.pjVideoMemoryAddress = (PUCHAR)MK_FP(0xA000,0); */ + + + HwDeviceExtension.pjIOAddress = ( FindPCIIOBase( 0 ,0x6300 ) & 0xFF80 ) + 0x30 ; + HwDeviceExtension.jChipType = XGI_340 ; + + + + /* HwDeviceExtension.pjIOAddress = ( FindPCIIOBase( 0 , 0x5315 ) & 0xFF80 ) + 0x30 ; */ + + HwDeviceExtension.pjIOAddress = ( FindPCIIOBase( 0 , 0x330 ) & 0xFF80 ) + 0x30 ; + HwDeviceExtension.jChipType = XGI_340 ; + + + HwDeviceExtension.ujVBChipID = VB_CHIP_301 ; + StrCpy(HwDeviceExtension.szVBIOSVer , "0.84" ) ; + HwDeviceExtension.bSkipDramSizing = FALSE ; + HwDeviceExtension.ulVideoMemorySize = 0 ; + + if ( argc == 2 ) + { + ModeNo = atoi( argv[ 1 ] ) ; + } + else + { + ModeNo = 0x2e ; + /* ModeNo = 0x37 ; 1024x768x 4bpp */ + /* ModeNo = 0x38 ; 1024x768x 8bpp */ + /* ModeNo = 0x4A ; 1024x768x 16bpp */ + /* ModeNo = 0x47 ; 800x600x 16bpp */ + } + + /* XGIInitNew( &HwDeviceExtension ) ; */ + XGISetModeNew( &HwDeviceExtension , ModeNo ) ; +} +#endif + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_WaitDisplay */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_WaitDisplay( PVB_DEVICE_INFO pVBInfo ) +{ + while( !( XGINew_GetReg2( pVBInfo->P3da ) & 0x01 ) ) ; + + while( XGINew_GetReg2( pVBInfo->P3da ) & 0x01 ) ; +} + + + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT2Group301 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_SetCRT2Group301( USHORT ModeNo , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempbx , + ModeIdIndex , + RefreshRateTableIndex ; + + tempbx=pVBInfo->VBInfo ; + pVBInfo->SetFlag |= ProgrammingCRT2 ; + XGI_SearchModeID( ModeNo , &ModeIdIndex, pVBInfo ) ; + pVBInfo->SelectCRT2Rate = 4 ; + RefreshRateTableIndex = XGI_GetRatePtrCRT2( HwDeviceExtension, ModeNo , ModeIdIndex, pVBInfo ) ; + XGI_SaveCRT2Info( ModeNo, pVBInfo ) ; + XGI_GetCRT2ResInfo( ModeNo , ModeIdIndex, pVBInfo) ; + XGI_GetCRT2Data( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + XGI_PreSetGroup1( ModeNo , ModeIdIndex , HwDeviceExtension , RefreshRateTableIndex, pVBInfo ) ; + XGI_SetGroup1( ModeNo , ModeIdIndex , HwDeviceExtension , RefreshRateTableIndex, pVBInfo ) ; + XGI_SetLockRegs( ModeNo , ModeIdIndex , HwDeviceExtension , RefreshRateTableIndex, pVBInfo ) ; + XGI_SetGroup2( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ; + XGI_SetLCDRegs(ModeNo , ModeIdIndex , HwDeviceExtension , RefreshRateTableIndex, pVBInfo ) ; + XGI_SetTap4Regs(pVBInfo) ; + XGI_SetGroup3(ModeNo, ModeIdIndex, pVBInfo); + XGI_SetGroup4( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ; + XGI_SetCRT2VCLK( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + XGI_SetGroup5( ModeNo , ModeIdIndex, pVBInfo) ; + XGI_AutoThreshold( pVBInfo) ; + return 1 ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_AutoThreshold */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_AutoThreshold( PVB_DEVICE_INFO pVBInfo ) +{ + if ( !( pVBInfo->SetFlag & Win9xDOSMode ) ) + XGINew_SetRegOR( pVBInfo->Part1Port , 0x01 , 0x40 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SaveCRT2Info */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SaveCRT2Info( USHORT ModeNo , PVB_DEVICE_INFO pVBInfo) +{ + USHORT temp1 , + temp2 ; + + XGINew_SetReg1( pVBInfo->P3d4 , 0x34 , ModeNo ) ; /* reserve CR34 for CRT1 Mode No */ + temp1 = ( pVBInfo->VBInfo&SetInSlaveMode ) >> 8 ; + temp2 = ~( SetInSlaveMode >> 8 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x31 , temp2 , temp1 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetCRT2ResInfo */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetCRT2ResInfo( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT xres , + yres , + modeflag , + resindex ; + + resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo) ; + if ( ModeNo <= 0x13 ) + { + xres = pVBInfo->StResInfo[ resindex ].HTotal ; + yres = pVBInfo->StResInfo[ resindex ].VTotal ; + /* modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; si+St_ResInfo */ + } + else + { + xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */ + yres = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */ + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex].Ext_ModeFlag ; /* si+St_ModeFlag */ + +/* if ( pVBInfo->IF_DEF_FSTN ) + { + xres *= 2 ; + yres *= 2 ; + } + else + { +*/ + if ( modeflag & HalfDCLK ) + xres *= 2; + + if ( modeflag & DoubleScanMode ) + yres *= 2 ; +/* } */ + } + + if ( pVBInfo->VBInfo & SetCRT2ToLCD ) + { + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + if ( pVBInfo->LCDResInfo == Panel1600x1200 ) + { + if ( !( pVBInfo->LCDInfo & LCDVESATiming ) ) + { + if ( yres == 1024 ) + yres = 1056 ; + } + } + + if ( pVBInfo->LCDResInfo == Panel1280x1024 ) + { + if ( yres == 400 ) + yres = 405 ; + else if ( yres == 350 ) + yres = 360 ; + + if ( pVBInfo->LCDInfo & LCDVESATiming ) + { + if ( yres == 360 ) + yres = 375 ; + } + } + + if ( pVBInfo->LCDResInfo == Panel1024x768 ) + { + if ( !( pVBInfo->LCDInfo & LCDVESATiming ) ) + { + if ( !( pVBInfo->LCDInfo & LCDNonExpanding ) ) + { + if ( yres == 350 ) + yres = 357 ; + else if ( yres == 400 ) + yres = 420 ; + else if ( yres == 480 ) + yres = 525 ; + } + } + } + } + + if ( xres == 720 ) + xres = 640 ; + } + + pVBInfo->VGAHDE = xres ; + pVBInfo->HDE = xres ; + pVBInfo->VGAVDE = yres ; + pVBInfo->VDE = yres ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_IsLCDDualLink */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_IsLCDDualLink( PVB_DEVICE_INFO pVBInfo ) +{ + + if ( ( ( ( pVBInfo->VBInfo & SetCRT2ToLCD ) | SetCRT2ToLCDA ) ) && ( pVBInfo->LCDInfo & SetLCDDualLink ) ) /* shampoo0129 */ + return ( 1 ) ; + + return( 0 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetCRT2Data */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetCRT2Data( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempax = 0, + tempbx , + modeflag , + resinfo ; + + XGI_LCDDataStruct *LCDPtr = NULL ; + XGI_TVDataStruct *TVPtr = NULL ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */ + resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */ + resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; + } + + pVBInfo->NewFlickerMode = 0 ; + pVBInfo->RVBHRS = 50 ; + + if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) + { + XGI_GetRAMDAC2DATA( ModeNo , ModeIdIndex , RefreshRateTableIndex,pVBInfo ) ; + return ; + } + + tempbx = 4 ; + + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + LCDPtr = (XGI_LCDDataStruct* )XGI_GetLcdPtr( tempbx, ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + + pVBInfo->RVBHCMAX = LCDPtr->RVBHCMAX ; + pVBInfo->RVBHCFACT = LCDPtr->RVBHCFACT ; + pVBInfo->VGAHT = LCDPtr->VGAHT ; + pVBInfo->VGAVT = LCDPtr->VGAVT ; + pVBInfo->HT = LCDPtr->LCDHT ; + pVBInfo->VT = LCDPtr->LCDVT ; + + if ( pVBInfo->LCDResInfo == Panel1024x768 ) + { + tempax = 1024 ; + tempbx = 768 ; + + if ( !( pVBInfo->LCDInfo & LCDVESATiming ) ) + { + if ( pVBInfo->VGAVDE == 357 ) + tempbx = 527 ; + else if ( pVBInfo->VGAVDE == 420 ) + tempbx = 620 ; + else if ( pVBInfo->VGAVDE == 525 ) + tempbx = 775 ; + else if ( pVBInfo->VGAVDE == 600 ) + tempbx = 775 ; + /* else if(pVBInfo->VGAVDE==350) tempbx=560; */ + /* else if(pVBInfo->VGAVDE==400) tempbx=640; */ + else + tempbx = 768 ; + } + else + tempbx = 768 ; + } + else if ( pVBInfo->LCDResInfo == Panel1024x768x75 ) + { + tempax = 1024 ; + tempbx = 768 ; + } + else if ( pVBInfo->LCDResInfo == Panel1280x1024 ) + { + tempax = 1280 ; + if ( pVBInfo->VGAVDE == 360 ) + tempbx = 768 ; + else if ( pVBInfo->VGAVDE == 375 ) + tempbx = 800 ; + else if ( pVBInfo->VGAVDE == 405 ) + tempbx = 864 ; + else + tempbx = 1024 ; + } + else if ( pVBInfo->LCDResInfo == Panel1280x1024x75 ) + { + tempax = 1280 ; + tempbx = 1024 ; + } + else if ( pVBInfo->LCDResInfo == Panel1280x960 ) + { + tempax = 1280 ; + if ( pVBInfo->VGAVDE == 350 ) + tempbx = 700 ; + else if ( pVBInfo->VGAVDE == 400 ) + tempbx = 800 ; + else if ( pVBInfo->VGAVDE == 1024 ) + tempbx = 960 ; + else + tempbx = 960 ; + } + else if ( pVBInfo->LCDResInfo == Panel1400x1050 ) + { + tempax = 1400 ; + tempbx = 1050 ; + + if ( pVBInfo->VGAVDE == 1024 ) + { + tempax = 1280 ; + tempbx = 1024 ; + } + } + else if ( pVBInfo->LCDResInfo == Panel1600x1200 ) + { + tempax = 1600 ; + tempbx = 1200 ; /* alan 10/14/2003 */ + if ( !( pVBInfo->LCDInfo & LCDVESATiming ) ) + { + if ( pVBInfo->VGAVDE == 350 ) + tempbx = 875 ; + else if ( pVBInfo->VGAVDE == 400 ) + tempbx = 1000 ; + } + } + + if ( pVBInfo->LCDInfo & LCDNonExpanding ) + { + tempax = pVBInfo->VGAHDE ; + tempbx = pVBInfo->VGAVDE ; + } + + pVBInfo->HDE = tempax ; + pVBInfo->VDE = tempbx ; + return ; + } + + if ( pVBInfo->VBInfo & ( SetCRT2ToTV ) ) + { + tempbx = 4 ; + TVPtr = ( XGI_TVDataStruct * )XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + + pVBInfo->RVBHCMAX = TVPtr->RVBHCMAX ; + pVBInfo->RVBHCFACT = TVPtr->RVBHCFACT ; + pVBInfo->VGAHT = TVPtr->VGAHT ; + pVBInfo->VGAVT = TVPtr->VGAVT ; + pVBInfo->HDE = TVPtr->TVHDE ; + pVBInfo->VDE = TVPtr->TVVDE ; + pVBInfo->RVBHRS = TVPtr->RVBHRS ; + pVBInfo->NewFlickerMode = TVPtr->FlickerMode ; + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + if ( resinfo == 0x08 ) + pVBInfo->NewFlickerMode = 0x40 ; + else if ( resinfo == 0x09 ) + pVBInfo->NewFlickerMode = 0x40 ; + else if ( resinfo == 0x12 ) + pVBInfo->NewFlickerMode = 0x40 ; + + if ( pVBInfo->VGAVDE == 350 ) + pVBInfo->TVInfo |= TVSimuMode ; + + tempax = ExtHiTVHT ; + tempbx = ExtHiTVVT ; + + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( pVBInfo->TVInfo & TVSimuMode ) + { + tempax = StHiTVHT ; + tempbx = StHiTVVT ; + + if ( !( modeflag & Charx8Dot ) ) + { + tempax = StHiTextTVHT ; + tempbx = StHiTextTVVT ; + } + } + } + } + else if ( pVBInfo->VBInfo & SetCRT2ToYPbPr ) + { + if ( pVBInfo->TVInfo & SetYPbPrMode750p ) + { + tempax = YPbPrTV750pHT ; /* Ext750pTVHT */ + tempbx = YPbPrTV750pVT ; /* Ext750pTVVT */ + } + + if ( pVBInfo->TVInfo & SetYPbPrMode525p ) + { + tempax = YPbPrTV525pHT ; /* Ext525pTVHT */ + tempbx = YPbPrTV525pVT ; /* Ext525pTVVT */ + } + else if ( pVBInfo->TVInfo & SetYPbPrMode525i ) + { + tempax = YPbPrTV525iHT ; /* Ext525iTVHT */ + tempbx = YPbPrTV525iVT ; /* Ext525iTVVT */ + if ( pVBInfo->TVInfo & NTSC1024x768 ) + tempax = NTSC1024x768HT ; + } + } + else + { + tempax = PALHT ; + tempbx = PALVT ; + if ( !( pVBInfo->TVInfo & SetPALTV ) ) + { + tempax = NTSCHT ; + tempbx = NTSCVT ; + if ( pVBInfo->TVInfo & NTSC1024x768 ) + tempax = NTSC1024x768HT ; + } + } + + pVBInfo->HT = tempax ; + pVBInfo->VT = tempbx ; + return ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT2VCLK */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT2VCLK( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR di_0 , + di_1 , + tempal ; + + tempal = XGI_GetVCLKPtr( RefreshRateTableIndex , ModeNo , ModeIdIndex, pVBInfo ) ; + XGI_GetVCLKLen( tempal, &di_0 , &di_1, pVBInfo ) ; + XGI_GetLCDVCLKPtr( &di_0 , &di_1, pVBInfo ) ; + + if ( pVBInfo->VBType & VB_XGI301 ) /* shampoo 0129 */ + { /* 301 */ + XGINew_SetReg1(pVBInfo->Part4Port , 0x0A , 0x10 ) ; + XGINew_SetReg1(pVBInfo->Part4Port , 0x0B , di_1 ) ; + XGINew_SetReg1(pVBInfo->Part4Port , 0x0A , di_0 ) ; + } + else + { /* 301b/302b/301lv/302lv */ + XGINew_SetReg1( pVBInfo->Part4Port , 0x0A , di_0 ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x0B , di_1 ) ; + } + + XGINew_SetReg1( pVBInfo->Part4Port , 0x00 , 0x12 ) ; + + if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) + XGINew_SetRegOR( pVBInfo->Part4Port , 0x12 , 0x28 ) ; + else + XGINew_SetRegOR( pVBInfo->Part4Port , 0x12 , 0x08 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GETLCDVCLKPtr */ +/* Input : */ +/* Output : al -> VCLK Index */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetLCDVCLKPtr( UCHAR* di_0 , UCHAR *di_1, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT index ; + + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + if ( pVBInfo->IF_DEF_ScaleLCD == 1 ) + { + if ( pVBInfo->LCDInfo & EnableScalingLCD ) + return ; + } + + /* index = XGI_GetLCDCapPtr(pVBInfo) ; */ + index = XGI_GetLCDCapPtr1( pVBInfo) ; + + if ( pVBInfo->VBInfo & SetCRT2ToLCD ) + { /* LCDB */ + *di_0 = pVBInfo->LCDCapList[ index ].LCUCHAR_VCLKData1 ; + *di_1 = pVBInfo->LCDCapList[ index ].LCUCHAR_VCLKData2 ; + } + else + { /* LCDA */ + *di_0 = pVBInfo->LCDCapList[ index ].LCDA_VCLKData1 ; + *di_1 = pVBInfo->LCDCapList[ index ].LCDA_VCLKData2 ; + } + } + return ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetVCLKPtr */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +UCHAR XGI_GetVCLKPtr(USHORT RefreshRateTableIndex,USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo) +{ + + USHORT index , + modeflag ; +#ifndef LINUX_XF86 + USHORT tempbx ; +#endif + + UCHAR tempal ; + UCHAR *CHTVVCLKPtr = NULL ; + + if ( ModeNo <= 0x13 ) + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */ + else + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + + + if ( ( pVBInfo->SetFlag & ProgrammingCRT2 ) && ( !( pVBInfo->LCDInfo & EnableScalingLCD ) ) ) + { /* {LCDA/LCDB} */ + index = XGI_GetLCDCapPtr(pVBInfo) ; + tempal = pVBInfo->LCDCapList[ index ].LCD_VCLK ; + + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + return tempal ; + + /* {TV} */ + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV| VB_XGI302LV| VB_XGI301C ) ) + { + if(pVBInfo->VBInfo&SetCRT2ToHiVisionTV) + { + tempal = HiTVVCLKDIV2; + if(!(pVBInfo->TVInfo & RPLLDIV2XO)) + tempal = HiTVVCLK; + if(pVBInfo->TVInfo & TVSimuMode) + { + tempal = HiTVSimuVCLK; + if(!(modeflag & Charx8Dot)) + tempal = HiTVTextVCLK; + + } + return tempal; + } + + if ( pVBInfo->TVInfo & SetYPbPrMode750p ) + { + tempal = YPbPr750pVCLK ; + return tempal ; + } + + if ( pVBInfo->TVInfo & SetYPbPrMode525p ) + { + tempal = YPbPr525pVCLK ; + return tempal ; + } + + tempal = NTSC1024VCLK ; + + if ( !( pVBInfo->TVInfo & NTSC1024x768 ) ) + { + tempal = TVVCLKDIV2 ; + if ( !( pVBInfo->TVInfo & RPLLDIV2XO ) ) + tempal = TVVCLK ; + } + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + return tempal ; + } + /*else + if((pVBInfo->IF_DEF_CH7017==1)&&(pVBInfo->VBType&VB_CH7017)) + { + if(ModeNo<=0x13) + *tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC; + else + *tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + *tempal = *tempal & 0x1F; + + tempbx = 0; + if(pVBInfo->TVInfo & SetPALTV) + tempbx = tempbx + 2; + if(pVBInfo->TVInfo & SetCHTVOverScan) + tempbx++; + tempbx = tempbx << 1; + } */ + } /* {End of VB} */ + + if((pVBInfo->IF_DEF_CH7007==1)&&(pVBInfo->VBType&VB_CH7007)) /* [Billy] 07/05/08 CH7007 */ + { + /* VideoDebugPrint((0, "XGI_GetVCLKPtr: pVBInfo->IF_DEF_CH7007==1\n")); */ + if ( (pVBInfo->VBInfo & SetCRT2ToTV) ) + { + if( ModeNo <= 0x13 ) + { + tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ; + } + else + { + tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + tempal = tempal & 0x0F; + tempbx = 0; + + if(pVBInfo->TVInfo & SetPALTV) + { + tempbx = tempbx + 2; + } + if(pVBInfo->TVInfo & SetCHTVOverScan) + { + tempbx++; + } + /** tempbx = tempbx << 1; CH7007 ? **/ + +/*[Billy]07/05/29 CH7007*/ + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + switch( tempbx ) + { + case 0: + CHTVVCLKPtr = XGI7007_CHTVVCLKUNTSC ; + break ; + case 1: + CHTVVCLKPtr = XGI7007_CHTVVCLKONTSC ; + break ; + case 2: + CHTVVCLKPtr = XGI7007_CHTVVCLKUPAL ; + break ; + case 3: + CHTVVCLKPtr = XGI7007_CHTVVCLKOPAL ; + break ; + default: + break ; + + } + } + /*else + { + switch( tempbx ) + { + case 0: + CHTVVCLKPtr = pVBInfo->CHTVVCLKUNTSC ; + break ; + case 1: + CHTVVCLKPtr = pVBInfo->CHTVVCLKONTSC ; + break ; + case 2: + CHTVVCLKPtr = pVBInfo->CHTVVCLKUPAL ; + break ; + case 3: + CHTVVCLKPtr = pVBInfo->CHTVVCLKOPAL ; + break ; + default: + break ; + } + }*/ + + tempal = CHTVVCLKPtr[ tempal ] ; + return tempal ; + } + + } + + tempal = ( UCHAR )XGINew_GetReg2( ( pVBInfo->P3ca + 0x02 ) ) ; + tempal = tempal >> 2 ; + tempal &= 0x03 ; + + if ( ( pVBInfo->LCDInfo & EnableScalingLCD ) && ( modeflag & Charx8Dot ) ) /* for Dot8 Scaling LCD */ + tempal = tempal ^ tempal ; /* ; set to VCLK25MHz always */ + + if ( ModeNo <= 0x13 ) + return tempal ; + + tempal = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRTVCLK ; + return tempal ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetVCLKLen */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetVCLKLen(UCHAR tempal,UCHAR* di_0,UCHAR* di_1, PVB_DEVICE_INFO pVBInfo) +{ + if ( pVBInfo->IF_DEF_CH7007 == 1 ) /* [Billy] 2007/05/16 */ + { + /* VideoDebugPrint((0, "XGI_GetVCLKLen: pVBInfo->IF_DEF_CH7007==1\n")); */ + *di_0 = ( UCHAR )XGI_CH7007VCLKData[ tempal ].SR2B ; + *di_1 = ( UCHAR )XGI_CH7007VCLKData[ tempal ].SR2C ; + } + else if ( pVBInfo->VBType & ( VB_XGI301 | VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) && ( pVBInfo->SetFlag & ProgrammingCRT2 ) ) + { + *di_0 = ( UCHAR )XGI_VBVCLKData[ tempal ].SR2B ; + *di_1 = XGI_VBVCLKData[ tempal ].SR2C ; + } + } + else + { + *di_0 = XGI_VCLKData[ tempal ].SR2B ; + *di_1 = XGI_VCLKData[ tempal ].SR2C ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT2Offset */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT2Offset( USHORT ModeNo , + USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT offset ; + UCHAR temp ; + + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + return ; + } + + offset = XGI_GetOffset( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ; + temp = ( UCHAR )( offset & 0xFF ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , temp ) ; + temp =( UCHAR)( ( offset & 0xFF00 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x09 , temp ) ; + temp =( UCHAR )( ( ( offset >> 3 ) & 0xFF ) + 1 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x03 , temp ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetOffset */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGI_GetOffset(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo) +{ + USHORT temp , + colordepth , + modeinfo , + index , + infoflag , + ColorDepth[] = { 0x01 , 0x02 , 0x04 } ; + + modeinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeInfo ; + if ( ModeNo <= 0x14 ) + infoflag = 0 ; + else + infoflag = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ; + + + index = ( modeinfo >> 8 ) & 0xFF ; + + temp = pVBInfo->ScreenOffset[ index ] ; + + if ( infoflag & InterlaceMode ) + { + temp = temp << 1 ; + } + + colordepth = XGI_GetColorDepth( ModeNo , ModeIdIndex, pVBInfo ) ; + + if ( ( ModeNo >= 0x7C ) && ( ModeNo <= 0x7E ) ) + { + temp = ModeNo - 0x7C ; + colordepth = ColorDepth[ temp ] ; + temp = 0x6B ; + if ( infoflag & InterlaceMode ) + { + temp = temp << 1 ; + } + return( temp * colordepth ) ; + } + else + return( temp * colordepth ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT2FIFO */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT2FIFO( PVB_DEVICE_INFO pVBInfo) +{ + XGINew_SetReg1( pVBInfo->Part1Port , 0x01 , 0x3B ) ; /* threshold high ,disable auto threshold */ + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x02 , ~( 0x3F ) , 0x04 ) ; /* threshold low default 04h */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_PreSetGroup1 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_PreSetGroup1(USHORT ModeNo , USHORT ModeIdIndex ,PXGI_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempcx = 0 , + CRT1Index = 0 , + resinfo = 0 ; + + if ( ModeNo > 0x13 ) + { + CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ; + CRT1Index &= IndexMask ; + resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; + } + + XGI_SetCRT2Offset( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ; + XGI_SetCRT2FIFO(pVBInfo) ; + /* XGI_SetCRT2Sync(ModeNo,RefreshRateTableIndex); */ + + for( tempcx = 4 ; tempcx < 7 ; tempcx++ ) + { + XGINew_SetReg1( pVBInfo->Part1Port , tempcx , 0x0 ) ; + } + + XGINew_SetReg1( pVBInfo->Part1Port , 0x50 , 0x00 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x02 , 0x44 ) ; /* temp 0206 */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetGroup1 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetGroup1( USHORT ModeNo , USHORT ModeIdIndex , + PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT temp = 0 , + tempax = 0 , + tempbx = 0 , + tempcx = 0 , + pushbx = 0 , + CRT1Index = 0 , + modeflag , + resinfo = 0 ; + + if ( ModeNo > 0x13 ) + { + CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ; + CRT1Index &= IndexMask ; + resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; + } + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + } + + /* bainy change table name */ + if ( modeflag & HalfDCLK ) + { + temp = ( pVBInfo->VGAHT / 2 - 1 ) & 0x0FF ; /* BTVGA2HT 0x08,0x09 */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , temp ) ; + temp = ( ( ( pVBInfo->VGAHT / 2 - 1 ) & 0xFF00 ) >> 8 ) << 4 ; + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x09 , ~0x0F0 , temp ) ; + temp = ( pVBInfo->VGAHDE / 2 + 16 ) & 0x0FF ; /* BTVGA2HDEE 0x0A,0x0C */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x0A , temp ) ; + tempcx = ( ( pVBInfo->VGAHT - pVBInfo->VGAHDE ) / 2 ) >> 2 ; + pushbx = pVBInfo->VGAHDE / 2 + 16 ; + tempcx = tempcx >> 1 ; + tempbx = pushbx + tempcx ; /* bx BTVGA@HRS 0x0B,0x0C */ + tempcx += tempbx ; + + if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) + { + tempbx = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 4 ] ; + tempbx |= ( ( pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 14 ] & 0xC0 ) << 2 ) ; + tempbx = ( tempbx - 3 ) << 3 ; /* (VGAHRS-3)*8 */ + tempcx = pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[ 5 ] ; + tempcx &= 0x1F ; + temp = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 15 ] ; + temp = ( temp & 0x04 ) << ( 5 - 2 ) ; /* VGAHRE D[5] */ + tempcx = ( ( tempcx | temp ) - 3 ) << 3 ; /* (VGAHRE-3)*8 */ + } + + tempbx += 4 ; + tempcx += 4 ; + + if ( tempcx > ( pVBInfo->VGAHT / 2 ) ) + tempcx = pVBInfo->VGAHT / 2 ; + + temp = tempbx & 0x00FF ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x0B , temp ) ; + } + else + { + temp = ( pVBInfo->VGAHT - 1 ) & 0x0FF ; /* BTVGA2HT 0x08,0x09 */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , temp ) ; + temp = ( ( ( pVBInfo->VGAHT - 1 ) & 0xFF00 ) >> 8 ) << 4 ; + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x09 , ~0x0F0 , temp ) ; + temp = ( pVBInfo->VGAHDE + 16 ) & 0x0FF ; /* BTVGA2HDEE 0x0A,0x0C */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x0A , temp ) ; + tempcx = ( pVBInfo->VGAHT - pVBInfo->VGAHDE ) >> 2 ; /* cx */ + pushbx = pVBInfo->VGAHDE + 16 ; + tempcx = tempcx >> 1 ; + tempbx = pushbx + tempcx ; /* bx BTVGA@HRS 0x0B,0x0C */ + tempcx += tempbx ; + + if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) + { + tempbx = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 3 ] ; + tempbx |= ( ( pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 5 ] & 0xC0 ) << 2 ) ; + tempbx = ( tempbx - 3 ) << 3 ; /* (VGAHRS-3)*8 */ + tempcx = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 4 ] ; + tempcx &= 0x1F ; + temp = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 6 ] ; + temp = ( temp & 0x04 ) << ( 5 - 2 ) ; /* VGAHRE D[5] */ + tempcx = ( ( tempcx | temp ) - 3 ) << 3 ; /* (VGAHRE-3)*8 */ + tempbx += 16 ; + tempcx += 16 ; + } + + if ( tempcx > pVBInfo->VGAHT ) + tempcx = pVBInfo->VGAHT ; + + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0B , temp ) ; + } + + tempax = ( tempax & 0x00FF ) | ( tempbx & 0xFF00 ) ; + tempbx = pushbx ; + tempbx = ( tempbx & 0x00FF ) | ( ( tempbx & 0xFF00 ) << 4 ) ; + tempax |= ( tempbx & 0xFF00 ) ; + temp = ( tempax & 0xFF00 ) >> 8 ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0C , temp ) ; + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0D , temp ) ; + tempcx = ( pVBInfo->VGAVT - 1 ) ; + temp = tempcx & 0x00FF ; + + if ( pVBInfo->IF_DEF_CH7005 == 1 ) + { + if ( pVBInfo->VBInfo & 0x0C ) + { + temp-- ; + } + } + + XGINew_SetReg1( pVBInfo->Part1Port , 0x0E , temp ) ; + tempbx = pVBInfo->VGAVDE - 1 ; + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0F , temp ) ; + temp = ( ( tempbx & 0xFF00 ) << 3 ) >> 8 ; + temp |= ( ( tempcx & 0xFF00 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x12 , temp ) ; + + tempax = pVBInfo->VGAVDE ; + tempbx = pVBInfo->VGAVDE ; + tempcx = pVBInfo->VGAVT ; + tempbx = ( pVBInfo->VGAVT + pVBInfo->VGAVDE ) >> 1 ; /* BTVGA2VRS 0x10,0x11 */ + tempcx = ( ( pVBInfo->VGAVT - pVBInfo->VGAVDE ) >> 4 ) + tempbx + 1 ; /* BTVGA2VRE 0x11 */ + + if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) + { + tempbx = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 10 ] ; + temp = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 9 ] ; + + if ( temp & 0x04 ) + tempbx |= 0x0100 ; + + if ( temp & 0x080 ) + tempbx |= 0x0200 ; + + temp = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 14 ] ; + + if ( temp & 0x08 ) + tempbx |= 0x0400 ; + + temp = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 11 ] ; + tempcx = ( tempcx & 0xFF00 ) | ( temp & 0x00FF ) ; + } + + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x10 , temp ) ; + temp = ( ( tempbx & 0xFF00 ) >> 8 ) << 4 ; + temp = ( ( tempcx & 0x000F ) | ( temp ) ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x11 , temp ) ; + tempax = 0 ; + + if ( modeflag & DoubleScanMode ) + tempax |= 0x80 ; + + if ( modeflag & HalfDCLK ) + tempax |= 0x40 ; + + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2C , ~0x0C0 , tempax ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetLockRegs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetLockRegs( USHORT ModeNo , USHORT ModeIdIndex , + PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT push1 , + push2 , + tempax , + tempbx = 0 , + tempcx , + temp , + resinfo , + modeflag , + CRT1Index ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */ + resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */ + resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; + CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ; + CRT1Index &= IndexMask; + } + + if ( !( pVBInfo->VBInfo & SetInSlaveMode ) ) + { + return ; + } + + temp = 0xFF ; /* set MAX HT */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x03 , temp ) ; + /* if ( modeflag & Charx8Dot ) tempcx = 0x08 ; */ + /* else */ + tempcx=0x08; + + if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + modeflag |= Charx8Dot ; + + tempax = pVBInfo->VGAHDE ; /* 0x04 Horizontal Display End */ + + if ( modeflag & HalfDCLK ) + tempax = tempax >> 1 ; + + tempax = ( tempax / tempcx ) - 1 ; + tempbx |= ( ( tempax & 0x00FF ) << 8 ) ; + temp = tempax & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x04 , temp ) ; + + temp = ( tempbx & 0xFF00 ) >> 8 ; + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + if ( !( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) ) + temp += 2 ; + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + if ( pVBInfo->VBType & VB_XGI301LV ) + { + if ( pVBInfo->VBExtInfo == VB_YPbPr1080i ) + { + if ( resinfo == 7 ) + temp -= 2 ; + } + } + else + if ( resinfo == 7 ) + temp -= 2 ; + } + } + + XGINew_SetReg1( pVBInfo->Part1Port , 0x05 , temp ) ; /* 0x05 Horizontal Display Start */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x06 , 0x03 ) ; /* 0x06 Horizontal Blank end */ + + if ( !( pVBInfo->VBInfo & DisableCRT2Display ) ) + { /* 030226 bainy */ + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + tempax = pVBInfo->VGAHT ; + else + tempax = XGI_GetVGAHT2( pVBInfo) ; + } + + if ( tempax >= pVBInfo->VGAHT ) + { + tempax = pVBInfo->VGAHT ; + } + + if ( modeflag & HalfDCLK ) + { + tempax = tempax >> 1 ; + } + + tempax = ( tempax / tempcx ) - 5 ; + tempcx = tempax ; /* 20030401 0x07 horizontal Retrace Start */ + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + temp = ( tempbx & 0x00FF ) - 1 ; + if ( !( modeflag & HalfDCLK ) ) + { + temp -= 6 ; + if ( pVBInfo->TVInfo & TVSimuMode ) + { + temp -= 4 ; + if ( ModeNo > 0x13 ) + temp -= 10 ; + } + } + } + else + { + /* tempcx = tempbx & 0x00FF ; */ + tempbx = ( tempbx & 0xFF00 ) >> 8 ; + tempcx = ( tempcx + tempbx ) >> 1 ; + temp = ( tempcx & 0x00FF ) + 2 ; + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + temp -= 1 ; + if ( !( modeflag & HalfDCLK ) ) + { + if ( ( modeflag & Charx8Dot ) ) + { + temp += 4 ; + if ( pVBInfo->VGAHDE >= 800 ) + { + temp -= 6 ; + } + } + } + } + else + { + if ( !( modeflag & HalfDCLK ) ) + { + temp -= 4 ; + if ( pVBInfo->LCDResInfo != Panel1280x960 ) + { + if( pVBInfo->VGAHDE >= 800 ) + { + temp -= 7 ; + if ( pVBInfo->ModeType == ModeEGA ) + { + if ( pVBInfo->VGAVDE == 1024 ) + { + temp += 15 ; + if ( pVBInfo->LCDResInfo != Panel1280x1024 ) + { + temp += 7 ; + } + } + } + + if ( pVBInfo->VGAHDE >= 1280 ) + { + if ( pVBInfo->LCDResInfo != Panel1280x960 ) + { + if ( pVBInfo->LCDInfo & LCDNonExpanding ) + { + temp += 28 ; + } + } + } + } + } + } + } + } + + XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , temp ) ; /* 0x07 Horizontal Retrace Start */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0 ) ; /* 0x08 Horizontal Retrace End */ + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + if ( pVBInfo->TVInfo & TVSimuMode ) + { + if ( ( ModeNo == 0x06 ) || ( ModeNo == 0x10 ) || ( ModeNo == 0x11 ) || ( ModeNo == 0x13 ) || ( ModeNo == 0x0F ) ) + { + XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x5b ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x03 ) ; + } + + if ( ( ModeNo == 0x00 ) || ( ModeNo == 0x01 ) ) + { + if ( pVBInfo->TVInfo & SetNTSCTV ) + { + XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x2A ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x61 ) ; + } + else + { + XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x2A ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x41 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0C , 0xF0 ) ; + } + } + + if ( ( ModeNo == 0x02 ) || ( ModeNo == 0x03 ) || ( ModeNo == 0x07 ) ) + { + if ( pVBInfo->TVInfo & SetNTSCTV ) + { + XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x54 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x00 ) ; + } + else + { + XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x55 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x00 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0C , 0xF0 ) ; + } + } + + if ( ( ModeNo == 0x04 ) || ( ModeNo == 0x05 ) || ( ModeNo == 0x0D ) || ( ModeNo == 0x50 ) ) + { + if ( pVBInfo->TVInfo & SetNTSCTV ) + { + XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x30 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x03 ) ; + } + else + { + XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x2f ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x02 ) ; + } + } + } + } + + XGINew_SetReg1( pVBInfo->Part1Port , 0x18 , 0x03 ) ; /* 0x18 SR0B */ + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , 0xF0 , 0x00 ) ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x09 , 0xFF ) ; /* 0x09 Set Max VT */ + + tempbx = pVBInfo->VGAVT ; + push1 = tempbx ; + tempcx = 0x121 ; + tempbx = pVBInfo->VGAVDE ; /* 0x0E Virtical Display End */ + + if ( tempbx == 357 ) + tempbx = 350 ; + if ( tempbx == 360 ) + tempbx =350 ; + if ( tempbx == 375 ) + tempbx = 350 ; + if ( tempbx == 405 ) + tempbx = 400 ; + if ( tempbx == 525 ) + tempbx = 480 ; + + push2 = tempbx ; + + if ( pVBInfo->VBInfo & SetCRT2ToLCD ) + { + if ( pVBInfo->LCDResInfo == Panel1024x768 ) + { + if ( !( pVBInfo->LCDInfo & LCDVESATiming ) ) + { + if ( tempbx == 350 ) + tempbx += 5 ; + if ( tempbx == 480 ) + tempbx += 5 ; + } + } + } + tempbx-- ; + temp = tempbx & 0x00FF ; + tempbx-- ; + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x10 ,temp ) ; /* 0x10 vertical Blank Start */ + tempbx = push2 ; + tempbx-- ; + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0E , temp ) ; + + if ( tempbx & 0x0100 ) + { + tempcx |= 0x0002 ; + } + + tempax = 0x000B ; + + if ( modeflag & DoubleScanMode ) + { + tempax |= 0x08000 ; + } + + if ( tempbx & 0x0200 ) + { + tempcx |= 0x0040 ; + } + + temp = ( tempax & 0xFF00 ) >> 8 ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0B , temp ) ; + + if ( tempbx & 0x0400 ) + { + tempcx |= 0x0600 ; + } + + XGINew_SetReg1( pVBInfo->Part1Port , 0x11 , 0x00 ) ; /* 0x11 Vertival Blank End */ + + tempax = push1 ; + tempax -= tempbx ; /* 0x0C Vertical Retrace Start */ + tempax = tempax >> 2 ; + push1 = tempax ; /* push ax */ + + if ( resinfo != 0x09 ) + { + tempax = tempax << 1 ; + tempbx += tempax ; + } + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + if ( pVBInfo->VBType & VB_XGI301LV ) + { + if ( pVBInfo->TVInfo & SetYPbPrMode1080i ) + tempbx -= 10 ; + else + { + if ( pVBInfo->TVInfo & TVSimuMode ) + { + if ( pVBInfo->TVInfo & SetPALTV ) + { + if ( pVBInfo->VBType & VB_XGI301LV ) + { + if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p | SetYPbPrMode1080i ) ) ) + tempbx += 40 ; + } + else + tempbx += 40 ; + } + } + } + } + else + tempbx -= 10 ; + } + else + { + if ( pVBInfo->TVInfo & TVSimuMode ) + { + if ( pVBInfo->TVInfo & SetPALTV ) + { + if ( pVBInfo->VBType & VB_XGI301LV ) + { + if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p | SetYPbPrMode1080i ) ) ) + tempbx += 40 ; + } + else + tempbx += 40 ; + } + } + } + tempax = push1 ; + tempax = tempax >> 2 ; + tempax++ ; + tempax += tempbx ; + push1 = tempax ; /* push ax */ + + if ( ( pVBInfo->TVInfo & SetPALTV ) ) + { + if ( tempbx <= 513 ) + { + if ( tempax >= 513 ) + { + tempbx = 513 ; + } + } + } + + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0C , temp ) ; + tempbx-- ; + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x10 , temp ) ; + + if ( tempbx & 0x0100 ) + { + tempcx |= 0x0008 ; + } + + if ( tempbx & 0x0200 ) + { + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x0B , 0x0FF , 0x20 ) ; + } + + tempbx++ ; + + if ( tempbx & 0x0100 ) + { + tempcx |= 0x0004 ; + } + + if ( tempbx & 0x0200 ) + { + tempcx |= 0x0080 ; + } + + if ( tempbx & 0x0400 ) + { + tempcx |= 0x0C00 ; + } + + tempbx = push1 ; /* pop ax */ + temp = tempbx & 0x00FF ; + temp &= 0x0F ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0D , temp ) ; /* 0x0D vertical Retrace End */ + + if ( tempbx & 0x0010 ) + { + tempcx |= 0x2000 ; + } + + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x0A , temp ) ; /* 0x0A CR07 */ + temp = ( tempcx & 0x0FF00 ) >> 8 ; + XGINew_SetReg1( pVBInfo->Part1Port , 0x17 , temp ) ; /* 0x17 SR0A */ + tempax = modeflag ; + temp = ( tempax & 0xFF00 ) >> 8 ; + + temp = ( temp >> 1 ) & 0x09 ; + + if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + temp |= 0x01 ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x16 , temp ) ; /* 0x16 SR01 */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x0F , 0 ) ; /* 0x0F CR14 */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x12 , 0 ) ; /* 0x12 CR17 */ + + if ( pVBInfo->LCDInfo & LCDRGB18Bit ) + temp = 0x80 ; + else + temp = 0x00 ; + + XGINew_SetReg1( pVBInfo->Part1Port , 0x1A , temp ) ; /* 0x1A SR0E */ + + return ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetGroup2 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetGroup2( USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT i , + j , + tempax , + tempbx , + tempcx , + temp , + push1 , + push2 , + modeflag , + resinfo , + crt2crtc ; + UCHAR *TimingPoint ; + + ULONG longtemp , + tempeax , + tempebx , + temp2 , + tempecx ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */ + resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; + crt2crtc = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */ + resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; + crt2crtc = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC ; + } + + tempax = 0 ; + + if ( !( pVBInfo->VBInfo & SetCRT2ToAVIDEO ) ) + tempax |= 0x0800 ; + + if ( !( pVBInfo->VBInfo & SetCRT2ToSVIDEO ) ) + tempax |= 0x0400 ; + + if ( pVBInfo->VBInfo & SetCRT2ToSCART ) + tempax |= 0x0200 ; + + if ( !( pVBInfo->TVInfo & SetPALTV ) ) + tempax |= 0x1000 ; + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + tempax |= 0x0100 ; + + if ( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) + tempax &= 0xfe00 ; + + tempax = ( tempax & 0xff00 ) >> 8 ; + + XGINew_SetReg1( pVBInfo->Part2Port , 0x0 , tempax ) ; + TimingPoint = pVBInfo->NTSCTiming ; + + if ( pVBInfo->TVInfo & SetPALTV ) + { + TimingPoint = pVBInfo->PALTiming ; + } + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + TimingPoint = pVBInfo->HiTVExtTiming ; + + if ( pVBInfo->VBInfo & SetInSlaveMode ) + TimingPoint = pVBInfo->HiTVSt2Timing ; + + if ( pVBInfo->SetFlag & TVSimuMode ) + TimingPoint = pVBInfo->HiTVSt1Timing ; + + if ( !(modeflag & Charx8Dot) ) + TimingPoint = pVBInfo->HiTVTextTiming ; + } + + if ( pVBInfo->VBInfo & SetCRT2ToYPbPr ) + { + if ( pVBInfo->TVInfo & SetYPbPrMode525i ) + TimingPoint = pVBInfo->YPbPr525iTiming ; + + if ( pVBInfo->TVInfo & SetYPbPrMode525p ) + TimingPoint = pVBInfo->YPbPr525pTiming ; + + if ( pVBInfo->TVInfo & SetYPbPrMode750p ) + TimingPoint = pVBInfo->YPbPr750pTiming ; + } + + for( i = 0x01 , j = 0 ; i <= 0x2D ; i++ , j++ ) + { + XGINew_SetReg1( pVBInfo->Part2Port , i , TimingPoint[ j ] ) ; + } + + for( i = 0x39 ; i <= 0x45 ; i++ , j++ ) + { + XGINew_SetReg1( pVBInfo->Part2Port , i , TimingPoint[ j ] ) ; /* di->temp2[j] */ + } + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x3A , 0x1F , 0x00 ) ; + } + + temp = pVBInfo->NewFlickerMode ; + temp &= 0x80 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x0A , 0xFF , temp ) ; + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + tempax = 950 ; + + if ( pVBInfo->TVInfo & SetPALTV ) + tempax = 520 ; + else + tempax = 440 ; + + if ( pVBInfo->VDE <= tempax ) + { + tempax -= pVBInfo->VDE ; + tempax = tempax >> 2 ; + tempax = ( tempax & 0x00FF ) | ( ( tempax & 0x00FF ) << 8 ) ; + push1 = tempax ; + temp = ( tempax & 0xFF00 ) >> 8 ; + temp += ( USHORT )TimingPoint[ 0 ] ; + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( pVBInfo->VBInfo & ( SetCRT2ToAVIDEO | SetCRT2ToSVIDEO | SetCRT2ToSCART | SetCRT2ToYPbPr ) ) + { + tempcx=pVBInfo->VGAHDE; + if ( tempcx >= 1024 ) + { + temp = 0x17 ; /* NTSC */ + if ( pVBInfo->TVInfo & SetPALTV ) + temp = 0x19 ; /* PAL */ + } + } + } + + XGINew_SetReg1( pVBInfo->Part2Port , 0x01 , temp ) ; + tempax = push1 ; + temp = ( tempax & 0xFF00 ) >> 8 ; + temp += TimingPoint[ 1 ] ; + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( ( pVBInfo->VBInfo & ( SetCRT2ToAVIDEO | SetCRT2ToSVIDEO | SetCRT2ToSCART | SetCRT2ToYPbPr ) ) ) + { + tempcx = pVBInfo->VGAHDE ; + if ( tempcx >= 1024 ) + { + temp = 0x1D ; /* NTSC */ + if ( pVBInfo->TVInfo & SetPALTV ) + temp = 0x52 ; /* PAL */ + } + } + } + XGINew_SetReg1( pVBInfo->Part2Port , 0x02 , temp ) ; + } + + /* 301b */ + tempcx = pVBInfo->HT ; + + if ( XGI_IsLCDDualLink( pVBInfo ) ) + tempcx = tempcx >> 1 ; + + tempcx -= 2 ; + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x1B , temp ) ; + + temp = ( tempcx & 0xFF00 ) >> 8 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x1D , ~0x0F , temp ) ; + + tempcx = pVBInfo->HT >> 1 ; + push1 = tempcx ; /* push cx */ + tempcx += 7 ; + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + tempcx -= 4 ; + } + + temp = tempcx & 0x00FF ; + temp = temp << 4 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x22 , 0x0F , temp ) ; + + tempbx = TimingPoint[ j ] | ( ( TimingPoint[ j + 1 ] ) << 8 ) ; + tempbx += tempcx ; + push2 = tempbx ; + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x24 , temp ) ; + temp = ( tempbx & 0xFF00 ) >> 8 ; + temp = temp << 4 ; + XGINew_SetRegANDOR(pVBInfo->Part2Port,0x25,0x0F,temp); + + tempbx=push2; + tempbx=tempbx+8; + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + tempbx=tempbx-4; + tempcx=tempbx; + } + + temp = ( tempbx & 0x00FF ) << 4 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x29 , 0x0F , temp ) ; + + j += 2 ; + tempcx += ( TimingPoint[ j ] | ( ( TimingPoint[ j + 1 ] ) << 8 ) ) ; + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x27 , temp ) ; + temp = ( ( tempcx & 0xFF00 ) >> 8 ) << 4 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x28 , 0x0F , temp ) ; + + tempcx += 8 ; + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + tempcx -= 4 ; + } + + temp = tempcx & 0xFF ; + temp = temp << 4 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x2A , 0x0F , temp ) ; + + tempcx = push1 ; /* pop cx */ + j += 2 ; + temp = TimingPoint[ j ] | ( ( TimingPoint[ j + 1 ] ) << 8 ) ; + tempcx -= temp ; + temp = tempcx & 0x00FF ; + temp = temp << 4 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x2D , 0x0F ,temp ) ; + + tempcx -= 11 ; + + if ( !( pVBInfo->VBInfo & SetCRT2ToTV ) ) + { + tempax = XGI_GetVGAHT2( pVBInfo) ; + tempcx = tempax - 1 ; + } + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x2E , temp ) ; + + tempbx = pVBInfo->VDE ; + + if ( pVBInfo->VGAVDE == 360 ) + tempbx = 746 ; + if ( pVBInfo->VGAVDE == 375 ) + tempbx = 746 ; + if ( pVBInfo->VGAVDE == 405 ) + tempbx = 853 ; + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) ) + tempbx = tempbx >> 1 ; + } + else + tempbx = tempbx >> 1 ; + } + + tempbx -= 2 ; + temp = tempbx & 0x00FF ; + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + if ( pVBInfo->VBType & VB_XGI301LV ) + { + if ( pVBInfo->TVInfo & SetYPbPrMode1080i ) + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( ModeNo == 0x2f ) + temp += 1 ; + } + } + } + else + { + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( ModeNo == 0x2f ) + temp += 1 ; + } + } + } + + XGINew_SetReg1( pVBInfo->Part2Port , 0x2F , temp ) ; + + temp = ( tempcx & 0xFF00 ) >> 8 ; + temp |= ( ( tempbx & 0xFF00 ) >> 8 ) << 6 ; + + if ( !( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) ) + { + if ( pVBInfo->VBType & VB_XGI301LV ) + { + if ( pVBInfo->TVInfo & SetYPbPrMode1080i ) + { + temp |= 0x10 ; + + if ( !( pVBInfo->VBInfo & SetCRT2ToSVIDEO ) ) + temp |= 0x20 ; + } + } + else + { + temp |= 0x10 ; + if ( !( pVBInfo->VBInfo & SetCRT2ToSVIDEO ) ) + temp |= 0x20 ; + } + } + + XGINew_SetReg1( pVBInfo->Part2Port , 0x30 , temp ) ; + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) /* TV gatingno */ + { + tempbx = pVBInfo->VDE ; + tempcx = tempbx - 2 ; + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) ) + tempbx = tempbx >> 1 ; + } + + if ( pVBInfo->VBType & ( VB_XGI302LV | VB_XGI301C ) ) + { + temp=0; + if( tempcx & 0x0400 ) + temp |= 0x20 ; + + if ( tempbx & 0x0400 ) + temp |= 0x40 ; + + XGINew_SetReg1( pVBInfo->Part4Port , 0x10 , temp ) ; + } + + temp = ( ( ( tempbx - 3 ) & 0x0300 ) >> 8 ) << 5 ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x46 , temp ) ; + temp = ( tempbx - 3 ) & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x47 , temp ) ; + } + + tempbx = tempbx & 0x00FF ; + + if ( !( modeflag & HalfDCLK ) ) + { + tempcx = pVBInfo->VGAHDE ; + if ( tempcx >= pVBInfo->HDE ) + { + tempbx |= 0x2000 ; + tempax &= 0x00FF ; + } + } + + tempcx = 0x0101 ; + + if( pVBInfo->VBInfo & SetCRT2ToTV ) { /*301b*/ + if(pVBInfo->VGAHDE>=1024) + { + tempcx=0x1920; + if(pVBInfo->VGAHDE>=1280) + { + tempcx=0x1420; + tempbx=tempbx&0xDFFF; + } + } + } + + if ( !( tempbx & 0x2000 ) ) + { + if ( modeflag & HalfDCLK ) + { + tempcx = ( tempcx & 0xFF00 ) | ( ( tempcx & 0x00FF ) << 1 ) ; + } + + push1 = tempbx ; + tempeax = pVBInfo->VGAHDE ; + tempebx = ( tempcx & 0xFF00 ) >> 8 ; + longtemp = tempeax * tempebx ; + tempecx = tempcx & 0x00FF ; + longtemp = longtemp / tempecx ; + + /* 301b */ + tempecx = 8 * 1024 ; + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + tempecx = tempecx * 8 ; + } + + longtemp = longtemp * tempecx ; + tempecx = pVBInfo->HDE ; + temp2 = longtemp % tempecx ; + tempeax = longtemp / tempecx ; + if ( temp2 != 0 ) + { + tempeax += 1 ; + } + + tempax = ( USHORT )tempeax ; + + /* 301b */ + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + tempcx = ( ( tempax & 0xFF00 ) >> 5 ) >> 8 ; + } + /* end 301b */ + + tempbx = push1 ; + tempbx =( USHORT )( ( ( tempeax & 0x0000FF00 ) & 0x1F00 ) | ( tempbx & 0x00FF ) ) ; + tempax =( USHORT )( ( ( tempeax & 0x000000FF ) << 8 ) | ( tempax & 0x00FF ) ) ; + temp = ( tempax & 0xFF00 ) >> 8 ; + } + else + { + temp = ( tempax & 0x00FF ) >> 8 ; + } + + XGINew_SetReg1( pVBInfo->Part2Port , 0x44 , temp ) ; + temp = ( tempbx & 0xFF00 ) >> 8 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x45 , ~0x03F , temp ) ; + temp = tempcx & 0x00FF ; + + if ( tempbx & 0x2000 ) + temp = 0 ; + + if ( !( pVBInfo->VBInfo & SetCRT2ToLCD ) ) + temp |= 0x18 ; + + XGINew_SetRegANDOR(pVBInfo->Part2Port,0x46,~0x1F,temp); + if ( pVBInfo->TVInfo & SetPALTV ) + { + tempbx = 0x0382 ; + tempcx = 0x007e ; + } + else + { + tempbx = 0x0369 ; + tempcx = 0x0061 ; + } + + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x4b , temp ) ; + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x4c , temp ) ; + + temp = ( ( tempcx & 0xFF00 ) >> 8 ) & 0x03 ; + temp = temp << 2 ; + temp |= ( ( tempbx & 0xFF00 ) >> 8 ) & 0x03 ; + + if ( pVBInfo->VBInfo & SetCRT2ToYPbPr ) + { + temp |= 0x10 ; + + if ( pVBInfo->TVInfo & SetYPbPrMode525p ) + temp |= 0x20 ; + + if ( pVBInfo->TVInfo & SetYPbPrMode750p ) + temp |= 0x60 ; + } + + XGINew_SetReg1( pVBInfo->Part2Port , 0x4d , temp ) ; + temp=XGINew_GetReg1( pVBInfo->Part2Port , 0x43 ) ; /* 301b change */ + XGINew_SetReg1( pVBInfo->Part2Port , 0x43 , ( USHORT )( temp - 3 ) ) ; + + if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) ) + { + if ( pVBInfo->TVInfo & NTSC1024x768 ) + { + TimingPoint = XGI_NTSC1024AdjTime ; + for( i = 0x1c , j = 0 ; i <= 0x30 ; i++ , j++ ) + { + XGINew_SetReg1( pVBInfo->Part2Port , i , TimingPoint[ j ] ) ; + } + XGINew_SetReg1( pVBInfo->Part2Port , 0x43 , 0x72 ) ; + } + } + + /* [ycchen] 01/14/03 Modify for 301C PALM Support */ + if ( pVBInfo->VBType & VB_XGI301C ) + { + if ( pVBInfo->TVInfo & SetPALMTV ) + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x4E , ~0x08 , 0x08 ) ; /* PALM Mode */ + } + + if ( pVBInfo->TVInfo & SetPALMTV ) + { + tempax = ( UCHAR )XGINew_GetReg1( pVBInfo->Part2Port , 0x01 ) ; + tempax-- ; + XGINew_SetRegAND( pVBInfo->Part2Port , 0x01 , tempax ) ; + + /* if ( !( pVBInfo->VBType & VB_XGI301C ) ) */ + XGINew_SetRegAND( pVBInfo->Part2Port , 0x00 , 0xEF ) ; + } + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + if ( !( pVBInfo->VBInfo & SetInSlaveMode ) ) + { + XGINew_SetReg1( pVBInfo->Part2Port , 0x0B , 0x00 ) ; + } + } + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + return ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetLCDRegs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetLCDRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo) +{ + USHORT push1 , + push2 , + pushbx , + tempax , + tempbx , + tempcx , + temp , + tempah , + tempbh , + tempch , + resinfo , + modeflag , + CRT1Index ; + + XGI_LCDDesStruct *LCDBDesPtr = NULL ; + + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */ + resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */ + resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; + CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ; + CRT1Index &= IndexMask ; + } + + if ( !( pVBInfo->VBInfo & SetCRT2ToLCD ) ) + { + return ; + } + + tempbx = pVBInfo->HDE ; /* RHACTE=HDE-1 */ + + if ( XGI_IsLCDDualLink( pVBInfo ) ) + tempbx = tempbx >> 1 ; + + tempbx -= 1 ; + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x2C , temp ) ; + temp = ( tempbx & 0xFF00 ) >> 8 ; + temp = temp << 4 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x2B , 0x0F , temp ) ; + temp = 0x01 ; + + if ( pVBInfo->LCDResInfo == Panel1280x1024 ) + { + if ( pVBInfo->ModeType == ModeEGA ) + { + if ( pVBInfo->VGAHDE >= 1024 ) + { + temp = 0x02 ; + if ( pVBInfo->LCDInfo & LCDVESATiming ) + temp = 0x01 ; + } + } + } + + XGINew_SetReg1( pVBInfo->Part2Port , 0x0B , temp ) ; + tempbx = pVBInfo->VDE ; /* RTVACTEO=(VDE-1)&0xFF */ + push1 = tempbx ; + tempbx-- ; + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x03 , temp ) ; + temp = ( ( tempbx & 0xFF00 ) >> 8 ) & 0x07 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x0C , ~0x07 , temp ) ; + + tempcx = pVBInfo->VT - 1 ; + push2 = tempcx + 1 ; + temp = tempcx & 0x00FF ; /* RVTVT=VT-1 */ + XGINew_SetReg1( pVBInfo->Part2Port , 0x19 , temp ) ; + temp = ( tempcx & 0xFF00 ) >> 8 ; + temp = temp << 5 ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x1A , temp ) ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x09 , 0xF0 , 0x00 ) ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x0A , 0xF0 , 0x00 ) ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x17 , 0xFB , 0x00 ) ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x18 , 0xDF , 0x00 ) ; + + /* Customized LCDB Des no add */ + tempbx = 5 ; + LCDBDesPtr = ( XGI_LCDDesStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; + tempah = pVBInfo->LCDResInfo ; + tempah &= PanelResInfo ; + + if ( ( tempah == Panel1024x768 ) || ( tempah == Panel1024x768x75 ) ) + { + tempbx = 1024 ; + tempcx = 768 ; + } + else if ( ( tempah == Panel1280x1024 ) || ( tempah == Panel1280x1024x75 ) ) + { + tempbx = 1280 ; + tempcx = 1024 ; + } + else if ( tempah == Panel1400x1050 ) + { + tempbx = 1400 ; + tempcx = 1050 ; + } + else + { + tempbx = 1600 ; + tempcx = 1200 ; + } + + if ( pVBInfo->LCDInfo & EnableScalingLCD ) + { + tempbx = pVBInfo->HDE ; + tempcx = pVBInfo->VDE ; + } + + pushbx = tempbx ; + tempax = pVBInfo->VT ; + pVBInfo->LCDHDES = LCDBDesPtr->LCDHDES ; + pVBInfo->LCDHRS = LCDBDesPtr->LCDHRS ; + pVBInfo->LCDVDES = LCDBDesPtr->LCDVDES ; + pVBInfo->LCDVRS = LCDBDesPtr->LCDVRS ; + tempbx = pVBInfo->LCDVDES ; + tempcx += tempbx ; + + if ( tempcx >= tempax ) + tempcx -= tempax ; /* lcdvdes */ + + temp = tempbx & 0x00FF ; /* RVEQ1EQ=lcdvdes */ + XGINew_SetReg1( pVBInfo->Part2Port , 0x05 , temp ) ; + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x06 , temp ) ; + tempch = ( ( tempcx & 0xFF00 ) >> 8 ) & 0x07 ; + tempbh = ( ( tempbx & 0xFF00 ) >> 8 ) & 0x07 ; + tempah = tempch ; + tempah = tempah << 3 ; + tempah |= tempbh ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x02 , tempah ) ; + + /* getlcdsync() */ + XGI_GetLCDSync( &tempax , &tempbx,pVBInfo ) ; + tempcx = tempbx ; + tempax = pVBInfo->VT ; + tempbx = pVBInfo->LCDVRS ; + + /* if ( SetLCD_Info & EnableScalingLCD ) */ + tempcx += tempbx ; + if ( tempcx >= tempax ) + tempcx -= tempax ; + + temp = tempbx & 0x00FF ; /* RTVACTEE=lcdvrs */ + XGINew_SetReg1( pVBInfo->Part2Port , 0x04 , temp ) ; + temp = ( tempbx & 0xFF00 ) >> 8 ; + temp = temp << 4 ; + temp |= ( tempcx & 0x000F ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x01 , temp ) ; + tempcx = pushbx ; + tempax = pVBInfo->HT ; + tempbx = pVBInfo->LCDHDES ; + tempbx &= 0x0FFF ; + + if ( XGI_IsLCDDualLink( pVBInfo ) ) + { + tempax = tempax >> 1 ; + tempbx = tempbx >> 1 ; + tempcx = tempcx >> 1 ; + } + + if ( pVBInfo->VBType & VB_XGI302LV ) + tempbx += 1 ; + + if ( pVBInfo->VBType & VB_XGI301C ) /* tap4 */ + tempbx += 1 ; + + tempcx += tempbx ; + + if ( tempcx >= tempax ) + tempcx -= tempax ; + + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x1F , temp ) ; /* RHBLKE=lcdhdes */ + temp = ( ( tempbx & 0xFF00 ) >> 8 ) << 4 ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x20 , temp ) ; + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x23 , temp ) ; /* RHEQPLE=lcdhdee */ + temp = ( tempcx & 0xFF00 ) >> 8 ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x25 , temp ) ; + + /* getlcdsync() */ + XGI_GetLCDSync( &tempax , &tempbx ,pVBInfo) ; + tempcx = tempax ; + tempax = pVBInfo->HT ; + tempbx = pVBInfo->LCDHRS ; + /* if ( SetLCD_Info & EnableScalingLCD) */ + if ( XGI_IsLCDDualLink( pVBInfo) ) + { + tempax = tempax >> 1 ; + tempbx = tempbx >> 1 ; + tempcx = tempcx >> 1 ; + } + + if ( pVBInfo->VBType & VB_XGI302LV ) + tempbx += 1 ; + + tempcx += tempbx ; + + if ( tempcx >= tempax ) + tempcx -= tempax ; + + temp = tempbx & 0x00FF ; /* RHBURSTS=lcdhrs */ + XGINew_SetReg1( pVBInfo->Part2Port , 0x1C , temp ) ; + + temp = ( tempbx & 0xFF00 ) >> 8 ; + temp = temp << 4 ; + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x1D , ~0x0F0 , temp ) ; + temp = tempcx & 0x00FF ; /* RHSYEXP2S=lcdhre */ + XGINew_SetReg1( pVBInfo->Part2Port , 0x21 , temp ) ; + + if ( !( pVBInfo->LCDInfo & LCDVESATiming ) ) + { + if ( pVBInfo->VGAVDE == 525 ) + { + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + temp = 0xC6 ; + } + else + temp = 0xC4 ; + + XGINew_SetReg1( pVBInfo->Part2Port , 0x2f , temp ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x30 , 0xB3 ) ; + } + + if ( pVBInfo->VGAVDE == 420 ) + { + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + temp = 0x4F ; + } + else + temp = 0x4E ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x2f , temp ) ; + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetTap4Ptr */ +/* Input : */ +/* Output : di -> Tap4 Reg. Setting Pointer */ +/* Description : */ +/* --------------------------------------------------------------------- */ +XGI301C_Tap4TimingStruct* XGI_GetTap4Ptr(USHORT tempcx, PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempax , + tempbx , + i ; + + XGI301C_Tap4TimingStruct *Tap4TimingPtr ; + + if ( tempcx == 0 ) + { + tempax = pVBInfo->VGAHDE ; + tempbx = pVBInfo->HDE ; + } + else + { + tempax = pVBInfo->VGAVDE ; + tempbx = pVBInfo->VDE ; + } + + if ( tempax < tempbx ) + return &EnlargeTap4Timing[ 0 ] ; + else if( tempax == tempbx ) + return &NoScaleTap4Timing[ 0 ] ; /* 1:1 */ + else + Tap4TimingPtr = NTSCTap4Timing ; /* NTSC */ + + if ( pVBInfo->TVInfo & SetPALTV ) + Tap4TimingPtr = PALTap4Timing ; + + + if ( pVBInfo->VBInfo & SetCRT2ToYPbPr ) + { + if ( pVBInfo->TVInfo & SetYPbPrMode525i ) + Tap4TimingPtr = YPbPr525iTap4Timing ; + if ( pVBInfo->TVInfo & SetYPbPrMode525p ) + Tap4TimingPtr = YPbPr525pTap4Timing ; + if ( pVBInfo->TVInfo & SetYPbPrMode750p ) + Tap4TimingPtr = YPbPr750pTap4Timing ; + } + + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + Tap4TimingPtr = HiTVTap4Timing ; + + i = 0 ; + while( Tap4TimingPtr[ i ].DE != 0xFFFF ) + { + if ( Tap4TimingPtr[ i ].DE == tempax ) + break ; + i++ ; + } + return &Tap4TimingPtr[ i ] ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetTap4Regs */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetTap4Regs( PVB_DEVICE_INFO pVBInfo) +{ + USHORT i , + j ; + + XGI301C_Tap4TimingStruct *Tap4TimingPtr ; + + if ( !( pVBInfo->VBType & VB_XGI301C ) ) + return ; + +#ifndef Tap4 + XGINew_SetRegAND( pVBInfo->Part2Port , 0x4E , 0xEB ) ; /* Disable Tap4 */ +#else /* Tap4 Setting */ + + Tap4TimingPtr = XGI_GetTap4Ptr( 0 , pVBInfo) ; /* Set Horizontal Scaling */ + for( i = 0x80 , j = 0 ; i <= 0xBF ; i++ , j++ ) + XGINew_SetReg1( pVBInfo->Part2Port , i , Tap4TimingPtr->Reg[ j ] ) ; + + if ( ( pVBInfo->VBInfo & SetCRT2ToTV ) && ( !( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) ) ) + { + Tap4TimingPtr = XGI_GetTap4Ptr( 1 , pVBInfo); /* Set Vertical Scaling */ + for( i = 0xC0 , j = 0 ; i < 0xFF ; i++ , j++ ) + XGINew_SetReg1( pVBInfo->Part2Port , i , Tap4TimingPtr->Reg[ j ] ) ; + } + + if ( ( pVBInfo->VBInfo & SetCRT2ToTV ) && ( !( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) ) ) + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x4E , ~0x14 , 0x04 ) ; /* Enable V.Scaling */ + else + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x4E , ~0x14 , 0x10 ) ; /* Enable H.Scaling */ +#endif +} + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetGroup3 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetGroup3(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo) +{ + USHORT i; + UCHAR *tempdi; + USHORT modeflag; + + if(ModeNo<=0x13) + { + modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } + else + { + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + + + XGINew_SetReg1(pVBInfo->Part3Port,0x00,0x00); + if(pVBInfo->TVInfo&SetPALTV) + { + XGINew_SetReg1(pVBInfo->Part3Port,0x13,0xFA); + XGINew_SetReg1(pVBInfo->Part3Port,0x14,0xC8); + } + else + { + XGINew_SetReg1(pVBInfo->Part3Port,0x13,0xF5); + XGINew_SetReg1(pVBInfo->Part3Port,0x14,0xB7); + } + + if(!(pVBInfo->VBInfo&SetCRT2ToTV)) + { + return; + } + + if(pVBInfo->TVInfo&SetPALMTV) + { + XGINew_SetReg1(pVBInfo->Part3Port,0x13,0xFA); + XGINew_SetReg1(pVBInfo->Part3Port,0x14,0xC8); + XGINew_SetReg1(pVBInfo->Part3Port,0x3D,0xA8); + } + + if((pVBInfo->VBInfo&SetCRT2ToHiVisionTV)|| (pVBInfo->VBInfo&SetCRT2ToYPbPr)) + { + if(pVBInfo->TVInfo & SetYPbPrMode525i) + { + return; + } + tempdi=pVBInfo->HiTVGroup3Data; + if(pVBInfo->SetFlag&TVSimuMode) + { + tempdi=pVBInfo->HiTVGroup3Simu; + if(!(modeflag&Charx8Dot)) + { + tempdi=pVBInfo->HiTVGroup3Text; + } + } + + if(pVBInfo->TVInfo & SetYPbPrMode525p) + { + tempdi=pVBInfo->Ren525pGroup3; + } + if(pVBInfo->TVInfo & SetYPbPrMode750p) + { + tempdi=pVBInfo->Ren750pGroup3; + } + + for(i=0;i<=0x3E;i++) + { + XGINew_SetReg1(pVBInfo->Part3Port,i,tempdi[i]); + } + if(pVBInfo->VBType&VB_XGI301C) /* Marcovision */ + { + if(pVBInfo->TVInfo & SetYPbPrMode525p) + { + XGINew_SetReg1(pVBInfo->Part3Port,0x28,0x3f); + } + } + } + return; +} /* {end of XGI_SetGroup3} */ + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetGroup4 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetGroup4(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempax , + tempcx , + tempbx , + modeflag , + temp , + temp2 ; + + ULONG tempebx , + tempeax , + templong ; + + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */ + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */ + } + + temp = pVBInfo->RVBHCFACT ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x13 , temp ) ; + + tempbx = pVBInfo->RVBHCMAX ; + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x14 , temp ) ; + temp2 = ( ( tempbx & 0xFF00 ) >> 8 ) << 7 ; + tempcx = pVBInfo->VGAHT - 1 ; + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x16 , temp ) ; + + temp =( ( tempcx & 0xFF00 ) >> 8 ) << 3 ; + temp2 |= temp ; + + tempcx = pVBInfo->VGAVT - 1 ; + if ( !( pVBInfo->VBInfo & SetCRT2ToTV ) ) + { + tempcx -= 5 ; + } + + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x17 , temp ) ; + temp = temp2 | ( ( tempcx & 0xFF00 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x15 , temp ) ; + XGINew_SetRegOR( pVBInfo->Part4Port , 0x0D , 0x08 ) ; + tempcx = pVBInfo->VBInfo ; + tempbx = pVBInfo->VGAHDE ; + + if ( modeflag & HalfDCLK ) + { + tempbx = tempbx >> 1 ; + } + + if ( XGI_IsLCDDualLink( pVBInfo ) ) + tempbx = tempbx >> 1 ; + + if(tempcx&SetCRT2ToHiVisionTV) + { + temp=0; + if(tempbx<=1024) + temp=0xA0; + if(tempbx == 1280) + temp = 0xC0; + } + else if(tempcx&SetCRT2ToTV) + { + temp=0xA0; + if(tempbx <= 800) + temp=0x80; + } + else + { + temp=0x80; + if(pVBInfo->VBInfo&SetCRT2ToLCD) + { + temp=0; + if(tempbx>800) + temp=0x60; + } + } + + if ( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) + { + temp = 0x00 ; + if ( pVBInfo->VGAHDE == 1280 ) + temp = 0x40 ; + if ( pVBInfo->VGAHDE == 1024 ) + temp = 0x20 ; + } + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x0E , ~0xEF , temp ) ; + + tempebx = pVBInfo->VDE ; + + if ( tempcx & SetCRT2ToHiVisionTV ) + { + if ( !( temp & 0xE000 ) ) + tempbx = tempbx >> 1 ; + } + + tempcx = pVBInfo->RVBHRS ; + temp = tempcx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x18 , temp ); + + tempeax = pVBInfo->VGAVDE ; + tempcx |= 0x04000 ; + + + if ( tempeax <= tempebx ) + { + tempcx=(tempcx&(~0x4000)); + tempeax = pVBInfo->VGAVDE ; + } + else + { + tempeax -= tempebx ; + } + + + templong = ( tempeax * 256 * 1024 ) % tempebx ; + tempeax = ( tempeax * 256 * 1024 ) / tempebx ; + tempebx = tempeax ; + + if ( templong != 0 ) + { + tempebx++ ; + } + + + temp = ( USHORT )( tempebx & 0x000000FF ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x1B , temp ) ; + + temp = ( USHORT )( ( tempebx & 0x0000FF00 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x1A , temp ) ; + tempbx = ( USHORT )( tempebx >> 16 ) ; + temp = tempbx & 0x00FF ; + temp = temp << 4 ; + temp |= ( ( tempcx & 0xFF00 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x19 , temp ) ; + + /* 301b */ + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + temp = 0x0028 ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x1C , temp ) ; + tempax = pVBInfo->VGAHDE ; + if ( modeflag & HalfDCLK ) + { + tempax = tempax >> 1 ; + } + + if ( XGI_IsLCDDualLink( pVBInfo ) ) + tempax = tempax >> 1 ; + + /* if((pVBInfo->VBInfo&(SetCRT2ToLCD))||((pVBInfo->TVInfo&SetYPbPrMode525p)||(pVBInfo->TVInfo&SetYPbPrMode750p))) { */ + if ( pVBInfo->VBInfo & SetCRT2ToLCD ) + { + if ( tempax > 800 ) + tempax -= 800 ; + } + else + { + if ( pVBInfo->VGAHDE > 800 ) + { + if ( pVBInfo->VGAHDE == 1024 ) + tempax = ( tempax * 25 / 32 ) - 1 ; + else + tempax = ( tempax * 20 / 32 ) - 1 ; + } + } + tempax -= 1 ; + +/* + if ( pVBInfo->VBInfo & ( SetCRT2ToTV | SetCRT2ToHiVisionTV ) ) + { + if ( pVBInfo->VBType & VB_XGI301LV ) + { + if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p | SetYPbPrMode1080i ) ) ) + { + if ( pVBInfo->VGAHDE > 800 ) + { + if ( pVBInfo->VGAHDE == 1024 ) + tempax = ( tempax * 25 / 32 ) - 1 ; + else + tempax = ( tempax * 20 / 32 ) - 1 ; + } + } + } + else + { + if ( pVBInfo->VGAHDE > 800 ) + { + if ( pVBInfo->VGAHDE == 1024 ) + tempax = ( tempax * 25 / 32 ) - 1 ; + else + tempax = ( tempax * 20 / 32 ) - 1 ; + } + } + } +*/ + + temp = ( tempax & 0xFF00 ) >> 8 ; + temp = ( ( temp & 0x0003 ) << 4 ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x1E , temp ) ; + temp = ( tempax & 0x00FF ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x1D , temp ) ; + + if ( pVBInfo->VBInfo & ( SetCRT2ToTV | SetCRT2ToHiVisionTV ) ) + { + if ( pVBInfo->VGAHDE > 800 ) + { + XGINew_SetRegOR( pVBInfo->Part4Port , 0x1E , 0x08 ) ; + } + } + temp = 0x0036 ; + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + if ( !( pVBInfo->TVInfo & ( NTSC1024x768 | SetYPbPrMode525p | SetYPbPrMode750p | SetYPbPrMode1080i ) ) ) + { + temp |= 0x0001 ; + if ( ( pVBInfo->VBInfo & SetInSlaveMode ) && ( !( pVBInfo->TVInfo & TVSimuMode ) ) ) + temp &= ( ~0x0001 ) ; + } + } + + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x1F , 0x00C0 , temp ) ; + tempbx = pVBInfo->HT ; + if ( XGI_IsLCDDualLink( pVBInfo ) ) + tempbx = tempbx >> 1 ; + tempbx = ( tempbx >> 1 ) - 2 ; + temp = ( ( tempbx & 0x0700 ) >> 8 ) << 3 ; + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x21 , 0x00C0 , temp ) ; + temp = tempbx & 0x00FF ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x22 , temp ) ; + } + /* end 301b */ + + if ( pVBInfo->ISXPDOS == 0 ) + XGI_SetCRT2VCLK( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetGroup5 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetGroup5( USHORT ModeNo , USHORT ModeIdIndex , PVB_DEVICE_INFO pVBInfo) +{ + USHORT Pindex , + Pdata ; + + Pindex = pVBInfo->Part5Port ; + Pdata = pVBInfo->Part5Port + 1 ; + if ( pVBInfo->ModeType == ModeVGA ) + { + if ( !( pVBInfo->VBInfo & ( SetInSlaveMode | LoadDACFlag | CRT2DisplayFlag ) ) ) + { + XGINew_EnableCRT2(pVBInfo) ; + /* LoadDAC2(pVBInfo->Part5Port,ModeNo,ModeIdIndex); */ + } + } + return ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetLcdPtr */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void* XGI_GetLcdPtr( USHORT BX , USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT i , + tempdx , + tempcx , + tempbx , + tempal , + modeflag , + table ; + + XGI330_LCDDataTablStruct *tempdi = 0 ; + + + tempbx = BX; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + tempal = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC ; + } + + tempal = tempal & 0x0f ; + + if ( tempbx <= 1 ) /* ExpLink */ + { + if ( ModeNo <= 0x13 ) + { + tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ; /* find no Ext_CRT2CRTC2 */ + } + else + { + tempal= pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC ; + } + + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + { + if ( ModeNo <= 0x13 ) + tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC2 ; + else + tempal= pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC2 ; + } + + if ( tempbx & 0x01 ) + tempal = ( tempal >> 4 ) ; + + tempal = ( tempal & 0x0f ) ; + } + + tempcx = LCDLenList[ tempbx ] ; /* mov cl,byte ptr cs:LCDLenList[bx] */ + + if ( pVBInfo->LCDInfo & EnableScalingLCD ) /* ScaleLCD */ + { + if ( ( tempbx == 5 ) || ( tempbx ) == 7 ) + tempcx = LCDDesDataLen2 ; + else if ( ( tempbx == 3 ) || ( tempbx == 8 ) ) + tempcx = LVDSDesDataLen2 ; + } + /* mov di, word ptr cs:LCDDataList[bx] */ + /* tempdi=pVideoMemory[LCDDataList+tempbx*2]|(pVideoMemory[LCDDataList+tempbx*2+1]<<8); */ + + switch( tempbx ) + { + case 0: + tempdi = XGI_EPLLCDCRT1Ptr_H ; + break ; + case 1: + tempdi = XGI_EPLLCDCRT1Ptr_V ; + break ; + case 2: + tempdi = XGI_EPLLCDDataPtr ; + break ; + case 3: + tempdi = XGI_EPLLCDDesDataPtr ; + break ; + case 4: + tempdi = XGI_LCDDataTable ; + break ; + case 5: + tempdi = XGI_LCDDesDataTable ; + break ; + case 6: + tempdi = XGI_EPLCHLCDRegPtr ; + break ; + case 7: + case 8: + case 9: + tempdi = 0 ; + break ; + default: + break ; + } + + if ( tempdi == 0x00 ) /* OEMUtil */ + return 0 ; + + table = tempbx ; + i = 0 ; + + while( tempdi[ i ].PANELID != 0xff ) + { + tempdx = pVBInfo->LCDResInfo ; + if ( tempbx & 0x0080 ) /* OEMUtil */ + { + tempbx &= ( ~0x0080 ) ; + tempdx = pVBInfo->LCDTypeInfo ; + } + + if ( pVBInfo->LCDInfo & EnableScalingLCD ) + tempdx &= ( ~PanelResInfo ) ; + + if ( tempdi[ i ].PANELID == tempdx ) + { + tempbx = tempdi[ i ].MASK ; + tempdx = pVBInfo->LCDInfo ; + + if ( ModeNo <= 0x13 ) /* alan 09/10/2003 */ + tempdx |= SetLCDStdMode ; + + if ( modeflag & HalfDCLK ) + tempdx |= SetLCDLowResolution ; + + tempbx &= tempdx; + if ( tempbx == tempdi[ i ].CAP ) + break ; + } + i++ ; + } + + if ( table == 0 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &XGI_LVDSCRT11024x768_1_H[ tempal ] ; + break ; + case 1: + return &XGI_LVDSCRT11024x768_2_H[ tempal ] ; + break ; + case 2: + return &XGI_LVDSCRT11280x1024_1_H[ tempal ] ; + break ; + case 3: + return &XGI_LVDSCRT11280x1024_2_H[ tempal ] ; + break ; + case 4: + return &XGI_LVDSCRT11400x1050_1_H[ tempal ] ; + break ; + case 5: + return &XGI_LVDSCRT11400x1050_2_H[ tempal ] ; + break ; + case 6: + return &XGI_LVDSCRT11600x1200_1_H[ tempal ] ; + break ; + case 7: + return &XGI_LVDSCRT11024x768_1_Hx75[ tempal ] ; + break ; + case 8: + return &XGI_LVDSCRT11024x768_2_Hx75[ tempal ] ; + break ; + case 9: + return &XGI_LVDSCRT11280x1024_1_Hx75[ tempal ] ; + break ; + case 10: + return &XGI_LVDSCRT11280x1024_2_Hx75[ tempal ] ; + break ; + default: + break ; + } + } + else if ( table == 1 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &XGI_LVDSCRT11024x768_1_V[ tempal ] ; + break ; + case 1: + return &XGI_LVDSCRT11024x768_2_V[ tempal ] ; + break ; + case 2: + return &XGI_LVDSCRT11280x1024_1_V[ tempal ] ; + break ; + case 3: + return &XGI_LVDSCRT11280x1024_2_V[ tempal ] ; + break ; + case 4: + return &XGI_LVDSCRT11400x1050_1_V[ tempal ] ; + break ; + case 5: + return &XGI_LVDSCRT11400x1050_2_V[ tempal ] ; + break ; + case 6: + return &XGI_LVDSCRT11600x1200_1_V[ tempal ] ; + break ; + case 7: + return &XGI_LVDSCRT11024x768_1_Vx75[ tempal ] ; + break ; + case 8: + return &XGI_LVDSCRT11024x768_2_Vx75[ tempal ] ; + break ; + case 9: + return &XGI_LVDSCRT11280x1024_1_Vx75[ tempal ] ; + break ; + case 10: + return &XGI_LVDSCRT11280x1024_2_Vx75[ tempal ] ; + break ; + default: + break ; + } + } + else if ( table == 2 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &XGI_LVDS1024x768Data_1[ tempal ] ; + break ; + case 1: + return &XGI_LVDS1024x768Data_2[ tempal ] ; + break ; + case 2: + return &XGI_LVDS1280x1024Data_1[ tempal ] ; + break ; + case 3: + return &XGI_LVDS1280x1024Data_2[ tempal ] ; + break ; + case 4: + return &XGI_LVDS1400x1050Data_1[ tempal ] ; + break ; + case 5: + return &XGI_LVDS1400x1050Data_2[ tempal ] ; + break ; + case 6: + return &XGI_LVDS1600x1200Data_1[ tempal ] ; + break ; + case 7: + return &XGI_LVDSNoScalingData[ tempal ] ; + break ; + case 8: + return &XGI_LVDS1024x768Data_1x75[ tempal ] ; + break ; + case 9: + return &XGI_LVDS1024x768Data_2x75[ tempal ] ; + break ; + case 10: + return &XGI_LVDS1280x1024Data_1x75[ tempal ] ; + break ; + case 11: + return &XGI_LVDS1280x1024Data_2x75[ tempal ] ; + break ; + case 12: + return &XGI_LVDSNoScalingDatax75[ tempal ] ; + break ; + default: + break ; + } + } + else if ( table == 3 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &XGI_LVDS1024x768Des_1[ tempal ] ; + break ; + case 1: + return &XGI_LVDS1024x768Des_3[ tempal ] ; + break ; + case 2: + return &XGI_LVDS1024x768Des_2[ tempal ] ; + break ; + case 3: + return &XGI_LVDS1280x1024Des_1[ tempal ] ; + break ; + case 4: + return &XGI_LVDS1280x1024Des_2[ tempal ] ; + break ; + case 5: + return &XGI_LVDS1400x1050Des_1[ tempal ] ; + break ; + case 6: + return &XGI_LVDS1400x1050Des_2[ tempal ] ; + break ; + case 7: + return &XGI_LVDS1600x1200Des_1[ tempal ] ; + break ; + case 8: + return &XGI_LVDSNoScalingDesData[ tempal ] ; + break ; + case 9: + return &XGI_LVDS1024x768Des_1x75[ tempal ] ; + break ; + case 10: + return &XGI_LVDS1024x768Des_3x75[ tempal ] ; + break ; + case 11: + return &XGI_LVDS1024x768Des_2x75[ tempal ] ; + break; + case 12: + return &XGI_LVDS1280x1024Des_1x75[ tempal ] ; + break ; + case 13: + return &XGI_LVDS1280x1024Des_2x75[ tempal ] ; + break ; + case 14: + return &XGI_LVDSNoScalingDesDatax75[ tempal ] ; + break ; + default: + break ; + } + } + else if ( table == 4 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &XGI_ExtLCD1024x768Data[ tempal ] ; + break ; + case 1: + return &XGI_StLCD1024x768Data[ tempal ] ; + break ; + case 2: + return &XGI_CetLCD1024x768Data[ tempal ] ; + break ; + case 3: + return &XGI_ExtLCD1280x1024Data[ tempal ] ; + break ; + case 4: + return &XGI_StLCD1280x1024Data[ tempal ] ; + break ; + case 5: + return &XGI_CetLCD1280x1024Data[ tempal ] ; + break ; + case 6: + return &XGI_ExtLCD1400x1050Data[ tempal ] ; + break ; + case 7: + return &XGI_StLCD1400x1050Data[ tempal ] ; + break ; + case 8: + return &XGI_CetLCD1400x1050Data[ tempal ] ; + break ; + case 9: + return &XGI_ExtLCD1600x1200Data[ tempal ] ; + break ; + case 10: + return &XGI_StLCD1600x1200Data[ tempal ] ; + break ; + case 11: + return &XGI_NoScalingData[ tempal ] ; + break ; + case 12: + return &XGI_ExtLCD1024x768x75Data[ tempal ] ; + break ; + case 13: + return &XGI_ExtLCD1024x768x75Data[ tempal ] ; + break ; + case 14: + return &XGI_CetLCD1024x768x75Data[ tempal ] ; + break ; + case 15: + return &XGI_ExtLCD1280x1024x75Data[ tempal ] ; + break ; + case 16: + return &XGI_StLCD1280x1024x75Data[ tempal ] ; + break; + case 17: + return &XGI_CetLCD1280x1024x75Data[ tempal ] ; + break; + case 18: + return &XGI_NoScalingDatax75[ tempal ] ; + break ; + default: + break ; + } + } + else if ( table == 5 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &XGI_ExtLCDDes1024x768Data[ tempal ] ; + break ; + case 1: + return &XGI_StLCDDes1024x768Data[ tempal ] ; + break ; + case 2: + return &XGI_CetLCDDes1024x768Data[ tempal ] ; + break ; + case 3: + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + return &XGI_ExtLCDDLDes1280x1024Data[ tempal ] ; + else + return &XGI_ExtLCDDes1280x1024Data[ tempal ] ; + break ; + case 4: + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + return &XGI_StLCDDLDes1280x1024Data[ tempal ] ; + else + return &XGI_StLCDDes1280x1024Data[ tempal ] ; + break ; + case 5: + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + return &XGI_CetLCDDLDes1280x1024Data[ tempal ] ; + else + return &XGI_CetLCDDes1280x1024Data[ tempal ] ; + break ; + case 6: + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + return &XGI_ExtLCDDLDes1400x1050Data[ tempal ] ; + else + return &XGI_ExtLCDDes1400x1050Data[ tempal ] ; + break ; + case 7: + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + return &XGI_StLCDDLDes1400x1050Data[ tempal ] ; + else + return &XGI_StLCDDes1400x1050Data[ tempal ] ; + break ; + case 8: + return &XGI_CetLCDDes1400x1050Data[ tempal ] ; + break ; + case 9: + return &XGI_CetLCDDes1400x1050Data2[ tempal ] ; + break ; + case 10: + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + return &XGI_ExtLCDDLDes1600x1200Data[ tempal ] ; + else + return &XGI_ExtLCDDes1600x1200Data[ tempal ] ; + break ; + case 11: + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + return &XGI_StLCDDLDes1600x1200Data[ tempal ] ; + else + return &XGI_StLCDDes1600x1200Data[ tempal ] ; + break ; + case 12: + return &XGI_NoScalingDesData[ tempal ] ; + break; + case 13: + return &XGI_ExtLCDDes1024x768x75Data[ tempal ] ; + break ; + case 14: + return &XGI_StLCDDes1024x768x75Data[ tempal ] ; + break ; + case 15: + return &XGI_CetLCDDes1024x768x75Data[ tempal ] ; + break ; + case 16: + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + return &XGI_ExtLCDDLDes1280x1024x75Data[ tempal ] ; + else + return &XGI_ExtLCDDes1280x1024x75Data[ tempal ] ; + break ; + case 17: + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + return &XGI_StLCDDLDes1280x1024x75Data[ tempal ] ; + else + return &XGI_StLCDDes1280x1024x75Data[ tempal ] ; + break ; + case 18: + if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) ) + return &XGI_CetLCDDLDes1280x1024x75Data[ tempal ] ; + else + return &XGI_CetLCDDes1280x1024x75Data[ tempal ] ; + break ; + case 19: + return &XGI_NoScalingDesDatax75[ tempal ] ; + break ; + default: + break ; + } + } + else if ( table == 6 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &XGI_CH7017LV1024x768[ tempal ] ; + break ; + case 1: + return &XGI_CH7017LV1400x1050[ tempal ] ; + break ; + default: + break ; + } + } + return 0 ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetTVPtr */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void* XGI_GetTVPtr (USHORT BX,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT i , tempdx , tempbx , tempal , modeflag , table ; + XGI330_TVDataTablStruct *tempdi = 0 ; + + tempbx = BX ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + tempal = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC ; + } + + tempal = tempal & 0x3f ; + table = tempbx ; + + switch( tempbx ) + { + case 0: + tempdi = 0 ; /*EPLCHTVCRT1Ptr_H;*/ + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + tempdi = XGI_EPLCHTVCRT1Ptr; + } + break ; + case 1: + tempdi = 0 ; /*EPLCHTVCRT1Ptr_V;*/ + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + tempdi = XGI_EPLCHTVCRT1Ptr; + } + break ; + case 2: + tempdi = XGI_EPLCHTVDataPtr ; + break ; + case 3: + tempdi = 0 ; + break ; + case 4: + tempdi = XGI_TVDataTable ; + break ; + case 5: + tempdi = 0 ; + break ; + case 6: + tempdi = XGI_EPLCHTVRegPtr ; + break ; + default: + break ; + } + + if ( tempdi == 0x00 ) /* OEMUtil */ + return( 0 ) ; + + tempdx = pVBInfo->TVInfo ; + + if ( pVBInfo->VBInfo & SetInSlaveMode ) + tempdx = tempdx | SetTVLockMode ; + + if ( modeflag & HalfDCLK ) + tempdx = tempdx | SetTVLowResolution ; + + i = 0 ; + + while( tempdi[ i ].MASK != 0xffff ) + { + if ( ( tempdx & tempdi[ i ].MASK ) == tempdi[ i ].CAP ) + break ; + i++ ; + } + + if ( table == 0x00 ) /* 07/05/22 */ + { +#ifdef WIN2000 + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &CH7007TVCRT1UNTSC_H[ tempal ] ; + break ; + case 1: + return &CH7007TVCRT1ONTSC_H[ tempal ] ; + break ; + case 2: + return &CH7007TVCRT1UPAL_H[ tempal ] ; + break ; + case 3: + return &CH7007TVCRT1OPAL_H[ tempal ] ; + break ; + default: + break ; + } + } +#endif + } + else if ( table == 0x01 ) + { +#ifdef WIN2000 + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &CH7007TVCRT1UNTSC_V[ tempal ] ; + break ; + case 1: + return &CH7007TVCRT1ONTSC_V[ tempal ] ; + break ; + case 2: + return &CH7007TVCRT1UPAL_V[ tempal ] ; + break ; + case 3: + return &CH7007TVCRT1OPAL_V[ tempal ] ; + break ; + default: + break ; + } + } +#endif + } + else if ( table == 0x04 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &XGI_ExtPALData[ tempal ] ; + break ; + case 1: + return &XGI_ExtNTSCData[ tempal ] ; + break ; + case 2: + return &XGI_StPALData[ tempal ] ; + break ; + case 3: + return &XGI_StNTSCData[ tempal ] ; + break ; + case 4: + return &XGI_ExtHiTVData[ tempal ] ; + break ; + case 5: + return &XGI_St2HiTVData[ tempal ] ; + break ; + case 6: + return &XGI_ExtYPbPr525iData[ tempal ] ; + break ; + case 7: + return &XGI_ExtYPbPr525pData[ tempal ] ; + break ; + case 8: + return &XGI_ExtYPbPr750pData[ tempal ] ; + break ; + case 9: + return &XGI_StYPbPr525iData[ tempal ] ; + break ; + case 10: + return &XGI_StYPbPr525pData[ tempal ] ; + break ; + case 11: + return &XGI_StYPbPr750pData[ tempal ] ; + break; + case 12: /* avoid system hang */ + return &XGI_ExtNTSCData[ tempal ] ; + break ; + case 13: + return &XGI_St1HiTVData[ tempal ] ; + break ; + default: + break ; + } + } + else if( table == 0x02 ) + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &XGI_CHTVUNTSCData[ tempal ] ; + break ; + case 1: + return &XGI_CHTVONTSCData[ tempal ] ; + break ; + case 2: + return &XGI_CHTVUPALData[ tempal ] ; + break ; + case 3: + return &XGI_CHTVOPALData[ tempal ] ; + break ; + default: + break ; + } + } + else if( table == 0x06 ) + { +#ifdef WIN2000 + if ( pVBInfo->IF_DEF_CH7007 == 1 ) + { + /* VideoDebugPrint((0, "XGI_GetTVPtr: pVBInfo->IF_DEF_CH7007==1\n")); */ + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &CH7007TVReg_UNTSC[ tempal ] ; + break ; + case 1: + return &CH7007TVReg_ONTSC[ tempal ] ; + break ; + case 2: + return &CH7007TVReg_UPAL[ tempal ] ; + break ; + case 3: + return &CH7007TVReg_OPAL[ tempal ] ; + break ; + default: + break ; + } + } + else + { + switch( tempdi[ i ].DATAPTR ) + { + case 0: + return &XGI_CHTVRegUNTSC[ tempal ] ; + break ; + case 1: + return &XGI_CHTVRegONTSC[ tempal ] ; + break ; + case 2: + return &XGI_CHTVRegUPAL[ tempal ] ; + break ; + case 3: + return &XGI_CHTVRegOPAL[ tempal ] ; + break ; + default: + break ; + } + } +#endif + } + return( 0 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_BacklightByDrv */ +/* Input : */ +/* Output : TRUE -> Skip backlight control */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_BacklightByDrv( PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR tempah ; + + tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x3A ) ; + if ( tempah & BacklightControlBit ) + return TRUE ; + else + return FALSE ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_FirePWDDisable */ +/* Input : */ +/* Output : */ +/* Description : Turn off VDD & Backlight : Fire disable procedure */ +/* --------------------------------------------------------------------- */ +/* +void XGI_FirePWDDisable( PVB_DEVICE_INFO pVBInfo ) +{ + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x26 , 0x00 , 0xFC ) ; +} +*/ + +/* --------------------------------------------------------------------- */ +/* Function : XGI_FirePWDEnable */ +/* Input : */ +/* Output : */ +/* Description : Turn on VDD & Backlight : Fire enable procedure */ +/* --------------------------------------------------------------------- */ +void XGI_FirePWDEnable(PVB_DEVICE_INFO pVBInfo ) +{ + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x26 , 0x03 , 0xFC ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_EnableGatingCRT */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_EnableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x63 , 0xBF , 0x40 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_DisableGatingCRT */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_DisableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x63 , 0xBF , 0x00 ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetPanelDelay */ +/* Input : */ +/* Output : */ +/* Description : */ +/* I/P : bl : 1 ; T1 : the duration between CPL on and signal on */ +/* : bl : 2 ; T2 : the duration signal on and Vdd on */ +/* : bl : 3 ; T3 : the duration between CPL off and signal off */ +/* : bl : 4 ; T4 : the duration signal off and Vdd off */ +/* --------------------------------------------------------------------- */ +void XGI_SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo) +{ + USHORT index ; + + index = XGI_GetLCDCapPtr(pVBInfo) ; + + if ( tempbl == 1 ) + XGINew_LCD_Wait_Time( pVBInfo->LCDCapList[ index ].PSC_S1, pVBInfo ) ; + + if ( tempbl == 2 ) + XGINew_LCD_Wait_Time( pVBInfo->LCDCapList[ index ].PSC_S2, pVBInfo ) ; + + if ( tempbl == 3 ) + XGINew_LCD_Wait_Time( pVBInfo->LCDCapList[ index ].PSC_S3, pVBInfo ) ; + + if ( tempbl == 4 ) + XGINew_LCD_Wait_Time( pVBInfo->LCDCapList[ index ].PSC_S4, pVBInfo ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetPanelPower */ +/* Input : */ +/* Output : */ +/* Description : */ +/* I/O : ah = 0011b = 03h ; Backlight on, Power on */ +/* = 0111b = 07h ; Backlight on, Power off */ +/* = 1011b = 0Bh ; Backlight off, Power on */ +/* = 1111b = 0Fh ; Backlight off, Power off */ +/* --------------------------------------------------------------------- */ +void XGI_SetPanelPower(USHORT tempah,USHORT tempbl, PVB_DEVICE_INFO pVBInfo) +{ + if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x26 , tempbl , tempah ) ; + else + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x11 , tempbl , tempah ) ; +} + +UCHAR XG21GPIODataTransfer(UCHAR ujDate) +{ + UCHAR ujRet = 0; + UCHAR i = 0; + + for (i=0; i<8; i++) + { + ujRet = ujRet << 1; + /* ujRet |= GETBITS(ujDate >> i, 0:0); */ + ujRet |= (ujDate >> i) & 1; + } + + return ujRet; +} + +/*----------------------------------------------------------------------------*/ +/* output */ +/* bl[5] : LVDS signal */ +/* bl[1] : LVDS backlight */ +/* bl[0] : LVDS VDD */ +/*----------------------------------------------------------------------------*/ +UCHAR XGI_XG21GetPSCValue(PVB_DEVICE_INFO pVBInfo) +{ + UCHAR CR4A,temp; + + CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ; + XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x23 ) ; /* enable GPIO write */ + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ; + + temp = XG21GPIODataTransfer(temp); + temp &= 0x23; + XGINew_SetReg1( pVBInfo->P3d4 , 0x4A , CR4A ) ; + return temp; +} + +/*----------------------------------------------------------------------------*/ +/* output */ +/* bl[5] : LVDS signal */ +/* bl[1] : LVDS backlight */ +/* bl[0] : LVDS VDD */ +/*----------------------------------------------------------------------------*/ +UCHAR XGI_XG27GetPSCValue(PVB_DEVICE_INFO pVBInfo) +{ + UCHAR CR4A,CRB4,temp; + + CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ; + XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x0C ) ; /* enable GPIO write */ + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ; + + temp &= 0x0C; + temp >>= 2; + XGINew_SetReg1( pVBInfo->P3d4 , 0x4A , CR4A ) ; + CRB4 = XGINew_GetReg1( pVBInfo->P3d4 , 0xB4 ) ; + temp |= ((CRB4&0x04)<<3); + return temp; +} +/*----------------------------------------------------------------------------*/ +/* input */ +/* bl[5] : 1;LVDS signal on */ +/* bl[1] : 1;LVDS backlight on */ +/* bl[0] : 1:LVDS VDD on */ +/* bh: 100000b : clear bit 5, to set bit5 */ +/* 000010b : clear bit 1, to set bit1 */ +/* 000001b : clear bit 0, to set bit0 */ +/*----------------------------------------------------------------------------*/ +void XGI_XG21BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo) +{ + UCHAR CR4A,temp; + + CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ; + tempbh &= 0x23; + tempbl &= 0x23; + XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~tempbh ) ; /* enable GPIO write */ + + if (tempbh&0x20) + { + temp = (tempbl>>4)&0x02; + + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0xB4 , ~0x02 , temp) ; /* CR B4[1] */ + + } + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ; + + temp = XG21GPIODataTransfer(temp); + temp &= ~tempbh; + temp |= tempbl; + XGINew_SetReg1( pVBInfo->P3d4 , 0x48 , temp ) ; +} + +void XGI_XG27BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo) +{ + UCHAR CR4A,temp; + USHORT tempbh0,tempbl0; + + tempbh0 = tempbh; + tempbl0 = tempbl; + tempbh0 &= 0x20; + tempbl0 &= 0x20; + tempbh0 >>= 3; + tempbl0 >>= 3; + + if (tempbh&0x20) + { + temp = (tempbl>>4)&0x02; + + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0xB4 , ~0x02 , temp) ; /* CR B4[1] */ + + } + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0xB4 , ~tempbh0 , tempbl0 ) ; + + CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ; + tempbh &= 0x03; + tempbl &= 0x03; + tempbh <<= 2; + tempbl <<= 2; /* GPIOC,GPIOD */ + XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~tempbh ) ; /* enable GPIO write */ + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x48 , ~tempbh , tempbl ) ; +} + +/* --------------------------------------------------------------------- */ +USHORT XGI_GetLVDSOEMTableIndex(PVB_DEVICE_INFO pVBInfo) +{ + USHORT index ; + + index = XGINew_GetReg1( pVBInfo->P3d4 , 0x36 ) ; + if (index<sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct)) + { + return index; + } + return 0; +} + +/* --------------------------------------------------------------------- */ +/* Function : XGI_XG21SetPanelDelay */ +/* Input : */ +/* Output : */ +/* Description : */ +/* I/P : bl : 1 ; T1 : the duration between CPL on and signal on */ +/* : bl : 2 ; T2 : the duration signal on and Vdd on */ +/* : bl : 3 ; T3 : the duration between CPL off and signal off */ +/* : bl : 4 ; T4 : the duration signal off and Vdd off */ +/* --------------------------------------------------------------------- */ +void XGI_XG21SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo) +{ + USHORT index ; + + index = XGI_GetLVDSOEMTableIndex( pVBInfo ); + if ( tempbl == 1 ) + XGINew_LCD_Wait_Time( pVBInfo->XG21_LVDSCapList[ index ].PSC_S1, pVBInfo ) ; + + if ( tempbl == 2 ) + XGINew_LCD_Wait_Time( pVBInfo->XG21_LVDSCapList[ index ].PSC_S2, pVBInfo ) ; + + if ( tempbl == 3 ) + XGINew_LCD_Wait_Time( pVBInfo->XG21_LVDSCapList[ index ].PSC_S3, pVBInfo ) ; + + if ( tempbl == 4 ) + XGINew_LCD_Wait_Time( pVBInfo->XG21_LVDSCapList[ index ].PSC_S4, pVBInfo ) ; +} + +BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT xres , + yres , + colordepth , + modeflag , + resindex , + lvdstableindex; + + resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ; + if ( ModeNo <= 0x13 ) + { + xres = pVBInfo->StResInfo[ resindex ].HTotal ; + yres = pVBInfo->StResInfo[ resindex ].VTotal ; + modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } + else + { + xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */ + yres = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */ + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex].Ext_ModeFlag ; /* si+St_ModeFlag */ + } + + if ( !( modeflag & Charx8Dot ) ) + { + xres /= 9; + xres *= 8; + } + + if ( ModeNo > 0x13 ) + { + if ( ( ModeNo>0x13 ) && ( modeflag & HalfDCLK ) ) + { + xres *= 2 ; + } + if ( ( ModeNo>0x13 ) && ( modeflag & DoubleScanMode ) ) + { + yres *= 2 ; + } + } + + lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo ); + if ( xres > (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE) ) + return FALSE; + + if ( yres > (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE) ) + return FALSE; + + if ( ModeNo > 0x13 ) + { + if ( ( xres != (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE) ) || + ( yres != (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE)) ) + { + colordepth = XGI_GetColorDepth( ModeNo , ModeIdIndex, pVBInfo ) ; + if ( colordepth > 2 ) + { + return FALSE; + } + } + } + return TRUE; +} + +void XGI_SetXG21FPBits(PVB_DEVICE_INFO pVBInfo) +{ + UCHAR temp; + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ; /* D[0] 1: 18bit */ + temp = ( temp & 1 ) << 6; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x06 , ~0x40 , temp ) ; /* SR06[6] 18bit Dither */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x09 , ~0xc0 , temp | 0x80 ) ; /* SR09[7] enable FP output, SR09[6] 1: sigle 18bits, 0: dual 12bits */ + +} + +void XGI_SetXG27FPBits(PVB_DEVICE_INFO pVBInfo) +{ + UCHAR temp; + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ; /* D[1:0] 01: 18bit, 00: dual 12, 10: single 24 */ + temp = ( temp & 3 ) << 6; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x06 , ~0xc0 , temp & 0x80 ) ; /* SR06[7]0: dual 12/1: single 24 [6] 18bit Dither <= 0 h/w recommend */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x09 , ~0xc0 , temp | 0x80 ) ; /* SR09[7] enable FP output, SR09[6] 1: sigle 18bits, 0: 24bits */ + +} + +void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR temp,Miscdata; + USHORT xres , + yres , + modeflag , + resindex , + lvdstableindex ; + USHORT LVDSHT,LVDSHBS,LVDSHRS,LVDSHRE,LVDSHBE; + USHORT LVDSVT,LVDSVBS,LVDSVRS,LVDSVRE,LVDSVBE; + USHORT value; + + lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo ); + + temp = (UCHAR) ( ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & (LCDPolarity << 8 ) ) >> 8 ); + temp &= LCDPolarity; + Miscdata =(UCHAR) XGINew_GetReg2(pVBInfo->P3cc) ; + + XGINew_SetReg3( pVBInfo->P3c2 , (Miscdata & 0x3F) | temp ) ; + + temp = (UCHAR) ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & LCDPolarity ) ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x80 , temp&0x80 ) ; /* SR35[7] FP VSync polarity */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , ~0x20 , (temp&0x40)>>1 ) ; /* SR30[5] FP HSync polarity */ + + XGI_SetXG21FPBits(pVBInfo); + resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ; + if ( ModeNo <= 0x13 ) + { + xres = pVBInfo->StResInfo[ resindex ].HTotal ; + yres = pVBInfo->StResInfo[ resindex ].VTotal ; + modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } + else + { + xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */ + yres = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */ + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex].Ext_ModeFlag ; /* si+St_ModeFlag */ + } + + if (!( modeflag & Charx8Dot )) + xres = xres * 8 / 9; + + LVDSHT = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHT; + + LVDSHBS = xres + ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE - xres ) / 2 ; + if ( ( ModeNo<=0x13 ) && ( modeflag & HalfDCLK ) ) + { + LVDSHBS -= xres/4 ; + } + if (LVDSHBS > LVDSHT) LVDSHBS -= LVDSHT ; + + LVDSHRS = LVDSHBS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHFP ; + if (LVDSHRS > LVDSHT) LVDSHRS -= LVDSHT ; + + LVDSHRE = LVDSHRS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHSYNC ; + if (LVDSHRE > LVDSHT) LVDSHRE -= LVDSHT ; + + LVDSHBE = LVDSHBS + LVDSHT - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE ; + + LVDSVT = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVT; + + LVDSVBS = yres + ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE - yres ) / 2 ; + if ( ( ModeNo>0x13 ) && ( modeflag & DoubleScanMode ) ) + { + LVDSVBS += yres/2 ; + } + if (LVDSVBS > LVDSVT) LVDSVBS -= LVDSVT ; + + LVDSVRS = LVDSVBS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVFP ; + if (LVDSVRS > LVDSVT) LVDSVRS -= LVDSVT ; + + LVDSVRE = LVDSVRS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVSYNC ; + if (LVDSVRE > LVDSVT) LVDSVRE -= LVDSVT ; + + LVDSVBE = LVDSVBS + LVDSVT - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE ; + + temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , temp & 0x7f ) ; /* Unlock CRTC */ + + if (!( modeflag & Charx8Dot )) + { + XGINew_SetRegOR( pVBInfo->P3c4 , 0x1 , 0x1 ) ; + } + + /* HT SR0B[1:0] CR00 */ + value = ( LVDSHT >> 3 ) - 5; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0x03 , ( value & 0x300 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x0 , (value & 0xFF) ) ; + + /* HBS SR0B[5:4] CR02 */ + value = ( LVDSHBS >> 3 ) - 1; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0x30 , ( value & 0x300 ) >> 4 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x2 , (value & 0xFF) ) ; + + /* HBE SR0C[1:0] CR05[7] CR03[4:0] */ + value = ( LVDSHBE >> 3 ) - 1; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0C , ~0x03 , ( value & 0xC0 ) >> 6 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x05 , ~0x80 , ( value & 0x20 ) << 2 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x03 , ~0x1F , value & 0x1F ) ; + + /* HRS SR0B[7:6] CR04 */ + value = ( LVDSHRS >> 3 ) + 2; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0xC0 , ( value & 0x300 ) >> 2 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x4 , (value & 0xFF) ) ; + + /* Panel HRS SR2F[1:0] SR2E[7:0] */ + value--; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x2F , ~0x03 , ( value & 0x300 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , (value & 0xFF) ) ; + + /* HRE SR0C[2] CR05[4:0] */ + value = ( LVDSHRE >> 3 ) + 2; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0C , ~0x04 , ( value & 0x20 ) >> 3 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x05 , ~0x1F , value & 0x1F ) ; + + /* Panel HRE SR2F[7:2] */ + value--; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x2F , ~0xFC , value << 2 ) ; + + /* VT SR0A[0] CR07[5][0] CR06 */ + value = LVDSVT - 2 ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x01 , ( value & 0x400 ) >> 10 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x20 , ( value & 0x200 ) >> 4 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x01 , ( value & 0x100 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x06 , (value & 0xFF) ) ; + + /* VBS SR0A[2] CR09[5] CR07[3] CR15 */ + value = LVDSVBS - 1 ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x04 , ( value & 0x400 ) >> 8 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x09 , ~0x20 , ( value & 0x200 ) >> 4 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x08 , ( value & 0x100 ) >> 5 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x15 , (value & 0xFF) ) ; + + /* VBE SR0A[4] CR16 */ + value = LVDSVBE - 1; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x10 , ( value & 0x100 ) >> 4 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x16 , (value & 0xFF) ) ; + + /* VRS SR0A[3] CR7[7][2] CR10 */ + value = LVDSVRS - 1 ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x08 , ( value & 0x400 ) >> 7 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x80 , ( value & 0x200 ) >> 2 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x04 , ( value & 0x100 ) >> 6 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x10 , (value & 0xFF) ) ; + + /* Panel VRS SR3F[1:0] SR34[7:0] SR33[0] */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0x03 , ( value & 0x600 ) >> 9 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , (value >> 1) & 0xFF ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x33 , ~0x01 , value & 0x01 ) ; + + /* VRE SR0A[5] CR11[3:0] */ + value = LVDSVRE - 1; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x20 , ( value & 0x10 ) << 1 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x11 , ~0x0F , value & 0x0F ) ; + + /* Panel VRE SR3F[7:2] */ /* SR3F[7] has to be 0, h/w bug */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0xFC , ( value << 2 ) & 0x7C ) ; + + for ( temp=0, value = 0; temp < 3; temp++) + { + + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x31 , ~0x30 , value ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData1) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData2) ; + value += 0x10; + } + + if (!( modeflag & Charx8Dot )) + { + XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */ + XGINew_SetReg3( pVBInfo->P3c0 , 0x13 ) ; /* set index */ + XGINew_SetReg3( pVBInfo->P3c0 , 0x00 ) ; /* set data, panning = 0, shift left 1 dot*/ + + XGINew_GetReg2( pVBInfo->P3da ) ; /* Enable Attribute */ + XGINew_SetReg3( pVBInfo->P3c0 , 0x20 ) ; + + XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */ + } + + +} + +/* no shadow case */ +void XGI_SetXG27LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR temp,Miscdata; + USHORT xres , + yres , + modeflag , + resindex , + lvdstableindex ; + USHORT LVDSHT,LVDSHBS,LVDSHRS,LVDSHRE,LVDSHBE; + USHORT LVDSVT,LVDSVBS,LVDSVRS,LVDSVRE,LVDSVBE; + USHORT value; + + lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo ); + temp = (UCHAR) ( ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & (LCDPolarity << 8 ) ) >> 8 ); + temp &= LCDPolarity; + Miscdata =(UCHAR) XGINew_GetReg2(pVBInfo->P3cc) ; + + XGINew_SetReg3( pVBInfo->P3c2 , (Miscdata & 0x3F) | temp ) ; + + temp = (UCHAR) ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & LCDPolarity ) ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x80 , temp&0x80 ) ; /* SR35[7] FP VSync polarity */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , ~0x20 , (temp&0x40)>>1 ) ; /* SR30[5] FP HSync polarity */ + + XGI_SetXG27FPBits(pVBInfo); + resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ; + if ( ModeNo <= 0x13 ) + { + xres = pVBInfo->StResInfo[ resindex ].HTotal ; + yres = pVBInfo->StResInfo[ resindex ].VTotal ; + modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } + else + { + xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */ + yres = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */ + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex].Ext_ModeFlag ; /* si+St_ModeFlag */ + } + + if (!( modeflag & Charx8Dot )) + xres = xres * 8 / 9; + + LVDSHT = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHT; + + LVDSHBS = xres + ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE - xres ) / 2 ; + if ( ( ModeNo<=0x13 ) && ( modeflag & HalfDCLK ) ) + { + LVDSHBS -= xres/4 ; + } + if (LVDSHBS > LVDSHT) LVDSHBS -= LVDSHT ; + + LVDSHRS = LVDSHBS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHFP ; + if (LVDSHRS > LVDSHT) LVDSHRS -= LVDSHT ; + + LVDSHRE = LVDSHRS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHSYNC ; + if (LVDSHRE > LVDSHT) LVDSHRE -= LVDSHT ; + + LVDSHBE = LVDSHBS + LVDSHT - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE ; + + LVDSVT = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVT; + + LVDSVBS = yres + ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE - yres ) / 2 ; + if ( ( ModeNo>0x13 ) && ( modeflag & DoubleScanMode ) ) + { + LVDSVBS += yres/2 ; + } + if (LVDSVBS > LVDSVT) LVDSVBS -= LVDSVT ; + + LVDSVRS = LVDSVBS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVFP ; + if (LVDSVRS > LVDSVT) LVDSVRS -= LVDSVT ; + + LVDSVRE = LVDSVRS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVSYNC ; + if (LVDSVRE > LVDSVT) LVDSVRE -= LVDSVT ; + + LVDSVBE = LVDSVBS + LVDSVT - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE ; + + temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , temp & 0x7f ) ; /* Unlock CRTC */ + + if (!( modeflag & Charx8Dot )) + { + XGINew_SetRegOR( pVBInfo->P3c4 , 0x1 , 0x1 ) ; + } + + /* HT SR0B[1:0] CR00 */ + value = ( LVDSHT >> 3 ) - 5; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0x03 , ( value & 0x300 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x0 , (value & 0xFF) ) ; + + /* HBS SR0B[5:4] CR02 */ + value = ( LVDSHBS >> 3 ) - 1; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0x30 , ( value & 0x300 ) >> 4 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x2 , (value & 0xFF) ) ; + + /* HBE SR0C[1:0] CR05[7] CR03[4:0] */ + value = ( LVDSHBE >> 3 ) - 1; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0C , ~0x03 , ( value & 0xC0 ) >> 6 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x05 , ~0x80 , ( value & 0x20 ) << 2 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x03 , ~0x1F , value & 0x1F ) ; + + /* HRS SR0B[7:6] CR04 */ + value = ( LVDSHRS >> 3 ) + 2; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0xC0 , ( value & 0x300 ) >> 2 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x4 , (value & 0xFF) ) ; + + /* Panel HRS SR2F[1:0] SR2E[7:0] */ + value--; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x2F , ~0x03 , ( value & 0x300 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , (value & 0xFF) ) ; + + /* HRE SR0C[2] CR05[4:0] */ + value = ( LVDSHRE >> 3 ) + 2; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0C , ~0x04 , ( value & 0x20 ) >> 3 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x05 , ~0x1F , value & 0x1F ) ; + + /* Panel HRE SR2F[7:2] */ + value--; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x2F , ~0xFC , value << 2 ) ; + + /* VT SR0A[0] CR07[5][0] CR06 */ + value = LVDSVT - 2 ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x01 , ( value & 0x400 ) >> 10 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x20 , ( value & 0x200 ) >> 4 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x01 , ( value & 0x100 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x06 , (value & 0xFF) ) ; + + /* VBS SR0A[2] CR09[5] CR07[3] CR15 */ + value = LVDSVBS - 1 ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x04 , ( value & 0x400 ) >> 8 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x09 , ~0x20 , ( value & 0x200 ) >> 4 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x08 , ( value & 0x100 ) >> 5 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x15 , (value & 0xFF) ) ; + + /* VBE SR0A[4] CR16 */ + value = LVDSVBE - 1; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x10 , ( value & 0x100 ) >> 4 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x16 , (value & 0xFF) ) ; + + /* VRS SR0A[3] CR7[7][2] CR10 */ + value = LVDSVRS - 1 ; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x08 , ( value & 0x400 ) >> 7 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x80 , ( value & 0x200 ) >> 2 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x04 , ( value & 0x100 ) >> 6 ) ; + XGINew_SetReg1( pVBInfo->P3d4 , 0x10 , (value & 0xFF) ) ; + + /* Panel VRS SR35[2:0] SR34[7:0] */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x07 , ( value & 0x700 ) >> 8 ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , value & 0xFF ) ; + + /* VRE SR0A[5] CR11[3:0] */ + value = LVDSVRE - 1; + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x20 , ( value & 0x10 ) << 1 ) ; + XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x11 , ~0x0F , value & 0x0F ) ; + + /* Panel VRE SR3F[7:2] */ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0xFC , ( value << 2 ) & 0xFC ) ; + + for ( temp=0, value = 0; temp < 3; temp++) + { + + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x31 , ~0x30 , value ) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData1) ; + XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData2) ; + value += 0x10; + } + + if (!( modeflag & Charx8Dot )) + { + XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */ + XGINew_SetReg3( pVBInfo->P3c0 , 0x13 ) ; /* set index */ + XGINew_SetReg3( pVBInfo->P3c0 , 0x00 ) ; /* set data, panning = 0, shift left 1 dot*/ + + XGINew_GetReg2( pVBInfo->P3da ) ; /* Enable Attribute */ + XGINew_SetReg3( pVBInfo->P3c0 , 0x20 ) ; + + XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */ + } + + +} + +/* --------------------------------------------------------------------- */ +/* Function : XGI_IsLCDON */ +/* Input : */ +/* Output : FALSE : Skip PSC Control */ +/* TRUE: Disable PSC */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_IsLCDON(PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempax ; + + tempax = pVBInfo->VBInfo ; + if ( tempax & SetCRT2ToDualEdge ) + return FALSE ; + else if ( tempax & ( DisableCRT2Display | SwitchToCRT2 | SetSimuScanMode ) ) + return TRUE ; + + return FALSE ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_EnablePWD */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_EnablePWD( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT index , + temp ; + + index = XGI_GetLCDCapPtr(pVBInfo) ; + temp = pVBInfo->LCDCapList[ index ].PWD_2B ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x2B , temp ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x2C , pVBInfo->LCDCapList[ index ].PWD_2C ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x2D , pVBInfo->LCDCapList[ index ].PWD_2D ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x2E , pVBInfo->LCDCapList[ index ].PWD_2E ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x2F , pVBInfo->LCDCapList[ index ].PWD_2F ) ; + XGINew_SetRegOR( pVBInfo->Part4Port , 0x27 , 0x80 ) ; /* enable PWD */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_DisablePWD */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_DisablePWD( PVB_DEVICE_INFO pVBInfo ) +{ + XGINew_SetRegAND( pVBInfo->Part4Port , 0x27 , 0x7F ) ; /* disable PWD */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_DisableChISLCD */ +/* Input : */ +/* Output : FALSE -> Not LCD Mode */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_DisableChISLCD(PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempbx , + tempah ; + + tempbx = pVBInfo->SetFlag & ( DisableChA | DisableChB ) ; + tempah = ~( ( USHORT )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ) ; + + if ( tempbx & ( EnableChA | DisableChA ) ) + { + if ( !( tempah & 0x08 ) ) /* Chk LCDA Mode */ + return FALSE ; + } + + if ( !( tempbx & ( EnableChB | DisableChB ) ) ) + return FALSE ; + + if ( tempah & 0x01 ) /* Chk LCDB Mode */ + return TRUE ; + + return FALSE ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_EnableChISLCD */ +/* Input : */ +/* Output : 0 -> Not LCD mode */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_EnableChISLCD(PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempbx , + tempah ; + + + tempbx = pVBInfo->SetFlag & ( EnableChA | EnableChB ) ; + tempah = ~( ( USHORT )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ) ; + + if ( tempbx & ( EnableChA | DisableChA ) ) + { + if ( !( tempah & 0x08 ) ) /* Chk LCDA Mode */ + return FALSE ; + } + + if ( !( tempbx & ( EnableChB | DisableChB ) ) ) + return FALSE ; + + if ( tempah & 0x01 ) /* Chk LCDB Mode */ + return TRUE ; + + return FALSE ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetLCDCapPtr */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGI_GetLCDCapPtr( PVB_DEVICE_INFO pVBInfo ) +{ + UCHAR tempal , + tempah , + tempbl , + i ; + + tempah = XGINew_GetReg1( pVBInfo->P3d4 , 0x36 ) ; + tempal = tempah & 0x0F ; + tempah = tempah & 0xF0 ; + i = 0 ; + tempbl = pVBInfo->LCDCapList[ i ].LCD_ID ; + + while( tempbl != 0xFF ) + { + if ( tempbl & 0x80 ) /* OEMUtil */ + { + tempal = tempah ; + tempbl = tempbl & ~( 0x80 ) ; + } + + if ( tempal == tempbl ) + break ; + + i++ ; + + tempbl = pVBInfo->LCDCapList[ i ].LCD_ID ; + } + + return i ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetLCDCapPtr1 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGI_GetLCDCapPtr1( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempah , + tempal , + tempbl , + i ; + + tempal = pVBInfo->LCDResInfo ; + tempah = pVBInfo->LCDTypeInfo ; + + i = 0 ; + tempbl = pVBInfo->LCDCapList[ i ].LCD_ID; + + while( tempbl != 0xFF ) + { + if ( ( tempbl & 0x80 ) && ( tempbl != 0x80 ) ) + { + tempal = tempah ; + tempbl &= ~0x80 ; + } + + if ( tempal == tempbl ) + break ; + + i++ ; + tempbl = pVBInfo->LCDCapList[ i ].LCD_ID ; + } + + if ( tempbl == 0xFF ) + { + pVBInfo->LCDResInfo = Panel1024x768 ; + pVBInfo->LCDTypeInfo = 0 ; + i = 0 ; + } + + return i ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetLCDSync */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetLCDSync( USHORT* HSyncWidth , USHORT* VSyncWidth, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT Index ; + + Index = XGI_GetLCDCapPtr(pVBInfo) ; + *HSyncWidth = pVBInfo->LCDCapList[ Index ].LCD_HSyncWidth ; + *VSyncWidth = pVBInfo->LCDCapList[ Index ].LCD_VSyncWidth ; + + return ; +} + + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_EnableBridge */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_EnableBridge( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempbl , + tempah ; + + if ( pVBInfo->SetFlag == Win9xDOSMode ) + { + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + XGI_DisplayOn( HwDeviceExtension, pVBInfo) ; + return ; + } + else /* LVDS or CH7017 */ + return ; + } + + + if ( HwDeviceExtension->jChipType < XG40 ) + { + if ( !XGI_DisableChISLCD(pVBInfo) ) + { + if ( ( XGI_EnableChISLCD(pVBInfo) ) || ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) ) + { + if ( pVBInfo->LCDInfo & SetPWDEnable ) + { + XGI_EnablePWD( pVBInfo); + } + else + { + pVBInfo->LCDInfo &= ( ~SetPWDEnable ) ; + if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + tempbl = 0xFD ; + tempah = 0x02 ; + } + else + { + tempbl = 0xFB ; + tempah = 0x00 ; + } + + XGI_SetPanelPower( tempah , tempbl, pVBInfo ) ; + XGI_SetPanelDelay( 1,pVBInfo ) ; + } + } + } + } /* Not 340 */ + + + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( !( pVBInfo->SetFlag & DisableChA ) ) + { + if ( pVBInfo->SetFlag & EnableChA ) + { + XGINew_SetReg1( pVBInfo->Part1Port , 0x1E , 0x20 ) ; /* Power on */ + } + else + { + if ( pVBInfo->VBInfo & SetCRT2ToDualEdge ) /* SetCRT2ToLCDA ) */ + { + XGINew_SetReg1(pVBInfo->Part1Port,0x1E,0x20); /* Power on */ + } + } + } + + if ( !( pVBInfo->SetFlag & DisableChB ) ) + { + if ( ( pVBInfo->SetFlag & EnableChB ) || ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToTV | SetCRT2ToRAMDAC ) ) ) + { + tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x32 ) ; + tempah &= 0xDF; + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + if ( !( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) ) + tempah |= 0x20 ; + } + XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , tempah ) ; + XGINew_SetRegOR( pVBInfo->P3c4 , 0x1E , 0x20 ) ; + + + tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ; + + if ( !( tempah & 0x80 ) ) + XGINew_SetRegOR( pVBInfo->Part1Port , 0x2E , 0x80 ) ; /* BVBDOENABLE = 1 */ + + XGINew_SetRegAND( pVBInfo->Part1Port , 0x00 , 0x7F ) ; /* BScreenOFF = 0 */ + } + } + + if ( ( pVBInfo->SetFlag & ( EnableChA | EnableChB ) ) || ( !( pVBInfo->VBInfo & DisableCRT2Display ) ) ) + { + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x00 , ~0xE0 , 0x20 ) ; /* shampoo 0129 */ + if ( pVBInfo->VBType & ( VB_XGI302LV | VB_XGI301C ) ) + { + if ( !XGI_DisableChISLCD(pVBInfo) ) + { + if ( XGI_EnableChISLCD( pVBInfo) || ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) ) + XGINew_SetRegAND( pVBInfo->Part4Port ,0x2A , 0x7F ) ; /* LVDS PLL power on */ + } + XGINew_SetRegAND( pVBInfo->Part4Port , 0x30 , 0x7F ) ; /* LVDS Driver power on */ + } + } + + tempah = 0x00 ; + + if ( !( pVBInfo->VBInfo & DisableCRT2Display ) ) + { + tempah = 0xc0 ; + + if ( !( pVBInfo->VBInfo & SetSimuScanMode ) ) + { + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + { + if ( pVBInfo->VBInfo & SetCRT2ToDualEdge ) + { + tempah = tempah & 0x40; + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + tempah = tempah ^ 0xC0 ; + + if ( pVBInfo->SetFlag & DisableChB ) + tempah &= 0xBF ; + + if ( pVBInfo->SetFlag & DisableChA ) + tempah &= 0x7F ; + + if ( pVBInfo->SetFlag & EnableChB ) + tempah |= 0x40 ; + + if ( pVBInfo->SetFlag & EnableChA ) + tempah |= 0x80 ; + } + } + } + } + + XGINew_SetRegOR( pVBInfo->Part4Port , 0x1F , tempah ) ; /* EnablePart4_1F */ + + if ( pVBInfo->SetFlag & Win9xDOSMode ) + { + XGI_DisplayOn( HwDeviceExtension, pVBInfo) ; + return ; + } + + if ( !( pVBInfo->SetFlag & DisableChA ) ) + { + XGI_VBLongWait( pVBInfo) ; + if ( !( pVBInfo->SetFlag & GatingCRT ) ) + { + XGI_DisableGatingCRT( HwDeviceExtension, pVBInfo ) ; + XGI_DisplayOn( HwDeviceExtension, pVBInfo) ; + XGI_VBLongWait( pVBInfo) ; + } + } + } /* 301 */ + else /* LVDS */ + { + if ( pVBInfo->VBInfo & ( SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA ) ) + XGINew_SetRegOR( pVBInfo->Part1Port , 0x1E , 0x20 ) ; /* enable CRT2 */ + + + + tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ; + if ( !( tempah & 0x80 ) ) + XGINew_SetRegOR( pVBInfo->Part1Port , 0x2E , 0x80 ) ; /* BVBDOENABLE = 1 */ + + XGINew_SetRegAND(pVBInfo->Part1Port,0x00,0x7F); + XGI_DisplayOn( HwDeviceExtension, pVBInfo); + } /* End of VB */ + + + if ( HwDeviceExtension->jChipType < XG40 ) + { + if ( !XGI_EnableChISLCD(pVBInfo) ) + { + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + if ( XGI_BacklightByDrv(pVBInfo) ) + return ; + } + else + return ; + } + + if ( pVBInfo->LCDInfo & SetPWDEnable ) + { + XGI_FirePWDEnable(pVBInfo) ; + return ; + } + + XGI_SetPanelDelay( 2,pVBInfo ) ; + + if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + tempah = 0x01 ; + tempbl = 0xFE ; /* turn on backlght */ + } + else + { + tempbl = 0xF7 ; + tempah = 0x00 ; + } + XGI_SetPanelPower( tempah , tempbl , pVBInfo) ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_DisableBridge */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_DisableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempax , + tempbx , + tempah = 0 , + tempbl = 0 ; + + if ( pVBInfo->SetFlag == Win9xDOSMode ) + return ; + + + if ( HwDeviceExtension->jChipType < XG40 ) + { + if ( ( !( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) ) || ( XGI_DisableChISLCD(pVBInfo) ) ) + { + if ( !XGI_IsLCDON(pVBInfo) ) + { + if ( pVBInfo->LCDInfo & SetPWDEnable ) + XGI_EnablePWD( pVBInfo) ; + else + { + pVBInfo->LCDInfo &= ~SetPWDEnable ; + XGI_DisablePWD(pVBInfo) ; + if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + tempbx = 0xFE ; /* not 01h */ + tempax = 0 ; + } + else + { + tempbx = 0xF7 ; /* not 08h */ + tempax = 0x08 ; + } + XGI_SetPanelPower( tempax , tempbx , pVBInfo) ; + XGI_SetPanelDelay( 3,pVBInfo ) ; + } + } /* end if(!XGI_IsLCDON(pVBInfo)) */ + } + } + +/* if ( CH7017 ) + { + if ( !( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2toLCDA ) ) || ( XGI_DisableChISLCD(pVBInfo) ) ) + { + if ( !XGI_IsLCDON(pVBInfo) ) + { + if ( DISCHARGE ) + { + tempbx = XGINew_GetCH7005( 0x61 ) ; + if ( tempbx < 0x01 ) //first time we power up + XGINew_SetCH7005( 0x0066 ) ; //and disable power sequence + else + XGINew_SetCH7005( 0x5f66 ) ; //leave VDD on - disable power + } + } + } + } */ + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B| VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + tempah = 0x3F ; + if ( !( pVBInfo->VBInfo & ( DisableCRT2Display | SetSimuScanMode ) ) ) + { + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + { + if ( pVBInfo->VBInfo & SetCRT2ToDualEdge ) + { + tempah = 0x7F; /* Disable Channel A */ + if ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) + tempah = 0xBF ; /* Disable Channel B */ + + if ( pVBInfo->SetFlag & DisableChB ) + tempah &= 0xBF ; /* force to disable Cahnnel */ + + if ( pVBInfo->SetFlag & DisableChA ) + tempah &= 0x7F ; /* Force to disable Channel B */ + } + } + } + + XGINew_SetRegAND( pVBInfo->Part4Port , 0x1F , tempah ) ; /* disable part4_1f */ + + if ( pVBInfo->VBType & ( VB_XGI302LV | VB_XGI301C ) ) + { + if ( ( ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) ) || ( XGI_DisableChISLCD(pVBInfo) ) || ( XGI_IsLCDON(pVBInfo) ) ) + XGINew_SetRegOR( pVBInfo->Part4Port , 0x30 , 0x80 ) ; /* LVDS Driver power down */ + } + + if ( ( pVBInfo->SetFlag & DisableChA ) || ( pVBInfo->VBInfo & ( DisableCRT2Display | SetCRT2ToLCDA | SetSimuScanMode ) ) ) + { + if ( pVBInfo->SetFlag & GatingCRT ) + XGI_EnableGatingCRT( HwDeviceExtension, pVBInfo ) ; + XGI_DisplayOff( HwDeviceExtension, pVBInfo) ; + } + + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + { + if ( ( pVBInfo->SetFlag & DisableChA ) || ( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) + XGINew_SetRegAND( pVBInfo->Part1Port , 0x1e , 0xdf ) ; /* Power down */ + } + + XGINew_SetRegAND( pVBInfo->P3c4 , 0x32 , 0xdf ) ; /* disable TV as primary VGA swap */ + + if ( ( pVBInfo->VBInfo & ( SetSimuScanMode | SetCRT2ToDualEdge ) ) ) + XGINew_SetRegAND(pVBInfo->Part2Port,0x00,0xdf); + + if ( ( pVBInfo->SetFlag & DisableChB ) || ( pVBInfo->VBInfo & ( DisableCRT2Display | SetSimuScanMode ) ) + || ( ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) && ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV ) ) ) ) + XGINew_SetRegOR( pVBInfo->Part1Port , 0x00 , 0x80 ) ; /* BScreenOff=1 */ + + if ( ( pVBInfo->SetFlag & DisableChB ) || ( pVBInfo->VBInfo & ( DisableCRT2Display | SetSimuScanMode ) ) + || ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) || ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV ) ) ) + { + tempah= XGINew_GetReg1( pVBInfo->Part1Port , 0x00 ) ; /* save Part1 index 0 */ + XGINew_SetRegOR( pVBInfo->Part1Port , 0x00 , 0x10 ) ; /* BTDAC = 1, avoid VB reset */ + XGINew_SetRegAND( pVBInfo->Part1Port , 0x1E , 0xDF ) ; /* disable CRT2 */ + XGINew_SetReg1( pVBInfo->Part1Port , 0x00 , tempah ) ; /* restore Part1 index 0 */ + } + } + else /* {301} */ + { + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToTV ) ) + { + XGINew_SetRegOR( pVBInfo->Part1Port , 0x00 , 0x80 ) ; /* BScreenOff=1 */ + XGINew_SetRegAND( pVBInfo->Part1Port , 0x1E , 0xDF ) ; /* Disable CRT2 */ + XGINew_SetRegAND( pVBInfo->P3c4 , 0x32 , 0xDF ) ; /* Disable TV asPrimary VGA swap */ + } + + if ( pVBInfo->VBInfo & ( DisableCRT2Display | SetCRT2ToLCDA | SetSimuScanMode ) ) + XGI_DisplayOff( HwDeviceExtension, pVBInfo) ; + } + + + + + if ( HwDeviceExtension->jChipType < XG40 ) + { + if ( !( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) || ( XGI_DisableChISLCD(pVBInfo) ) || ( XGI_IsLCDON(pVBInfo) ) ) + { + if ( pVBInfo->LCDInfo & SetPWDEnable ) + { + if ( pVBInfo->LCDInfo & SetPWDEnable ) + XGI_BacklightByDrv(pVBInfo) ; + else + { + XGI_SetPanelDelay( 4 ,pVBInfo) ; + if ( pVBInfo->VBType & VB_XGI301LV ) + { + tempbl = 0xFD ; + tempah = 0x00 ; + } + else + { + tempbl = 0xFB ; + tempah = 0x04 ; + } + } + } + XGI_SetPanelPower( tempah , tempbl , pVBInfo) ; + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetTVPtrIndex */ +/* Input : */ +/* Output : */ +/* Description : bx 0 : ExtNTSC */ +/* 1 : StNTSC */ +/* 2 : ExtPAL */ +/* 3 : StPAL */ +/* 4 : ExtHiTV */ +/* 5 : StHiTV */ +/* 6 : Ext525i */ +/* 7 : St525i */ +/* 8 : Ext525p */ +/* 9 : St525p */ +/* A : Ext750p */ +/* B : St750p */ +/* --------------------------------------------------------------------- */ +USHORT XGI_GetTVPtrIndex( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempbx = 0 ; + + if ( pVBInfo->TVInfo & SetPALTV ) + tempbx = 2 ; + if ( pVBInfo->TVInfo & SetYPbPrMode1080i ) + tempbx = 4 ; + if ( pVBInfo->TVInfo & SetYPbPrMode525i ) + tempbx = 6 ; + if ( pVBInfo->TVInfo & SetYPbPrMode525p ) + tempbx = 8 ; + if ( pVBInfo->TVInfo & SetYPbPrMode750p ) + tempbx = 10 ; + if ( pVBInfo->TVInfo & TVSimuMode ) + tempbx++ ; + + return tempbx ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_OEM310Setting */ +/* Input : */ +/* Output : */ +/* Description : Customized Param. for 301 */ +/* --------------------------------------------------------------------- */ +void XGI_OEM310Setting( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo) +{ + if ( pVBInfo->SetFlag & Win9xDOSMode ) + return ; + + /* GetPart1IO(); */ + XGI_SetDelayComp(pVBInfo) ; + + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + XGI_SetLCDCap(pVBInfo) ; + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + /* GetPart2IO() */ + XGI_SetPhaseIncr(pVBInfo) ; + XGI_SetYFilter( ModeNo , ModeIdIndex,pVBInfo ) ; + XGI_SetAntiFlicker( ModeNo , ModeIdIndex,pVBInfo ) ; + + if ( pVBInfo->VBType&VB_XGI301) + XGI_SetEdgeEnhance( ModeNo , ModeIdIndex ,pVBInfo) ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetDelayComp */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetDelayComp( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT index ; + + UCHAR tempah , + tempbl , + tempbh ; + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA | SetCRT2ToTV | SetCRT2ToRAMDAC ) ) + { + tempbl = 0; + tempbh = 0; + + index = XGI_GetTVPtrIndex(pVBInfo ) ; /* Get TV Delay */ + tempbl = pVBInfo->XGI_TVDelayList[ index ] ; + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + tempbl = pVBInfo->XGI_TVDelayList2[ index ] ; + + if ( pVBInfo->VBInfo & SetCRT2ToDualEdge ) + tempbl = tempbl >> 4 ; +/* + if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) + tempbl = CRT2Delay1 ; // Get CRT2 Delay + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + tempbl = CRT2Delay2 ; +*/ + if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + index = XGI_GetLCDCapPtr(pVBInfo) ; /* Get LCD Delay */ + tempbh=pVBInfo->LCDCapList[ index ].LCD_DelayCompensation ; + + if ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) + tempbl = tempbh ; + } + + tempbl &= 0x0F ; + tempbh &= 0xF0 ; + tempah = XGINew_GetReg1( pVBInfo->Part1Port , 0x2D ) ; + + if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV ) ) /* Channel B */ + { + tempah &= 0xF0 ; + tempah |= tempbl ; + } + + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) /* Channel A */ + { + tempah &= 0x0F ; + tempah |= tempbh ; + } + XGINew_SetReg1(pVBInfo->Part1Port,0x2D,tempah); + } + } + else if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + tempbl = 0; + tempbh = 0; + if ( pVBInfo->VBInfo & SetCRT2ToLCD ) + { + tempah = pVBInfo->LCDCapList[ XGI_GetLCDCapPtr(pVBInfo) ].LCD_DelayCompensation ; /* / Get LCD Delay */ + tempah &= 0x0f ; + tempah = tempah << 4 ; + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2D , 0x0f , tempah ) ; + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetLCDCap */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetLCDCap( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempcx ; + + tempcx = pVBInfo->LCDCapList[ XGI_GetLCDCapPtr(pVBInfo) ].LCD_Capability ; + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { /* 301LV/302LV only */ + /* Set 301LV Capability */ + XGINew_SetReg1( pVBInfo->Part4Port , 0x24 , ( UCHAR )( tempcx & 0x1F ) ) ; + } + /* VB Driving */ + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x0D , ~( ( EnableVBCLKDRVLOW | EnablePLLSPLOW ) >> 8 ) , ( USHORT )( ( tempcx & ( EnableVBCLKDRVLOW | EnablePLLSPLOW ) ) >> 8 ) ) ; + } + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( pVBInfo->VBInfo & SetCRT2ToLCD ) + XGI_SetLCDCap_B( tempcx,pVBInfo ) ; + else if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + XGI_SetLCDCap_A( tempcx,pVBInfo ) ; + + if ( pVBInfo->VBType & ( VB_XGI302LV | VB_XGI301C ) ) + { + if ( tempcx & EnableSpectrum ) + SetSpectrum( pVBInfo) ; + } + } + else /* LVDS,CH7017 */ + XGI_SetLCDCap_A( tempcx, pVBInfo ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetLCDCap_A */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetLCDCap_A(USHORT tempcx,PVB_DEVICE_INFO pVBInfo) +{ + USHORT temp ; + + temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ; + + if ( temp & LCDRGB18Bit ) + { + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , 0x0F , ( USHORT )( 0x20 | ( tempcx & 0x00C0 ) ) ) ; /* Enable Dither */ + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x1A , 0x7F , 0x80 ) ; + } + else + { + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , 0x0F , ( USHORT )( 0x30 | ( tempcx & 0x00C0 ) ) ) ; + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x1A , 0x7F , 0x00 ) ; + } + +/* + if ( tempcx & EnableLCD24bpp ) // 24bits + { + XGINew_SetRegANDOR(pVBInfo->Part1Port,0x19, 0x0F,(USHORT)(0x30|(tempcx&0x00C0)) ); + XGINew_SetRegANDOR(pVBInfo->Part1Port,0x1A,0x7F,0x00); + } + else + { + XGINew_SetRegANDOR(pVBInfo->Part1Port,0x19, 0x0F,(USHORT)(0x20|(tempcx&0x00C0)) );//Enable Dither + XGINew_SetRegANDOR(pVBInfo->Part1Port,0x1A,0x7F,0x80); + } +*/ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetLCDCap_B */ +/* Input : cx -> LCD Capability */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetLCDCap_B(USHORT tempcx,PVB_DEVICE_INFO pVBInfo) +{ + if ( tempcx & EnableLCD24bpp ) /* 24bits */ + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x1A , 0xE0 , ( USHORT )( ( ( tempcx & 0x00ff ) >> 6 ) | 0x0c ) ) ; + else + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x1A , 0xE0 , ( USHORT )( ( ( tempcx & 0x00ff ) >> 6 ) | 0x18 ) ) ; /* Enable Dither */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : SetSpectrum */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void SetSpectrum( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT index ; + + index = XGI_GetLCDCapPtr(pVBInfo) ; + + XGINew_SetRegAND( pVBInfo->Part4Port , 0x30 , 0x8F ) ; /* disable down spectrum D[4] */ + XGI_LongWait(pVBInfo) ; + XGINew_SetRegOR( pVBInfo->Part4Port , 0x30 , 0x20 ) ; /* reset spectrum */ + XGI_LongWait(pVBInfo) ; + + XGINew_SetReg1( pVBInfo->Part4Port , 0x31 , pVBInfo->LCDCapList[ index ].Spectrum_31 ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x32 , pVBInfo->LCDCapList[ index ].Spectrum_32 ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x33 , pVBInfo->LCDCapList[ index ].Spectrum_33 ) ; + XGINew_SetReg1( pVBInfo->Part4Port , 0x34 , pVBInfo->LCDCapList[ index ].Spectrum_34 ) ; + XGI_LongWait(pVBInfo) ; + XGINew_SetRegOR( pVBInfo->Part4Port , 0x30 , 0x40 ) ; /* enable spectrum */ +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetAntiFlicker */ +/* Input : */ +/* Output : */ +/* Description : Set TV Customized Param. */ +/* --------------------------------------------------------------------- */ +void XGI_SetAntiFlicker( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempbx , + index ; + + UCHAR tempah ; + + if (pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) + return ; + + tempbx = XGI_GetTVPtrIndex(pVBInfo ) ; + tempbx &= 0xFE ; + + if ( ModeNo <= 0x13 ) + { + index = pVBInfo->SModeIDTable[ ModeIdIndex ].VB_StTVFlickerIndex ; + } + else + { + index = pVBInfo->EModeIDTable[ ModeIdIndex ].VB_ExtTVFlickerIndex ; + } + + tempbx += index ; + tempah = TVAntiFlickList[ tempbx ] ; + tempah = tempah << 4 ; + + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x0A , 0x8F , tempah ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetEdgeEnhance */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetEdgeEnhance( USHORT ModeNo , USHORT ModeIdIndex , PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempbx , + index ; + + UCHAR tempah ; + + + tempbx = XGI_GetTVPtrIndex(pVBInfo ) ; + tempbx &= 0xFE ; + + if ( ModeNo <= 0x13 ) + { + index = pVBInfo->SModeIDTable[ ModeIdIndex ].VB_StTVEdgeIndex ; + } + else + { + index = pVBInfo->EModeIDTable[ ModeIdIndex ].VB_ExtTVEdgeIndex ; + } + + tempbx += index ; + tempah = TVEdgeList[ tempbx ] ; + tempah = tempah << 5 ; + + XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x3A , 0x1F , tempah ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetPhaseIncr */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetPhaseIncr( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempbx ; + + UCHAR tempcl , + tempch ; + + ULONG tempData ; + + XGI_GetTVPtrIndex2( &tempbx , &tempcl , &tempch, pVBInfo ) ; /* bx, cl, ch */ + tempData = TVPhaseList[ tempbx ] ; + + XGINew_SetReg1( pVBInfo->Part2Port , 0x31 , ( USHORT )( tempData & 0x000000FF ) ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x32 , ( USHORT )( ( tempData & 0x0000FF00 ) >> 8 ) ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x33 , ( USHORT )( ( tempData & 0x00FF0000 ) >> 16 ) ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x34 , ( USHORT )( ( tempData & 0xFF000000 ) >> 24 ) ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetYFilter */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_SetYFilter( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempbx , + index ; + + UCHAR tempcl , + tempch , + tempal , + *filterPtr ; + + XGI_GetTVPtrIndex2( &tempbx , &tempcl , &tempch, pVBInfo ) ; /* bx, cl, ch */ + + switch( tempbx ) + { + case 0x00: + case 0x04: + filterPtr = NTSCYFilter1 ; + break ; + + case 0x01: + filterPtr = PALYFilter1 ; + break ; + + case 0x02: + case 0x05: + case 0x0D: + filterPtr = PALMYFilter1 ; + break ; + + case 0x03: + filterPtr = PALNYFilter1 ; + break ; + + case 0x08: + case 0x0C: + filterPtr = NTSCYFilter2 ; + break ; + + case 0x0A: + filterPtr = PALMYFilter2 ; + break ; + + case 0x0B: + filterPtr = PALNYFilter2 ; + break ; + + case 0x09: + filterPtr = PALYFilter2 ; + break ; + + default: + return ; + } + + if ( ModeNo <= 0x13 ) + tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].VB_StTVYFilterIndex ; + else + tempal = pVBInfo->EModeIDTable[ ModeIdIndex ].VB_ExtTVYFilterIndex ; + + if ( tempcl == 0 ) + index = tempal * 4; + else + index = tempal * 7; + + if ( ( tempcl == 0 ) && ( tempch == 1 ) ) + { + XGINew_SetReg1( pVBInfo->Part2Port , 0x35 , 0 ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x36 , 0 ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x37 , 0 ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x38 , filterPtr[ index++ ] ) ; + } + else + { + XGINew_SetReg1( pVBInfo->Part2Port , 0x35 , filterPtr[ index++ ] ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x36 , filterPtr[ index++ ] ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x37 , filterPtr[ index++ ] ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x38 , filterPtr[ index++ ] ) ; + } + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + XGINew_SetReg1( pVBInfo->Part2Port , 0x48 , filterPtr[ index++ ] ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x49 , filterPtr[ index++ ] ) ; + XGINew_SetReg1( pVBInfo->Part2Port , 0x4A , filterPtr[ index++ ] ) ; + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetTVPtrIndex2 */ +/* Input : */ +/* Output : bx 0 : NTSC */ +/* 1 : PAL */ +/* 2 : PALM */ +/* 3 : PALN */ +/* 4 : NTSC1024x768 */ +/* 5 : PAL-M 1024x768 */ +/* 6-7: reserved */ +/* cl 0 : YFilter1 */ +/* 1 : YFilter2 */ +/* ch 0 : 301A */ +/* 1 : 301B/302B/301LV/302LV */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetTVPtrIndex2(USHORT* tempbx,UCHAR* tempcl,UCHAR* tempch, PVB_DEVICE_INFO pVBInfo) +{ + *tempbx = 0 ; + *tempcl = 0 ; + *tempch = 0 ; + + if ( pVBInfo->TVInfo & SetPALTV ) + *tempbx = 1 ; + + if ( pVBInfo->TVInfo & SetPALMTV ) + *tempbx = 2 ; + + if ( pVBInfo->TVInfo & SetPALNTV ) + *tempbx = 3 ; + + if ( pVBInfo->TVInfo & NTSC1024x768 ) + { + *tempbx = 4 ; + if ( pVBInfo->TVInfo & SetPALMTV ) + *tempbx = 5 ; + } + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + if ( ( !( pVBInfo->VBInfo & SetInSlaveMode ) ) || ( pVBInfo->TVInfo & TVSimuMode ) ) + { + *tempbx += 8 ; + *tempcl += 1 ; + } + } + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + (*tempch)++ ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_SetCRT2ModeRegs */ +/* Input : */ +/* Output : */ +/* Description : Origin code for crt2group */ +/* --------------------------------------------------------------------- */ +void XGI_SetCRT2ModeRegs(USHORT ModeNo,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempbl ; + SHORT tempcl ; + + UCHAR tempah ; + + /* XGINew_SetReg1( pVBInfo->Part1Port , 0x03 , 0x00 ) ; // fix write part1 index 0 BTDRAM bit Bug */ + tempah=0; + if ( !( pVBInfo->VBInfo & DisableCRT2Display ) ) + { + tempah=XGINew_GetReg1( pVBInfo->Part1Port , 0x00 ) ; + tempah &= ~0x10 ; /* BTRAMDAC */ + tempah |= 0x40 ; /* BTRAM */ + + if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD ) ) + { + tempah=0x40; /* BTDRAM */ + if ( ModeNo > 0x13 ) + { + tempcl = pVBInfo->ModeType ; + tempcl -= ModeVGA ; + if ( tempcl >= 0 ) + { + tempah = ( 0x008 >> tempcl ) ; /* BT Color */ + if ( tempah == 0 ) + tempah = 1 ; + tempah |= 0x040 ; + } + } + if ( pVBInfo->VBInfo & SetInSlaveMode ) + tempah ^= 0x50 ; /* BTDAC */ + } + } + +/* 0210 shampoo + if ( pVBInfo->VBInfo & DisableCRT2Display ) + { + tempah = 0 ; + } + + XGINew_SetReg1( pVBInfo->Part1Port , 0x00 , tempah ) ; + if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD ) ) + { + tempcl = pVBInfo->ModeType ; + if ( ModeNo > 0x13 ) + { + tempcl -= ModeVGA ; + if ( ( tempcl > 0 ) || ( tempcl == 0 ) ) + { + tempah=(0x008>>tempcl) ; + if ( tempah == 0 ) + tempah = 1 ; + tempah |= 0x040; + } + } + else + { + tempah = 0x040 ; + } + + if ( pVBInfo->VBInfo & SetInSlaveMode ) + { + tempah = ( tempah ^ 0x050 ) ; + } + } +*/ + + XGINew_SetReg1( pVBInfo->Part1Port , 0x00 , tempah ) ; + tempah = 0x08 ; + tempbl = 0xf0 ; + + if ( pVBInfo->VBInfo & DisableCRT2Display ) + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2e , tempbl , tempah ) ; + else + { + tempah = 0x00 ; + tempbl = 0xff ; + + if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + if ( ( pVBInfo->VBInfo & SetCRT2ToLCDA ) && ( !( pVBInfo->VBInfo & SetSimuScanMode ) ) ) + { + tempbl &= 0xf7 ; + tempah |= 0x01 ; + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2e , tempbl , tempah ) ; + } + else + { + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + { + tempbl &= 0xf7 ; + tempah |= 0x01 ; + } + + if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD ) ) + { + tempbl &= 0xf8 ; + tempah = 0x01 ; + + if ( !( pVBInfo->VBInfo & SetInSlaveMode ) ) + tempah |= 0x02 ; + + if ( !( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) ) + { + tempah = tempah ^ 0x05 ; + if ( !( pVBInfo->VBInfo & SetCRT2ToLCD ) ) + tempah = tempah ^ 0x01 ; + } + + if ( !( pVBInfo->VBInfo & SetCRT2ToDualEdge ) ) + tempah |= 0x08 ; + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2e , tempbl , tempah ) ; + } + else + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2e , tempbl , tempah ) ; + } + } + else + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2e , tempbl , tempah ) ; + } + + if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA ) ) + { + tempah &= ( ~0x08 ) ; + if ( ( pVBInfo->ModeType == ModeVGA ) && ( !( pVBInfo->VBInfo & SetInSlaveMode ) ) ) + { + tempah |= 0x010 ; + } + tempah |= 0x080 ; + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + /* if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) ) */ + /* { */ + tempah |= 0x020 ; + if ( ModeNo > 0x13 ) + { + if ( pVBInfo->VBInfo & DriverMode ) + tempah = tempah ^ 0x20 ; + } + /* } */ + } + + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x0D , ~0x0BF , tempah ) ; + tempah = 0 ; + + if ( pVBInfo->LCDInfo & SetLCDDualLink ) + tempah |= 0x40 ; + + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + /* if ( ( !( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) ) && ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) ) ) */ + /* { */ + if ( pVBInfo->TVInfo & RPLLDIV2XO ) + tempah |= 0x40 ; + /* } */ + } + + if ( ( pVBInfo->LCDResInfo == Panel1280x1024 ) || ( pVBInfo->LCDResInfo == Panel1280x1024x75 ) ) + tempah |= 0x80 ; + + if ( pVBInfo->LCDResInfo == Panel1280x960 ) + tempah |= 0x80 ; + + XGINew_SetReg1( pVBInfo->Part4Port , 0x0C , tempah ) ; + } + + if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) + { + tempah = 0 ; + tempbl = 0xfb ; + + if ( pVBInfo->VBInfo & SetCRT2ToDualEdge ) + { + tempbl=0xff; + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + tempah |= 0x04 ; /* shampoo 0129 */ + } + + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x13 , tempbl , tempah ) ; + tempah = 0x00 ; + tempbl = 0xcf ; + if ( !( pVBInfo->VBInfo & DisableCRT2Display ) ) + { + if ( pVBInfo->VBInfo & SetCRT2ToDualEdge ) + tempah |= 0x30 ; + } + + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2c , tempbl , tempah ) ; + tempah = 0 ; + tempbl = 0x3f ; + + if ( !( pVBInfo->VBInfo & DisableCRT2Display ) ) + { + if ( pVBInfo->VBInfo & SetCRT2ToDualEdge ) + tempah |= 0xc0 ; + } + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x21 , tempbl , tempah ) ; + } + + tempah = 0 ; + tempbl = 0x7f ; + if ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) + { + tempbl = 0xff ; + if ( !( pVBInfo->VBInfo & SetCRT2ToDualEdge ) ) + tempah |= 0x80 ; + } + + XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x23 , tempbl , tempah ) ; + + if ( pVBInfo->VBType & ( VB_XGI302LV | VB_XGI301C ) ) + { + if ( pVBInfo->LCDInfo & SetLCDDualLink ) + { + XGINew_SetRegOR( pVBInfo->Part4Port , 0x27 , 0x20 ) ; + XGINew_SetRegOR( pVBInfo->Part4Port , 0x34 , 0x10 ) ; + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_CloseCRTC */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_CloseCRTC( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempbx ; + + tempbx = 0 ; + + if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) + tempbx = 0x08A0 ; + + +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_OpenCRTC */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_OpenCRTC( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempbx ; + + tempbx = 0 ; + + +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetRAMDAC2DATA */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_GetRAMDAC2DATA(USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempax , + tempbx , + temp1 , + temp2 , + modeflag = 0 , + tempcx , + StandTableIndex , + CRT1Index ; + + pVBInfo->RVBHCMAX = 1 ; + pVBInfo->RVBHCFACT = 1 ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + StandTableIndex = XGI_GetModePtr( ModeNo , ModeIdIndex, pVBInfo ) ; + tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 0 ] ; + tempbx = pVBInfo->StandTable[StandTableIndex ].CRTC[ 6 ] ; + temp1 = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 7 ] ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ; + CRT1Index &= IndexMask ; + temp1 = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 0 ] ; + temp2 = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 5 ] ; + tempax = ( temp1 & 0xFF ) | ( ( temp2 & 0x03 ) << 8 ) ; + tempbx = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 8 ] ; + tempcx = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 14 ] << 8 ; + tempcx &= 0x0100 ; + tempcx = tempcx << 2 ; + tempbx |= tempcx; + temp1 = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 9 ] ; + } + + if ( temp1 & 0x01 ) + tempbx |= 0x0100 ; + + if ( temp1 & 0x20 ) + tempbx |= 0x0200 ; + tempax += 5 ; + + if ( modeflag & Charx8Dot ) + tempax *= 8 ; + else + tempax *= 9 ; + + pVBInfo->VGAHT = tempax ; + pVBInfo->HT = tempax ; + tempbx++ ; + pVBInfo->VGAVT = tempbx ; + pVBInfo->VT = tempbx ; +} + + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetColorDepth */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGI_GetColorDepth(USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo) +{ + USHORT ColorDepth[ 6 ] = { 1 , 2 , 4 , 4 , 6 , 8 } ; + SHORT index ; + USHORT modeflag ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; + } + + index=(modeflag&ModeInfoFlag)-ModeEGA; + + if ( index < 0 ) + index = 0 ; + + return( ColorDepth[ index ] ) ; +} + + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_UnLockCRT2 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_UnLockCRT2( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo ) +{ + + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2f , 0xFF , 0x01 ) ; + +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_LockCRT2 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_LockCRT2( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo ) +{ + + XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2F , 0xFE , 0x00 ) ; + + +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_EnableCRT2 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_EnableCRT2( PVB_DEVICE_INFO pVBInfo) +{ + XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x1E , 0xFF , 0x20 ) ; +} + + + +/* --------------------------------------------------------------------- */ +/* Function : */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_LCD_Wait_Time(UCHAR DelayTime, PVB_DEVICE_INFO pVBInfo) +{ + USHORT i , + j ; + + ULONG temp , + flag ; + + flag = 0 ; +//printk("XGINew_LCD_Wait_Time"); +//return; + for( i = 0 ; i < DelayTime ; i++ ) + { + for( j = 0 ; j < 66 ; j++ ) + { + + temp = XGINew_GetReg3( 0x61 ) ; + + //temp &= 0x10000000; + temp &= 0x10; + if ( temp == flag ) + continue ; + + flag = temp ; + } + } +} + + + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_BridgeIsOn */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +BOOLEAN XGI_BridgeIsOn( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT flag ; + + if ( pVBInfo->IF_DEF_LVDS == 1 ) + { + return( 1 ) ; + } + else + { + flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x00 ) ; + if ( ( flag == 1 ) || ( flag == 2 ) ) + return( 1 ) ; /* 301b */ + else + return( 0 ) ; + } +} + + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_LongWait */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_LongWait(PVB_DEVICE_INFO pVBInfo) +{ + USHORT i ; + + i = XGINew_GetReg1( pVBInfo->P3c4 , 0x1F ) ; + + if ( !( i & 0xC0 ) ) + { + for( i = 0 ; i < 0xFFFF ; i++ ) + { + if ( !( XGINew_GetReg2( pVBInfo->P3da ) & 0x08 ) ) + break ; + } + + for( i = 0 ; i < 0xFFFF ; i++ ) + { + if ( ( XGINew_GetReg2( pVBInfo->P3da ) & 0x08 ) ) + break ; + } + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_VBLongWait */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGI_VBLongWait( PVB_DEVICE_INFO pVBInfo ) +{ + USHORT tempal , + temp , + i , + j ; +return ; + if ( !( pVBInfo->VBInfo & SetCRT2ToTV ) ) + { + temp = 0 ; + for( i = 0 ; i < 3 ; i++ ) + { + for( j = 0 ; j < 100 ; j++ ) + { + tempal = XGINew_GetReg2( pVBInfo->P3da ) ; + if ( temp & 0x01 ) + { /* VBWaitMode2 */ + if ( ( tempal & 0x08 ) ) + { + continue ; + } + + if ( !( tempal & 0x08 ) ) + { + break ; + } + } + else + { /* VBWaitMode1 */ + if ( !( tempal & 0x08 ) ) + { + continue ; + } + + if ( ( tempal & 0x08 ) ) + { + break ; + } + } + } + temp = temp ^ 0x01 ; + } + } + else + { + XGI_LongWait(pVBInfo) ; + } + return ; +} + + + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetVGAHT2 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGI_GetVGAHT2( PVB_DEVICE_INFO pVBInfo ) +{ + ULONG tempax , + tempbx ; + + tempbx = ( ( pVBInfo->VGAVT - pVBInfo->VGAVDE ) * pVBInfo->RVBHCMAX ) & 0xFFFF ; + tempax = ( pVBInfo->VT - pVBInfo->VDE ) * pVBInfo->RVBHCFACT ; + tempax = ( tempax * pVBInfo->HT ) /tempbx ; + + return( ( USHORT )tempax ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGI_GetVCLK2Ptr */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +USHORT XGI_GetVCLK2Ptr( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE_INFO pVBInfo) +{ + USHORT tempbx ; + + USHORT LCDXlat1VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ; + USHORT LCDXlat2VCLK[ 4 ] = { VCLK108_2 + 5 , VCLK108_2 + 5 , VCLK108_2 + 5 , VCLK108_2 + 5 } ; + USHORT LVDSXlat1VCLK[ 4 ] = { VCLK40 , VCLK40 , VCLK40 , VCLK40 } ; + USHORT LVDSXlat2VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ; + USHORT LVDSXlat3VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ; + + USHORT CRT2Index , VCLKIndex ; + USHORT modeflag , resinfo ; + UCHAR *CHTVVCLKPtr = NULL ; + + if ( ModeNo <= 0x13 ) + { + modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */ + resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; + CRT2Index = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ; + } + else + { + modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */ + resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; + CRT2Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC ; + } + + if ( pVBInfo->IF_DEF_LVDS == 0 ) + { + CRT2Index = CRT2Index >> 6 ; /* for LCD */ + if ( ( ( pVBInfo->VBInfo & SetCRT2ToLCD ) | SetCRT2ToLCDA ) ) /*301b*/ + { + if ( pVBInfo->LCDResInfo != Panel1024x768 ) + { + VCLKIndex = LCDXlat2VCLK[ CRT2Index ] ; + } + else + { + VCLKIndex = LCDXlat1VCLK[ CRT2Index ] ; + } + } + else /* for TV */ + { + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) + { + if ( pVBInfo->SetFlag & RPLLDIV2XO ) + { + VCLKIndex = HiTVVCLKDIV2 ; + + + VCLKIndex += 25 ; + + } + else + { + VCLKIndex = HiTVVCLK ; + + + VCLKIndex += 25 ; + + } + + if ( pVBInfo->SetFlag & TVSimuMode ) + { + if( modeflag & Charx8Dot ) + { + VCLKIndex = HiTVSimuVCLK ; + + + VCLKIndex += 25 ; + + } + else + { + VCLKIndex = HiTVTextVCLK ; + + + VCLKIndex += 25 ; + + } + } + + if ( pVBInfo->VBType & VB_XGI301LV ) /* 301lv */ + { + if ( !( pVBInfo->VBExtInfo == VB_YPbPr1080i ) ) + { + VCLKIndex = YPbPr750pVCLK ; + if ( !( pVBInfo->VBExtInfo == VB_YPbPr750p ) ) + { + VCLKIndex = YPbPr525pVCLK ; + if ( !( pVBInfo->VBExtInfo == VB_YPbPr525p ) ) + { + VCLKIndex = YPbPr525iVCLK_2 ; + if ( !( pVBInfo->SetFlag & RPLLDIV2XO ) ) + VCLKIndex = YPbPr525iVCLK ; + } + } + } + } + } + else + { + if ( pVBInfo->VBInfo & SetCRT2ToTV ) + { + if ( pVBInfo->SetFlag & RPLLDIV2XO ) + { + VCLKIndex = TVVCLKDIV2 ; + + + VCLKIndex += 25 ; + + } + else + { + VCLKIndex = TVVCLK ; + + + VCLKIndex += 25 ; + + } + } + } + } + else + { /* for CRT2 */ + VCLKIndex = ( UCHAR )XGINew_GetReg2( ( pVBInfo->P3ca + 0x02 ) ) ; /* Port 3cch */ + VCLKIndex = ( ( VCLKIndex >> 2 ) & 0x03 ) ; + if ( ModeNo > 0x13 ) + { + VCLKIndex = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRTVCLK ; /* di+Ext_CRTVCLK */ + VCLKIndex &= IndexMask ; + } + } + } + } + else + { /* LVDS */ + if ( ModeNo <= 0x13 ) + VCLKIndex = CRT2Index ; + else + VCLKIndex = CRT2Index ; + + if ( pVBInfo->IF_DEF_CH7005 == 1 ) + { + if ( !( pVBInfo->VBInfo & SetCRT2ToLCD ) ) + { + VCLKIndex &= 0x1f ; + tempbx = 0 ; + + if ( pVBInfo->VBInfo & SetPALTV ) + tempbx += 2 ; + + if ( pVBInfo->VBInfo & SetCHTVOverScan ) + tempbx += 1 ; + + switch( tempbx ) + { + case 0: + CHTVVCLKPtr = pVBInfo->CHTVVCLKUNTSC ; + break ; + case 1: + CHTVVCLKPtr = pVBInfo->CHTVVCLKONTSC ; + break; + case 2: + CHTVVCLKPtr = pVBInfo->CHTVVCLKUPAL ; + break ; + case 3: + CHTVVCLKPtr = pVBInfo->CHTVVCLKOPAL ; + break ; + default: + break ; + } + + VCLKIndex = CHTVVCLKPtr[ VCLKIndex ] ; + } + } + else + { + VCLKIndex = VCLKIndex >> 6 ; + if ( ( pVBInfo->LCDResInfo == Panel800x600 ) || ( pVBInfo->LCDResInfo == Panel320x480 ) ) + VCLKIndex = LVDSXlat1VCLK[ VCLKIndex ] ; + else if ( ( pVBInfo->LCDResInfo == Panel1024x768 ) || ( pVBInfo->LCDResInfo == Panel1024x768x75 ) ) + VCLKIndex = LVDSXlat2VCLK[ VCLKIndex ] ; + else + VCLKIndex = LVDSXlat3VCLK[ VCLKIndex ] ; + } + } + /* VCLKIndex = VCLKIndex&IndexMask ; */ + + + + return( VCLKIndex ) ; +} + diff --git a/drivers/staging/xgifb/vb_setmode.h b/drivers/staging/xgifb/vb_setmode.h new file mode 100644 index 000000000000..09753d706665 --- /dev/null +++ b/drivers/staging/xgifb/vb_setmode.h @@ -0,0 +1,40 @@ +#ifndef _VBSETMODE_ +#define _VBSETMODE_ + +extern void InitTo330Pointer(UCHAR,PVB_DEVICE_INFO); +extern void XGI_UnLockCRT2(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO ); +extern void XGI_LockCRT2(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO ); +extern void XGI_LongWait( PVB_DEVICE_INFO ); +extern void XGI_SetCRT2ModeRegs(USHORT ModeNo,PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO ); +extern void XGI_DisableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO ); +extern void XGI_EnableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO ); +extern void XGI_DisplayOff( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO ); +extern void XGI_DisplayOn( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO ); +extern void XGI_GetVBType(PVB_DEVICE_INFO); +extern void XGI_SenseCRT1(PVB_DEVICE_INFO ); +extern void XGI_GetVGAType(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO ); +extern void XGI_GetVBInfo(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO ); +extern void XGI_GetTVInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO ); +extern void XGI_SetCRT1Offset(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO ); +extern void XGI_SetLCDAGroup(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO ); +extern void XGI_WaitDisply( PVB_DEVICE_INFO ); +extern USHORT XGI_GetResInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo); + +extern BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo ) ; + +extern BOOLEAN XGI_SearchModeID( USHORT ModeNo,USHORT *ModeIdIndex, PVB_DEVICE_INFO ); +extern BOOLEAN XGI_GetLCDInfo(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO ); +extern BOOLEAN XGI_BridgeIsOn( PVB_DEVICE_INFO ); +extern BOOLEAN XGI_SetCRT2Group301(USHORT ModeNo, PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO); +extern USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO ); + +extern void XGI_SetXG21FPBits(PVB_DEVICE_INFO pVBInfo); +extern void XGI_SetXG27FPBits(PVB_DEVICE_INFO pVBInfo); +extern void XGI_XG21BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo); +extern void XGI_XG27BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo); +extern void XGI_XG21SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo); +extern BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ); +extern void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ); +extern USHORT XGI_GetLVDSOEMTableIndex(PVB_DEVICE_INFO pVBInfo); + +#endif diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h new file mode 100644 index 000000000000..bb25c0e2785e --- /dev/null +++ b/drivers/staging/xgifb/vb_struct.h @@ -0,0 +1,534 @@ +#ifndef _VB_STRUCT_ +#define _VB_STRUCT_ + +#ifdef _INITNEW_ +#define EXTERN +#else +#define EXTERN extern +#endif + + + + +typedef struct _XGI_PanelDelayTblStruct +{ + UCHAR timer[2]; +} XGI_PanelDelayTblStruct; + +typedef struct _XGI_LCDDataStruct +{ + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} XGI_LCDDataStruct; + + +typedef struct _XGI_LVDSCRT1HDataStruct +{ + UCHAR Reg[8]; +} XGI_LVDSCRT1HDataStruct; +typedef struct _XGI_LVDSCRT1VDataStruct +{ + UCHAR Reg[7]; +} XGI_LVDSCRT1VDataStruct; + + +typedef struct _XGI_TVDataStruct +{ + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT TVHDE; + USHORT TVVDE; + USHORT RVBHRS; + UCHAR FlickerMode; + USHORT HALFRVBHRS; + UCHAR RY1COE; + UCHAR RY2COE; + UCHAR RY3COE; + UCHAR RY4COE; +} XGI_TVDataStruct; + +typedef struct _XGI_LVDSDataStruct +{ + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} XGI_LVDSDataStruct; + +typedef struct _XGI_LVDSDesStruct +{ + USHORT LCDHDES; + USHORT LCDVDES; +} XGI_LVDSDesStruct; + +typedef struct _XGI_LVDSCRT1DataStruct +{ + UCHAR CR[15]; +} XGI_LVDSCRT1DataStruct; + +/*add for LCDA*/ + + +typedef struct _XGI_StStruct +{ + UCHAR St_ModeID; + USHORT St_ModeFlag; + UCHAR St_StTableIndex; + UCHAR St_CRT2CRTC; + UCHAR St_CRT2CRTC2; + UCHAR St_ResInfo; + UCHAR VB_StTVFlickerIndex; + UCHAR VB_StTVEdgeIndex; + UCHAR VB_StTVYFilterIndex; +} XGI_StStruct; + +typedef struct _XGI_StandTableStruct +{ + UCHAR CRT_COLS; + UCHAR ROWS; + UCHAR CHAR_HEIGHT; + USHORT CRT_LEN; + UCHAR SR[4]; + UCHAR MISC; + UCHAR CRTC[0x19]; + UCHAR ATTR[0x14]; + UCHAR GRC[9]; +} XGI_StandTableStruct; + +typedef struct _XGI_ExtStruct +{ + UCHAR Ext_ModeID; + USHORT Ext_ModeFlag; + USHORT Ext_ModeInfo; + USHORT Ext_Point; + USHORT Ext_VESAID; + UCHAR Ext_VESAMEMSize; + UCHAR Ext_RESINFO; + UCHAR VB_ExtTVFlickerIndex; + UCHAR VB_ExtTVEdgeIndex; + UCHAR VB_ExtTVYFilterIndex; + UCHAR REFindex; +} XGI_ExtStruct; + +typedef struct _XGI_Ext2Struct +{ + USHORT Ext_InfoFlag; + UCHAR Ext_CRT1CRTC; + UCHAR Ext_CRTVCLK; + UCHAR Ext_CRT2CRTC; + UCHAR Ext_CRT2CRTC2; + UCHAR ModeID; + USHORT XRes; + USHORT YRes; + /* USHORT ROM_OFFSET; */ +} XGI_Ext2Struct; + + +typedef struct _XGI_MCLKDataStruct +{ + UCHAR SR28,SR29,SR2A; + USHORT CLOCK; +} XGI_MCLKDataStruct; + +typedef struct _XGI_ECLKDataStruct +{ + UCHAR SR2E,SR2F,SR30; + USHORT CLOCK; +} XGI_ECLKDataStruct; + +typedef struct _XGI_VCLKDataStruct +{ + UCHAR SR2B,SR2C; + USHORT CLOCK; +} XGI_VCLKDataStruct; + +typedef struct _XGI_VBVCLKDataStruct +{ + UCHAR Part4_A,Part4_B; + USHORT CLOCK; +} XGI_VBVCLKDataStruct; + +typedef struct _XGI_StResInfoStruct +{ + USHORT HTotal; + USHORT VTotal; +} XGI_StResInfoStruct; + +typedef struct _XGI_ModeResInfoStruct +{ + USHORT HTotal; + USHORT VTotal; + UCHAR XChar; + UCHAR YChar; +} XGI_ModeResInfoStruct; + +typedef struct _XGI_LCDNBDesStruct +{ + UCHAR NB[12]; +} XGI_LCDNBDesStruct; + /*add for new UNIVGABIOS*/ +typedef struct _XGI_LCDDesStruct +{ + USHORT LCDHDES; + USHORT LCDHRS; + USHORT LCDVDES; + USHORT LCDVRS; +} XGI_LCDDesStruct; + +typedef struct _XGI_LCDDataTablStruct +{ + UCHAR PANELID; + USHORT MASK; + USHORT CAP; + USHORT DATAPTR; +} XGI_LCDDataTablStruct; + +typedef struct _XGI_TVTablDataStruct +{ + USHORT MASK; + USHORT CAP; + USHORT DATAPTR; +} XGI_TVDataTablStruct; + +typedef struct _XGI330_LCDDesDataStruct +{ + USHORT LCDHDES; + USHORT LCDHRS; + USHORT LCDVDES; + USHORT LCDVRS; +} XGI330_LCDDataDesStruct; + + +typedef struct _XGI330_LVDSDataStruct +{ + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} XGI330_LVDSDataStruct; + +typedef struct _XGI330_LCDDesDataStruct2 +{ + USHORT LCDHDES; + USHORT LCDHRS; + USHORT LCDVDES; + USHORT LCDVRS; + USHORT LCDHSync; + USHORT LCDVSync; +} XGI330_LCDDataDesStruct2; + +typedef struct _XGI330_LCDDataStruct +{ + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} XGI330_LCDDataStruct; + + +typedef struct _XGI330_TVDataStruct +{ + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT TVHDE; + USHORT TVVDE; + USHORT RVBHRS; + UCHAR FlickerMode; + USHORT HALFRVBHRS; +} XGI330_TVDataStruct; + +typedef struct _XGI330_LCDDataTablStruct +{ + UCHAR PANELID; + USHORT MASK; + USHORT CAP; + USHORT DATAPTR; +} XGI330_LCDDataTablStruct; + +typedef struct _XGI330_TVDataTablStruct +{ + USHORT MASK; + USHORT CAP; + USHORT DATAPTR; +} XGI330_TVDataTablStruct; + + +typedef struct _XGI330_CHTVDataStruct +{ + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} XGI330_CHTVDataStruct; + +typedef struct _XGI_TimingHStruct +{ + UCHAR data[8]; +} XGI_TimingHStruct; + +typedef struct _XGI_TimingVStruct +{ + UCHAR data[7]; +} XGI_TimingVStruct; + +typedef struct _XGI_CH7007TV_TimingHStruct +{ + UCHAR data[10]; +} XGI_CH7007TV_TimingHStruct; + +typedef struct _XGI_CH7007TV_TimingVStruct +{ + UCHAR data[10]; +} XGI_CH7007TV_TimingVStruct; + +typedef struct _XGI_XG21CRT1Struct +{ + UCHAR ModeID,CR02,CR03,CR15,CR16; +} XGI_XG21CRT1Struct; + +typedef struct _XGI330_CHTVRegDataStruct +{ + UCHAR Reg[16]; +} XGI330_CHTVRegDataStruct; + +typedef struct _XGI330_LCDCapStruct +{ + UCHAR LCD_ID; + USHORT LCD_Capability; + UCHAR LCD_SetFlag; + UCHAR LCD_DelayCompensation; + UCHAR LCD_HSyncWidth; + UCHAR LCD_VSyncWidth; + UCHAR LCD_VCLK; + UCHAR LCDA_VCLKData1; + UCHAR LCDA_VCLKData2; + UCHAR LCUCHAR_VCLKData1; + UCHAR LCUCHAR_VCLKData2; + UCHAR PSC_S1; + UCHAR PSC_S2; + UCHAR PSC_S3; + UCHAR PSC_S4; + UCHAR PSC_S5; + UCHAR PWD_2B; + UCHAR PWD_2C; + UCHAR PWD_2D; + UCHAR PWD_2E; + UCHAR PWD_2F; + UCHAR Spectrum_31; + UCHAR Spectrum_32; + UCHAR Spectrum_33; + UCHAR Spectrum_34; +} XGI330_LCDCapStruct; + +typedef struct _XGI21_LVDSCapStruct +{ + USHORT LVDS_Capability; + USHORT LVDSHT; + USHORT LVDSVT; + USHORT LVDSHDE; + USHORT LVDSVDE; + USHORT LVDSHFP; + USHORT LVDSVFP; + USHORT LVDSHSYNC; + USHORT LVDSVSYNC; + UCHAR VCLKData1; + UCHAR VCLKData2; + UCHAR PSC_S1; + UCHAR PSC_S2; + UCHAR PSC_S3; + UCHAR PSC_S4; + UCHAR PSC_S5; +} XGI21_LVDSCapStruct; + +typedef struct _XGI_CRT1TableStruct +{ + UCHAR CR[16]; +} XGI_CRT1TableStruct; + + +typedef struct _XGI330_VCLKDataStruct +{ + UCHAR SR2B,SR2C; + USHORT CLOCK; +} XGI330_VCLKDataStruct; + +typedef struct _XGI301C_Tap4TimingStruct +{ + USHORT DE; + UCHAR Reg[64]; /* C0-FF */ +} XGI301C_Tap4TimingStruct; + +typedef struct _XGI_New_StandTableStruct +{ + UCHAR CRT_COLS; + UCHAR ROWS; + UCHAR CHAR_HEIGHT; + USHORT CRT_LEN; + UCHAR SR[4]; + UCHAR MISC; + UCHAR CRTC[0x19]; + UCHAR ATTR[0x14]; + UCHAR GRC[9]; +} XGI_New_StandTableStruct; + +typedef UCHAR DRAM8Type[8]; +typedef UCHAR DRAM4Type[4]; +typedef UCHAR DRAM32Type[32]; +typedef UCHAR DRAM2Type[2]; + +typedef struct _VB_DEVICE_INFO VB_DEVICE_INFO; +typedef VB_DEVICE_INFO * PVB_DEVICE_INFO; + +struct _VB_DEVICE_INFO +{ + BOOLEAN ISXPDOS; + ULONG P3c4,P3d4,P3c0,P3ce,P3c2,P3cc; + ULONG P3ca,P3c6,P3c7,P3c8,P3c9,P3da; + ULONG Part0Port,Part1Port,Part2Port; + ULONG Part3Port,Part4Port,Part5Port; + USHORT RVBHCFACT,RVBHCMAX,RVBHRS; + USHORT VGAVT,VGAHT,VGAVDE,VGAHDE; + USHORT VT,HT,VDE,HDE; + USHORT LCDHRS,LCDVRS,LCDHDES,LCDVDES; + + USHORT ModeType; + USHORT IF_DEF_LVDS,IF_DEF_TRUMPION,IF_DEF_DSTN;/* ,IF_DEF_FSTN; add for dstn */ + USHORT IF_DEF_CRT2Monitor,IF_DEF_VideoCapture; + USHORT IF_DEF_LCDA,IF_DEF_CH7017,IF_DEF_YPbPr,IF_DEF_ScaleLCD,IF_DEF_OEMUtil,IF_DEF_PWD; + USHORT IF_DEF_ExpLink; + USHORT IF_DEF_CH7005,IF_DEF_HiVision; + USHORT IF_DEF_CH7007; /* Billy 2007/05/03 */ + USHORT LCDResInfo,LCDTypeInfo, VBType;/*301b*/ + USHORT VBInfo,TVInfo,LCDInfo, Set_VGAType; + USHORT VBExtInfo;/*301lv*/ + USHORT SetFlag; + USHORT NewFlickerMode; + USHORT SelectCRT2Rate; + + PUCHAR ROMAddr; + PUCHAR FBAddr; + ULONG BaseAddr; + ULONG RelIO; + + DRAM4Type *CR6B; + DRAM4Type *CR6E; + DRAM32Type *CR6F; + DRAM2Type *CR89; + + DRAM8Type *SR15; /* pointer : point to array */ + DRAM8Type *CR40; + UCHAR *pSoftSetting; + UCHAR *pOutputSelect; + + USHORT *pRGBSenseData; + USHORT *pRGBSenseData2; /*301b*/ + USHORT *pVideoSenseData; + USHORT *pVideoSenseData2; + USHORT *pYCSenseData; + USHORT *pYCSenseData2; + + UCHAR *pSR07; + UCHAR *CR49; + UCHAR *pSR1F; + UCHAR *AGPReg; + UCHAR *SR16; + UCHAR *pSR21; + UCHAR *pSR22; + UCHAR *pSR23; + UCHAR *pSR24; + UCHAR *SR25; + UCHAR *pSR31; + UCHAR *pSR32; + UCHAR *pSR33; + UCHAR *pSR36; /* alan 12/07/2006 */ + UCHAR *pCRCF; + UCHAR *pCRD0; /* alan 12/07/2006 */ + UCHAR *pCRDE; /* alan 12/07/2006 */ + UCHAR *pCR8F; /* alan 12/07/2006 */ + UCHAR *pSR40; /* alan 12/07/2006 */ + UCHAR *pSR41; /* alan 12/07/2006 */ + UCHAR *pDVOSetting; + UCHAR *pCR2E; + UCHAR *pCR2F; + UCHAR *pCR46; + UCHAR *pCR47; + UCHAR *pCRT2Data_1_2; + UCHAR *pCRT2Data_4_D; + UCHAR *pCRT2Data_4_E; + UCHAR *pCRT2Data_4_10; + XGI_MCLKDataStruct *MCLKData; + XGI_ECLKDataStruct *ECLKData; + + UCHAR *XGI_TVDelayList; + UCHAR *XGI_TVDelayList2; + UCHAR *CHTVVCLKUNTSC; + UCHAR *CHTVVCLKONTSC; + UCHAR *CHTVVCLKUPAL; + UCHAR *CHTVVCLKOPAL; + UCHAR *NTSCTiming; + UCHAR *PALTiming; + UCHAR *HiTVExtTiming; + UCHAR *HiTVSt1Timing; + UCHAR *HiTVSt2Timing; + UCHAR *HiTVTextTiming; + UCHAR *YPbPr750pTiming; + UCHAR *YPbPr525pTiming; + UCHAR *YPbPr525iTiming; + UCHAR *HiTVGroup3Data; + UCHAR *HiTVGroup3Simu; + UCHAR *HiTVGroup3Text; + UCHAR *Ren525pGroup3; + UCHAR *Ren750pGroup3; + UCHAR *ScreenOffset; + UCHAR *pXGINew_DRAMTypeDefinition; + UCHAR *pXGINew_I2CDefinition ; + UCHAR *pXGINew_CR97 ; + + XGI330_LCDCapStruct *LCDCapList; + XGI21_LVDSCapStruct *XG21_LVDSCapList; + + XGI_TimingHStruct *TimingH; + XGI_TimingVStruct *TimingV; + + XGI_StStruct *SModeIDTable; + XGI_StandTableStruct *StandTable; + XGI_ExtStruct *EModeIDTable; + XGI_Ext2Struct *RefIndex; + /* XGINew_CRT1TableStruct *CRT1Table; */ + XGI_CRT1TableStruct *XGINEWUB_CRT1Table; + XGI_VCLKDataStruct *VCLKData; + XGI_VBVCLKDataStruct *VBVCLKData; + XGI_StResInfoStruct *StResInfo; + XGI_ModeResInfoStruct *ModeResInfo; + XGI_XG21CRT1Struct *UpdateCRT1; +}; /* _VB_DEVICE_INFO */ + + +typedef struct +{ + USHORT Horizontal_ACTIVE; + USHORT Horizontal_FP; + USHORT Horizontal_SYNC; + USHORT Horizontal_BP; + USHORT Vertical_ACTIVE; + USHORT Vertical_FP; + USHORT Vertical_SYNC; + USHORT Vertical_BP; + double DCLK; + UCHAR FrameRate; + UCHAR Interlace; + USHORT Margin; +} TimingInfo; + +#define _VB_STRUCT_ +#endif /* _VB_STRUCT_ */ diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h new file mode 100644 index 000000000000..781caefc56b1 --- /dev/null +++ b/drivers/staging/xgifb/vb_table.h @@ -0,0 +1,4406 @@ +#define Tap4 + + +XGI_MCLKDataStruct XGI330New_MCLKData[]= +{ + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x7C,0x08,0x80,200}, + { 0x79,0x06,0x80,250}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300} +}; +//yilin modify for xgi20 +XGI_MCLKDataStruct XGI340New_MCLKData[]= +{ + { 0x16,0x01,0x01,166}, + { 0x19,0x02,0x01,124}, + { 0x7C,0x08,0x01,200}, + { 0x79,0x06,0x01,250}, + { 0x29,0x01,0x81,301}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166} +}; + +XGI_MCLKDataStruct XGI27New_MCLKData[]= +{ + { 0x5c,0x23,0x01,166}, + { 0x19,0x02,0x01,124}, + { 0x7C,0x08,0x80,200}, + { 0x79,0x06,0x80,250}, + { 0x29,0x01,0x81,300}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166} +}; + +XGI_ECLKDataStruct XGI330_ECLKData[]= +{ + { 0x7c,0x08,0x01,200}, + { 0x7c,0x08,0x01,200}, + { 0x7C,0x08,0x80,200}, + { 0x79,0x06,0x80,250}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300}, + { 0x29,0x01,0x81,300} +}; +//yilin modify for xgi20 +XGI_ECLKDataStruct XGI340_ECLKData[]= +{ + { 0x5c,0x23,0x01,166}, + { 0x55,0x84,0x01,123}, + { 0x7C,0x08,0x01,200}, + { 0x79,0x06,0x01,250}, + { 0x29,0x01,0x81,301}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166}, + { 0x5c,0x23,0x01,166} +}; + + + +UCHAR XGI340_SR13[4][8]={ +{0x35,0x45,0xb1,0x00,0x00,0x00,0x00,0x00},/* SR13 */ +{0x41,0x51,0x5c,0x00,0x00,0x00,0x00,0x00},/* SR14 */ +{0x31,0x42,0x42,0x00,0x00,0x00,0x00,0x00},/* SR18 */ +{0x03,0x03,0x03,0x00,0x00,0x00,0x00,0x00}/* SR1B */ +}; + +UCHAR XGI340_cr41[24][8]= +{{0x20,0x50,0x60,0x00,0x00,0x00,0x00,0x00},/* 0 CR41 */ +{0xc4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 1 CR8A */ +{0xc4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 2 CR8B */ +{0xb5,0xa4,0xa4,0x00,0x00,0x00,0x00,0x00}, +{0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0x00}, +{0x90,0x90,0x24,0x00,0x00,0x00,0x00,0x00},/* 5 CR68 */ +{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 6 CR69 */ +{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 7 CR6A */ +{0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00},/* 8 CR6D */ +{0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x00},/* 9 CR80 */ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/* 10 CR81 */ +{0x88,0xa8,0x48,0x00,0x00,0x00,0x00,0x00},/* 11 CR82 */ +{0x44,0x44,0x77,0x00,0x00,0x00,0x00,0x00},/* 12 CR85 */ +{0x48,0x48,0x88,0x00,0x00,0x00,0x00,0x00},/* 13 CR86 */ +{0x54,0x54,0x44,0x00,0x00,0x00,0x00,0x00},/* 14 CR90 */ +{0x54,0x54,0x44,0x00,0x00,0x00,0x00,0x00},/* 15 CR91 */ +{0x0a,0x0a,0x07,0x00,0x00,0x00,0x00,0x00},/* 16 CR92 */ +{0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x00},/* 17 CR93 */ +{0x10,0x10,0x0A,0x00,0x00,0x00,0x00,0x00},/* 18 CR94 */ +{0x11,0x11,0x0a,0x00,0x00,0x00,0x00,0x00},/* 19 CR95 */ +{0x05,0x05,0x05,0x00,0x00,0x00,0x00,0x00},/* 20 CR96 */ +{0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0x00},/* 21 CRC3 */ +{0x05,0x00,0x02,0x00,0x00,0x00,0x00,0x00},/* 22 CRC4 */ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}/* 23 CRC5 */ +}; + + +UCHAR XGI27_cr41[24][8]= +{ +{0x20,0x40,0x60,0x00,0x00,0x00,0x00,0x00},/* 0 CR41 */ +{0xC4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 1 CR8A */ +{0xC4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 2 CR8B */ +{0xB5,0x13,0xa4,0x00,0x00,0x00,0x00,0x00},/* 3 CR40[7],CR99[2:0],CR45[3:0]*/ +{0xf0,0xf5,0xf0,0x00,0x00,0x00,0x00,0x00},/* 4 CR59 */ +{0x90,0x90,0x24,0x00,0x00,0x00,0x00,0x00},/* 5 CR68 */ +{0x77,0x67,0x44,0x00,0x00,0x00,0x00,0x00},/* 6 CR69 */ +{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 7 CR6A */ +{0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00},/* 8 CR6D */ +{0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x00},/* 9 CR80 */ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/* 10 CR81 */ +{0x88,0xcc,0x48,0x00,0x00,0x00,0x00,0x00},/* 11 CR82 */ +{0x44,0x88,0x77,0x00,0x00,0x00,0x00,0x00},/* 12 CR85 */ +{0x48,0x88,0x88,0x00,0x00,0x00,0x00,0x00},/* 13 CR86 */ +{0x54,0x32,0x44,0x00,0x00,0x00,0x00,0x00},/* 14 CR90 */ +{0x54,0x33,0x44,0x00,0x00,0x00,0x00,0x00},/* 15 CR91 */ +{0x0a,0x07,0x07,0x00,0x00,0x00,0x00,0x00},/* 16 CR92 */ +{0x44,0x63,0x44,0x00,0x00,0x00,0x00,0x00},/* 17 CR93 */ +{0x10,0x14,0x0A,0x00,0x00,0x00,0x00,0x00},/* 18 CR94 */ +{0x11,0x0B,0x0C,0x00,0x00,0x00,0x00,0x00},/* 19 CR95 */ +{0x05,0x22,0x05,0x00,0x00,0x00,0x00,0x00},/* 20 CR96 */ +{0xf0,0xf0,0x00,0x00,0x00,0x00,0x00,0x00},/* 21 CRC3 */ +{0x05,0x00,0x02,0x00,0x00,0x00,0x00,0x00},/* 22 CRC4 */ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}/* 23 CRC5 */ +}; + + +#if 0 +UCHAR XGI27_cr41[24][8]= +{ +{0x20,0x60,0x60,0x00,0x00,0x00,0x00,0x00},/* 0 CR41 */ +{0x04,0x44,0x84,0x00,0x00,0x00,0x00,0x00},/* 1 CR8A */ +{0x04,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 2 CR8B */ +{0xb5,0x03,0xa4,0x00,0x00,0x00,0x00,0x00},/* 3 CR40[7],CR99[2:0],CR45[3:0]*/ +{0xf0,0xf5,0xf0,0x00,0x00,0x00,0x00,0x00},/* 4 CR59 */ +{0xa4,0x1C,0x24,0x00,0x00,0x00,0x00,0x00},/* 5 CR68 */ +{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 6 CR69 */ +{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 7 CR6A */ +{0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00},/* 8 CR6D */ +{0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x00},/* 9 CR80 */ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/* 10 CR81 */ +{0x48,0xa8,0x48,0x00,0x00,0x00,0x00,0x00},/* 11 CR82 */ +{0x77,0x88,0x77,0x00,0x00,0x00,0x00,0x00},/* 12 CR85 */ +{0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00},/* 13 CR86 */ +{0x44,0x32,0x44,0x00,0x00,0x00,0x00,0x00},/* 14 CR90 */ +{0x44,0x33,0x44,0x00,0x00,0x00,0x00,0x00},/* 15 CR91 */ +{0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00},/* 16 CR92 */ +{0x44,0x63,0x44,0x00,0x00,0x00,0x00,0x00},/* 17 CR93 */ +{0x0A,0x14,0x0A,0x00,0x00,0x00,0x00,0x00},/* 18 CR94 */ +{0x0C,0x0B,0x0C,0x00,0x00,0x00,0x00,0x00},/* 19 CR95 */ +{0x05,0x22,0x05,0x00,0x00,0x00,0x00,0x00},/* 20 CR96 */ +{0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0x00},/* 21 CRC3 */ +{0x03,0x00,0x02,0x00,0x00,0x00,0x00,0x00},/* 22 CRC4 */ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}/* 23 CRC5 */ +}; +#endif +UCHAR XGI340_CR6B[8][4]={ +{0xaa,0xaa,0xaa,0xaa}, +{0xaa,0xaa,0xaa,0xaa}, +{0xaa,0xaa,0xaa,0xaa}, +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00} +}; + +UCHAR XGI340_CR6E[8][4]={ +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00} +}; + +UCHAR XGI340_CR6F[8][32]={ +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +}; + +UCHAR XGI340_CR89[8][2]={ +{0x00,0x00}, +{0x00,0x00}, +{0x00,0x00}, +{0x00,0x00}, +{0x00,0x00}, +{0x00,0x00}, +{0x00,0x00}, +{0x00,0x00} +}; + /* CR47,CR48,CR49,CR4A,CR4B,CR4C,CR70,CR71,CR74,CR75,CR76,CR77 */ +UCHAR XGI340_AGPReg[12]={0x28,0x23,0x00,0x20,0x00,0x20,0x00,0x05,0xd0,0x10,0x10,0x00}; + +UCHAR XGI340_SR16[4]={0x03,0x83,0x03,0x83}; + +UCHAR XGI330_SR15_1[8][8]={ +{0x0,0x0,0x00,0x00,0x20,0x20,0x00,0x00}, +{0x5,0x15,0x15,0x15,0x15,0x15,0x00,0x00}, +{0xba,0xba,0xba,0xba,0xBA,0xBA,0x00,0x00}, +{0x55,0x57,0x57,0xAB,0xAB,0xAB,0x00,0x00}, +{0x60,0x34,0x34,0x34,0x34,0x34,0x00,0x00}, +{0x0,0x80,0x80,0x80,0x83,0x83,0x00,0x00}, +{0x50,0x50,0x50,0x3C,0x3C,0x3C,0x00,0x00}, +{0x0,0xa5,0xfb,0xf6,0xF6,0xF6,0x00,0x00} +}; + +UCHAR XGI330_cr40_1[15][8]={ +{0x66,0x40,0x40,0x28,0x24,0x24,0x00,0x00}, +{0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x0F,0x0F,0x00,0x00}, +{0x00,0xf0,0xf0,0xf0,0xF0,0xF0,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x10,0x10,0x10,0x10,0x20,0x20,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x88,0x88,0x88,0xAA,0xAC,0xAC,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x77,0x77,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, +{0x00,0xA2,0x00,0x00,0xA2,0xA2,0x00,0x00}, +}; + +UCHAR XGI330_sr25[]={0x00,0x0}; +UCHAR XGI330_sr31=0xc0; +UCHAR XGI330_sr32=0x11; +UCHAR XGI330_SR33=0x00; +UCHAR XG40_CRCF=0x13; +UCHAR XG40_DRAMTypeDefinition=0xFF ; + +XGI_StStruct XGI330_SModeIDTable[]= +{ + {0x01,0x9208,0x01,0x00,0x10,0x00,0x00,0x01,0x00}, + {0x01,0x1210,0x14,0x01,0x00,0x01,0x00,0x01,0x00}, + {0x01,0x1010,0x17,0x02,0x11,0x00,0x00,0x01,0x01}, + {0x03,0x8208,0x03,0x00,0x14,0x00,0x00,0x01,0x02}, + {0x03,0x0210,0x16,0x01,0x04,0x01,0x00,0x01,0x02}, + {0x03,0x0010,0x18,0x02,0x15,0x00,0x00,0x01,0x03}, + {0x05,0x9209,0x05,0x00,0x10,0x00,0x00,0x00,0x04}, + {0x06,0x8209,0x06,0x00,0x14,0x00,0x00,0x00,0x05}, + {0x07,0x0000,0x07,0x03,0x05,0x03,0x00,0x01,0x03}, + {0x07,0x0000,0x19,0x02,0x15,0x02,0x00,0x01,0x03}, + {0x0d,0x920a,0x0d,0x00,0x10,0x00,0x00,0x00,0x04}, + {0x0e,0x820a,0x0e,0x00,0x14,0x00,0x00,0x00,0x05}, + {0x0f,0x0202,0x11,0x01,0x04,0x01,0x00,0x00,0x05}, + {0x10,0x0212,0x12,0x01,0x04,0x01,0x00,0x00,0x05}, + {0x11,0x0212,0x1a,0x04,0x24,0x04,0x00,0x00,0x05}, + {0x12,0x0212,0x1b,0x04,0x24,0x04,0x00,0x00,0x05}, + {0x13,0x021b,0x1c,0x00,0x14,0x00,0x00,0x00,0x04}, + {0x12,0x0010,0x18,0x02,0x24,0x02,0x00,0x00,0x05},/* St_CRT2CRTC2 not sure */ + {0x12,0x0210,0x18,0x01,0x24,0x01,0x00,0x00,0x05},/* St_CRT2CRTC2 not sure */ + {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +}; + + +XGI_ExtStruct XGI330_EModeIDTable[]= +{ + {0x6a,0x2212,0x0407,0x3a81,0x0102,0x08,0x07,0x00,0x00,0x07,0x0e}, + {0x2e,0x0a1b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x06}, + {0x2f,0x0a1b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x05}, + {0x30,0x2a1b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x0e}, + {0x31,0x0a1b,0x030d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x3d}, + {0x32,0x0a1b,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x3e}, + {0x33,0x0a1d,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x3d}, + {0x34,0x2a1d,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x3e}, + {0x35,0x0a1f,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x3d}, + {0x36,0x2a1f,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x3e}, + {0x37,0x0212,0x0508,0x3aab,0x0104,0x08,0x08,0x00,0x00,0x00,0x16}, + {0x38,0x0a1b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x00,0x16}, + {0x3a,0x0e3b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1e}, + {0x3c,0x0e3b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x22}, /* mode 1600x1200 add CRT2MODE [2003/10/07] */ + {0x3d,0x0e7d,0x070a,0x3af2,0x0131,0x08,0x0a,0x00,0x00,0x00,0x22}, /* mode 1600x1200 add CRT2MODE */ + {0x40,0x9a1c,0x0000,0x3a34,0x010d,0x08,0x00,0x00,0x00,0x04,0x00}, + {0x41,0x9a1d,0x0000,0x3a34,0x010e,0x08,0x00,0x00,0x00,0x04,0x00}, /* ModeIdIndex = 0x10 */ + {0x43,0x0a1c,0x0306,0x3a57,0x0110,0x08,0x06,0x00,0x00,0x05,0x06}, + {0x44,0x0a1d,0x0306,0x3a57,0x0111,0x08,0x06,0x00,0x00,0x05,0x06}, + {0x46,0x2a1c,0x0407,0x3a81,0x0113,0x08,0x07,0x00,0x00,0x07,0x0e}, + {0x47,0x2a1d,0x0407,0x3a81,0x0114,0x08,0x07,0x00,0x00,0x07,0x0e}, + {0x49,0x0a3c,0x0508,0x3aab,0x0116,0x08,0x08,0x00,0x00,0x00,0x16}, + {0x4a,0x0a3d,0x0508,0x3aab,0x0117,0x08,0x08,0x00,0x00,0x00,0x16}, + {0x4c,0x0e7c,0x0609,0x3adc,0x0119,0x08,0x09,0x00,0x00,0x00,0x1e}, + {0x4d,0x0e7d,0x0609,0x3adc,0x011a,0x08,0x09,0x00,0x00,0x00,0x1e}, + {0x50,0x9a1b,0x0001,0x3a3b,0x0132,0x08,0x01,0x00,0x00,0x04,0x02}, + {0x51,0xba1b,0x0103,0x3a42,0x0133,0x08,0x03,0x00,0x00,0x07,0x03}, + {0x52,0x9a1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x04}, + {0x56,0x9a1d,0x0001,0x3a3b,0x0135,0x08,0x01,0x00,0x00,0x04,0x02}, + {0x57,0xba1d,0x0103,0x3a42,0x0136,0x08,0x03,0x00,0x00,0x07,0x03}, + {0x58,0x9a1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x04}, + {0x59,0x9a1b,0x0000,0x3a34,0x0138,0x08,0x00,0x00,0x00,0x04,0x00}, + {0x5A,0x021b,0x0014,0x3b83,0x0138,0x08,0x01,0x00,0x00,0x04,0x3f}, /* ModeIdIndex = 0x20 */ + {0x5B,0x0a1d,0x0014,0x3b83,0x0135,0x08,0x01,0x00,0x00,0x04,0x3f}, + {0x5d,0x0a1d,0x0305,0x3a50,0x0139,0x08,0x05,0x00,0x00,0x07,0x05}, + {0x62,0x0a3f,0x0306,0x3a57,0x013a,0x08,0x06,0x00,0x00,0x05,0x06}, + {0x63,0x2a3f,0x0407,0x3a81,0x013b,0x08,0x07,0x00,0x00,0x07,0x0e}, + {0x64,0x0a7f,0x0508,0x3aab,0x013c,0x08,0x08,0x00,0x00,0x00,0x16}, + {0x65,0x0eff,0x0609,0x3adc,0x013d,0x08,0x09,0x00,0x00,0x00,0x1e}, + {0x66,0x0eff,0x070a,0x3af2,0x013e,0x08,0x0a,0x00,0x00,0x00,0x22}, /* mode 1600x1200 add CRT2MODE */ + {0x68,0x067b,0x080b,0x3b17,0x013f,0x08,0x0b,0x00,0x00,0x00,0x29}, + {0x69,0x06fd,0x080b,0x3b17,0x0140,0x08,0x0b,0x00,0x00,0x00,0x29}, + {0x6b,0x07ff,0x080b,0x3b17,0x0141,0x10,0x0b,0x00,0x00,0x00,0x29}, + {0x6c,0x067b,0x090c,0x3b37,0x0000,0x08,0x0c,0x00,0x00,0x00,0x2f}, + {0x6d,0x06fd,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f}, + {0x6e,0x07ff,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f}, + {0x70,0x2a1b,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34}, + {0x71,0x0a1b,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37}, + {0x74,0x0a1d,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37}, /* ModeIdIndex = 0x30 */ + {0x75,0x0a3d,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a}, + {0x76,0x2a1f,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34}, + {0x77,0x0a1f,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37}, + {0x78,0x0a3f,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a}, + {0x79,0x0a3b,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a}, + {0x7a,0x2a1d,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34}, + {0x7b,0x0e3b,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x1d}, + {0x7c,0x0e7d,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x1d}, + {0x7d,0x0eff,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x1d}, + {0x20,0x0e3b,0x0D16,0x49e0,0x0000,0x08,0x16,0x00,0x00,0x00,0x43}, + {0x21,0x0e7d,0x0D16,0x49e0,0x0000,0x08,0x16,0x00,0x00,0x00,0x43}, + {0x22,0x0eff,0x0D16,0x49e0,0x0000,0x08,0x16,0x00,0x00,0x00,0x43}, + {0x23,0x0e3b,0x0614,0x49d5,0x0000,0x08,0x14,0x00,0x00,0x00,0x41}, + {0x24,0x0e7d,0x0614,0x49d5,0x0000,0x08,0x14,0x00,0x00,0x00,0x41}, + {0x25,0x0eff,0x0614,0x49d5,0x0000,0x08,0x14,0x00,0x00,0x00,0x41}, + {0x26,0x063b,0x0c15,0x49dc,0x0000,0x08,0x15,0x00,0x00,0x00,0x42}, /* ModeIdIndex = 0x40 */ + {0x27,0x067d,0x0c15,0x49dc,0x0000,0x08,0x15,0x00,0x00,0x00,0x42}, + {0x28,0x06ff,0x0c15,0x49dc,0x0000,0x08,0x15,0x00,0x00,0x00,0x42}, + {0xff,0x0000,0x0000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00} +}; + +XGI_StandTableStruct XGI330_StandTable[]= +{ +/* MD_0_200 */ + { + 0x28,0x18,0x08,0x0800, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* MD_1_200 */ + { + 0x28,0x18,0x08,0x0800, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* MD_2_200 */ + { + 0x50,0x18,0x08,0x1000, + {0x01,0x03,0x00,0x02}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* MD_3_200 */ + { + 0x50,0x18,0x08,0x1000, + {0x01,0x03,0x00,0x02}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* MD_4 */ + { + 0x28,0x18,0x08,0x4000, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, + 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2, + 0xff}, + {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x03,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00, + 0xff} + }, +/* MD_5 */ + { + 0x28,0x18,0x08,0x4000, + {0x09,0x03,0x00,0x02}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, + 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2, + 0xff}, + {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x03,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00, + 0xff} + }, +/* MD_6 */ + { + 0x50,0x18,0x08,0x4000, + {0x01,0x01,0x00,0x06}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2, + 0xff}, + {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17, + 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, + 0x01,0x00,0x01,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00, + 0xff} + }, +/* MD_7 */ + { + 0x50,0x18,0x0e,0x1000, + {0x00,0x03,0x00,0x03}, + 0xa6, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x28,0x0d,0x63,0xba,0xa3, + 0xff}, + {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x0e,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00, + 0xff} + }, +/* MDA_DAC */ + { + 0x00,0x00,0x00,0x0000, + {0x00,0x00,0x00,0x15}, + 0x15, + {0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0x00, + 0x00}, + {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, + 0x15,0x15,0x15,0x15}, + {0x15,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f} + }, +/* CGA_DAC */ + { + 0x00,0x10,0x04,0x0114, + {0x11,0x09,0x15,0x00}, + 0x10, + {0x04,0x14,0x01,0x11,0x09,0x15,0x2a,0x3a, + 0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x2a,0x3a, + 0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x10, + 0x04}, + {0x14,0x01,0x11,0x09,0x15,0x00,0x10,0x04, + 0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,0x2e, + 0x3e,0x2b,0x3b,0x2f}, + {0x3f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f, + 0x3f} + }, +/* EGA_DAC */ + { + 0x00,0x10,0x04,0x0114, + {0x11,0x05,0x15,0x20}, + 0x30, + {0x24,0x34,0x21,0x31,0x25,0x35,0x08,0x18, + 0x0c,0x1c,0x09,0x19,0x0d,0x1d,0x28,0x38, + 0x2c,0x3c,0x29,0x39,0x2d,0x3d,0x02,0x12, + 0x06}, + {0x16,0x03,0x13,0x07,0x17,0x22,0x32,0x26, + 0x36,0x23,0x33,0x27,0x37,0x0a,0x1a,0x0e, + 0x1e,0x0b,0x1b,0x0f}, + {0x1f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f, + 0x3f} + }, +/* VGA_DAC */ + { + 0x00,0x10,0x04,0x0114, + {0x11,0x09,0x15,0x2a}, + 0x3a, + {0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x05, + 0x08,0x0b,0x0e,0x11,0x14,0x18,0x1c,0x20, + 0x24,0x28,0x2d,0x32,0x38,0x3f,0x00,0x10, + 0x1f}, + {0x2f,0x3f,0x1f,0x27,0x2f,0x37,0x3f,0x2d, + 0x31,0x36,0x3a,0x3f,0x00,0x07,0x0e,0x15, + 0x1c,0x0e,0x11,0x15}, + {0x18,0x1c,0x14,0x16,0x18,0x1a,0x1c,0x00, + 0x04} + }, + { + 0x08,0x0c,0x10,0x0a08, + {0x0c,0x0e,0x10,0x0b}, + 0x0c, + {0x0d,0x0f,0x10,0x10,0x01,0x08,0x00,0x00, + 0x00,0x00,0x01,0x00,0x02,0x02,0x01,0x00, + 0x04,0x04,0x01,0x00,0x05,0x02,0x05,0x00, + 0x06}, + {0x01,0x06,0x05,0x06,0x00,0x08,0x01,0x08, + 0x00,0x07,0x02,0x07,0x06,0x07,0x00,0x00, + 0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00} + }, +/* MD_D */ + { + 0x28,0x18,0x08,0x2000, + {0x09,0x0f,0x00,0x06}, + 0x63, + {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, + 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* MD_E */ + { + 0x50,0x18,0x08,0x4000, + {0x01,0x0f,0x00,0x06}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* ExtVGATable */ + { + 0x00,0x00,0x00,0x0000, + {0x01,0x0f,0x00,0x0e}, + 0x23, + {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x01,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, + 0xff} + }, +/* ROM_SAVEPTR */ + { + 0x9f,0x3b,0x00,0x00c0, + {0x00,0x00,0x00,0x00}, + 0x00, + {0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x3f, + 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x1a,0x00,0xac,0x3e,0x00,0xc0, + 0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00} + }, +/* MD_F */ + { + 0x50,0x18,0x0e,0x8000, + {0x01,0x0f,0x00,0x06}, + 0xa2, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3, + 0xff}, + {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00, + 0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00, + 0x0b,0x00,0x05,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05, + 0xff} + }, +/* MD_10 */ + { + 0x50,0x18,0x0e,0x8000, + {0x01,0x0f,0x00,0x06}, + 0xa3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* MD_0_350 */ + { + 0x28,0x18,0x0e,0x0800, + {0x09,0x03,0x00,0x02}, + 0xa3, + {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* MD_1_350 */ + { + 0x28,0x18,0x0e,0x0800, + {0x09,0x03,0x00,0x02}, + 0xa3, + {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* MD_2_350 */ + { + 0x50,0x18,0x0e,0x1000, + {0x01,0x03,0x00,0x02}, + 0xa3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* MD_3_350 */ + { + 0x50,0x18,0x0e,0x1000, + {0x01,0x03,0x00,0x02}, + 0xa3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x08,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* MD_0_1_400 */ + { + 0x28,0x18,0x10,0x0800, + {0x08,0x03,0x00,0x02}, + 0x67, + {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f, + 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x0c,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* MD_2_3_400 */ + { + 0x50,0x18,0x10,0x1000, + {0x00,0x03,0x00,0x02}, + 0x67, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x0c,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, + 0xff} + }, +/* MD_7_400 */ + { + 0x50,0x18,0x10,0x1000, + {0x00,0x03,0x00,0x02}, + 0x66, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x0e,0x00,0x0f,0x08}, + {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00, + 0xff} + }, +/* MD_11 */ + { + 0x50,0x1d,0x10,0xa000, + {0x01,0x0f,0x00,0x06}, + 0xe3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xc3, + 0xff}, + {0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01, + 0xff} + }, +/* ExtEGATable */ + { + 0x50,0x1d,0x10,0xa000, + {0x01,0x0f,0x00,0x06}, + 0xe3, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x01,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f, + 0xff} + }, +/* MD_13 */ + { + 0x28,0x18,0x08,0x2000, + {0x01,0x0f,0x00,0x0e}, + 0x63, + {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, + 0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3, + 0xff}, + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x41,0x00,0x0f,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, + 0xff} + } +}; + +XGI_TimingHStruct XGI_TimingH[]= +{{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}}; + +XGI_TimingVStruct XGI_TimingV[]= +{{{0x00,0x00,0x00,0x00,0x00,0x00,0x00}}}; + +XGI_XG21CRT1Struct XGI_UpdateCRT1Table[]= +{ + {0x01,0x27,0x91,0x8f,0xc0}, /* 00 */ + {0x03,0x4f,0x83,0x8f,0xc0}, /* 01 */ + {0x05,0x27,0x91,0x8f,0xc0}, /* 02 */ + {0x06,0x4f,0x83,0x8f,0xc0}, /* 03 */ + {0x07,0x4f,0x83,0x8f,0xc0}, /* 04 */ + {0x0d,0x27,0x91,0x8f,0xc0}, /* 05 */ + {0x0e,0x4f,0x83,0x8f,0xc0}, /* 06 */ + {0x0f,0x4f,0x83,0x5d,0xc0}, /* 07 */ + {0x10,0x4f,0x83,0x5d,0xc0}, /* 08 */ + {0x11,0x4f,0x83,0xdf,0x0c}, /* 09 */ + {0x12,0x4f,0x83,0xdf,0x0c}, /* 10 */ + {0x13,0x4f,0x83,0x8f,0xc0}, /* 11 */ + {0x2e,0x4f,0x83,0xdf,0x0c}, /* 12 */ + {0x2e,0x4f,0x87,0xdf,0xc0}, /* 13 */ + {0x2f,0x4f,0x83,0x8f,0xc0}, /* 14 */ + {0x50,0x27,0x91,0xdf,0x0c}, /* 15 */ + {0x59,0x27,0x91,0x8f,0xc0} /* 16 */ +}; + +XGI_CRT1TableStruct XGI_CRT1Table[]= +{ + {{0x2d,0x28,0x90,0x2c,0x90,0x00,0x04,0x00, + 0xbf,0x1f,0x9c,0x8e,0x96,0xb9,0x30}}, /* 0x0 */ + {{0x2d,0x28,0x90,0x2c,0x90,0x00,0x04,0x00, + 0x0b,0x3e,0xe9,0x8b,0xe7,0x04,0x00}}, /* 0x1 */ + {{0x3D,0x31,0x81,0x37,0x1F,0x00,0x05,0x00, + 0x72,0xF0,0x58,0x8C,0x57,0x73,0xA0}}, /* 0x2 */ + {{0x4F,0x3F,0x93,0x45,0x0D,0x00,0x01,0x00, + 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90}}, /* 0x3 */ + {{0x5F,0x50,0x82,0x55,0x81,0x00,0x05,0x00, + 0xBF,0x1F,0x9C,0x8E,0x96,0xB9,0x30}}, /* 0x4 */ + {{0x5F,0x50,0x82,0x55,0x81,0x00,0x05,0x00, + 0x0B,0x3E,0xE9,0x8B,0xE7,0x04,0x00}}, /* 0x5 */ + {{0x63,0x50,0x86,0x56,0x9B,0x00,0x01,0x00, + 0x06,0x3E,0xE8,0x8B,0xE7,0xFF,0x10}}, /* 0x6 */ + {{0x64,0x4F,0x88,0x55,0x9D,0x00,0x01,0x00, + 0xF2,0x1F,0xE0,0x83,0xDF,0xF3,0x10}}, /* 0x7 */ + {{0x63,0x4F,0x87,0x5A,0x81,0x00,0x05,0x00, + 0xFB,0x1F,0xE0,0x83,0xDF,0xFC,0x10}}, /* 0x8 */ + {{0x65,0x4F,0x89,0x58,0x80,0x00,0x05,0x60, + 0xFB,0x1F,0xE0,0x83,0xDF,0xFC,0x80}}, /* 0x9 */ + {{0x65,0x4F,0x89,0x58,0x80,0x00,0x05,0x60, + 0x01,0x3E,0xE0,0x83,0xDF,0x02,0x80}}, /* 0xa */ + {{0x67,0x4F,0x8B,0x58,0x81,0x00,0x05,0x60, + 0x0D,0x3E,0xE0,0x83,0xDF,0x0E,0x90}}, /* 0xb */ + {{0x65,0x4F,0x89,0x57,0x9F,0x00,0x01,0x00, + 0xFB,0x1F,0xE6,0x8A,0xDF,0xFC,0x10}}, /* 0xc */ + {{0x7B,0x63,0x9F,0x6A,0x93,0x00,0x05,0x00, /* ; 0D (800x600,56Hz) */ + 0x6F,0xF0,0x58,0x8A,0x57,0x70,0xA0}}, /* ; (VCLK 36.0MHz) */ + {{0x7F,0x63,0x83,0x6C,0x1C,0x00,0x06,0x00, /* ; 0E (800x600,60Hz) */ + 0x72,0xF0,0x58,0x8C,0x57,0x73,0xA0}}, /* ; (VCLK 40.0MHz) */ + {{0x7D,0x63,0x81,0x6E,0x1D,0x00,0x06,0x00, /* ; 0F (800x600,72Hz) */ + 0x98,0xF0,0x7C,0x82,0x57,0x99,0x80}}, /* ; (VCLK 50.0MHz) */ + {{0x7F,0x63,0x83,0x69,0x13,0x00,0x06,0x00, /* ; 10 (800x600,75Hz) */ + 0x6F,0xF0,0x58,0x8B,0x57,0x70,0xA0}}, /* ; (VCLK 49.5MHz) */ + {{0x7E,0x63,0x82,0x6B,0x13,0x00,0x06,0x00, /* ; 11 (800x600,85Hz) */ + 0x75,0xF0,0x58,0x8B,0x57,0x76,0xA0}}, /* ; (VCLK 56.25MHz) */ + {{0x81,0x63,0x85,0x6D,0x18,0x00,0x06,0x60, /* ; 12 (800x600,100Hz) */ + 0x7A,0xF0,0x58,0x8B,0x57,0x7B,0xA0}}, /* ; (VCLK 75.8MHz) */ + {{0x83,0x63,0x87,0x6E,0x19,0x00,0x06,0x60, /* ; 13 (800x600,120Hz) */ + 0x81,0xF0,0x58,0x8B,0x57,0x82,0xA0}}, /* ; (VCLK 79.411MHz) */ + {{0x85,0x63,0x89,0x6F,0x1A,0x00,0x06,0x60, /* ; 14 (800x600,160Hz) */ + 0x91,0xF0,0x58,0x8B,0x57,0x92,0xA0}}, /* ; (VCLK 105.822MHz) */ + {{0x99,0x7F,0x9D,0x84,0x1A,0x00,0x02,0x00, + 0x96,0x1F,0x7F,0x83,0x7F,0x97,0x10}}, /* 0x15 */ + {{0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00, + 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90}}, /* 0x16 */ + {{0xA1,0x7F,0x85,0x86,0x97,0x00,0x02,0x00, + 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90}}, /* 0x17 */ + {{0x9F,0x7F,0x83,0x85,0x91,0x00,0x02,0x00, + 0x1E,0xF5,0x00,0x83,0xFF,0x1F,0x90}}, /* 0x18 */ + {{0xA7,0x7F,0x8B,0x89,0x95,0x00,0x02,0x00, + 0x26,0xF5,0x00,0x83,0xFF,0x27,0x90}}, /* 0x19 */ + {{0xA9,0x7F,0x8D,0x8C,0x9A,0x00,0x02,0x62, + 0x2C,0xF5,0x00,0x83,0xFF,0x2D,0x14}}, /* 0x1a */ + {{0xAB,0x7F,0x8F,0x8D,0x9B,0x00,0x02,0x62, + 0x35,0xF5,0x00,0x83,0xFF,0x36,0x14}}, /* 0x1b */ + {{0xCF,0x9F,0x93,0xB2,0x01,0x00,0x03,0x00, + 0x14,0xBA,0x00,0x83,0xFF,0x15,0x00}}, /* 0x1c */ + {{0xCE,0x9F,0x92,0xA9,0x17,0x00,0x07,0x00, + 0x28,0x5A,0x00,0x83,0xFF,0x29,0x89}}, /* 0x1d */ + {{0xCE,0x9F,0x92,0xA5,0x17,0x00,0x07,0x00, + 0x28,0x5A,0x00,0x83,0xFF,0x29,0x89}}, /* 0x1e */ + {{0xD3,0x9F,0x97,0xAB,0x1F,0x00,0x07,0x00, + 0x2E,0x5A,0x00,0x83,0xFF,0x2F,0x89}}, /* 0x1f */ + {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00, + 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x20 */ + {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00, + 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x21 */ + {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00, + 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x22 */ + {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00, + 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x23 */ + {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00, + 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x24 */ + {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00, + 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x25 */ + {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00, + 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x26 */ + {{0x40,0xEF,0x84,0x03,0x1D,0x41,0x01,0x00, + 0xDA,0x1F,0xA0,0x83,0x9F,0xDB,0x1F}}, /* 0x27 */ + {{0x43,0xEF,0x87,0x06,0x00,0x41,0x05,0x62, + 0xD4,0x1F,0xA0,0x83,0x9F,0xD5,0x9F}}, /* 0x28 */ + {{0x45,0xEF,0x89,0x07,0x01,0x41,0x05,0x62, + 0xD9,0x1F,0xA0,0x83,0x9F,0xDA,0x9F}}, /* 0x29 */ + {{0x40,0xEF,0x84,0x03,0x1D,0x41,0x01,0x00, + 0xDA,0x1F,0xA0,0x83,0x9F,0xDB,0x1F}}, /* 0x2a */ + {{0x40,0xEF,0x84,0x03,0x1D,0x41,0x01,0x00, + 0xDA,0x1F,0xA0,0x83,0x9F,0xDB,0x1F}}, /* 0x2b */ + {{0x40,0xEF,0x84,0x03,0x1D,0x41,0x01,0x00, + 0xDA,0x1F,0xA0,0x83,0x9F,0xDB,0x1F}}, /* 0x2c */ + {{0x59,0xFF,0x9D,0x17,0x13,0x41,0x05,0x44, + 0x33,0xBA,0x00,0x83,0xFF,0x34,0x0F}}, /* 0x2d */ + {{0x5B,0xFF,0x9F,0x18,0x14,0x41,0x05,0x44, + 0x38,0xBA,0x00,0x83,0xFF,0x39,0x0F}}, /* 0x2e */ + {{0x5B,0xFF,0x9F,0x18,0x14,0x41,0x05,0x44, + 0x3D,0xBA,0x00,0x83,0xFF,0x3E,0x0F}}, /* 0x2f */ + {{0x5D,0xFF,0x81,0x19,0x95,0x41,0x05,0x44, + 0x41,0xBA,0x00,0x84,0xFF,0x42,0x0F}}, /* 0x30 */ + {{0x55,0xFF,0x99,0x0D,0x0C,0x41,0x05,0x00, + 0x3E,0xBA,0x00,0x84,0xFF,0x3F,0x0F}}, /* 0x31 */ + {{0x7F,0x63,0x83,0x6C,0x1C,0x00,0x06,0x00, + 0x72,0xBA,0x27,0x8B,0xDF,0x73,0x80}}, /* 0x32 */ + {{0x7F,0x63,0x83,0x69,0x13,0x00,0x06,0x00, + 0x6F,0xBA,0x26,0x89,0xDF,0x6F,0x80}}, /* 0x33 */ + {{0x7F,0x63,0x82,0x6B,0x13,0x00,0x06,0x00, + 0x75,0xBA,0x29,0x8C,0xDF,0x75,0x80}}, /* 0x34 */ + {{0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00, + 0x24,0xF1,0xAF,0x85,0x3F,0x25,0xB0}}, /* 0x35 */ + {{0x9F,0x7F,0x83,0x85,0x91,0x00,0x02,0x00, + 0x1E,0xF1,0xAD,0x81,0x3F,0x1F,0xB0}}, /* 0x36 */ + {{0xA7,0x7F,0x88,0x89,0x15,0x00,0x02,0x00, + 0x26,0xF1,0xB1,0x85,0x3F,0x27,0xB0}}, /* 0x37 */ + {{0xCE,0x9F,0x92,0xA9,0x17,0x00,0x07,0x00, + 0x28,0xC4,0x7A,0x8E,0xCF,0x29,0xA1}}, /* 0x38 */ + {{0xCE,0x9F,0x92,0xA5,0x17,0x00,0x07,0x00, + 0x28,0xD4,0x7A,0x8E,0xCF,0x29,0xA1}}, /* 0x39 */ + {{0xD3,0x9F,0x97,0xAB,0x1F,0x00,0x07,0x00, + 0x2E,0xD4,0x7D,0x81,0xCF,0x2F,0xA1}}, /* 0x3a */ + {{0xDC,0x9F,0x00,0xAB,0x19,0x00,0x07,0x00, + 0xE6,0xEF,0xC0,0xC3,0xBF,0xE7,0x90}}, /* 0x3b */ + {{0x6B,0x59,0x8F,0x5E,0x8C,0x00,0x05,0x00, + 0x0B,0x3E,0xE9,0x8B,0xE7,0x04,0x00}}, /* 0x3c */ + {{0x7B,0x63,0x9F,0x6A,0x93,0x00,0x05,0x00, + 0x6F,0xF0,0x58,0x8A,0x57,0x70,0xA0}}, /* 0x3d */ + {{0x86,0x6A,0x8a,0x74,0x06,0x00,0x02,0x00, + 0x8c,0x15,0x4f,0x83,0xef,0x8d,0x30}}, /* 0x3e */ + {{0x81,0x6A,0x85,0x70,0x00,0x00,0x02,0x00, + 0x0f,0x3e,0xeb,0x8e,0xdf,0x10,0x00}}, /* 0x3f */ + {{0xCE,0x9F,0x92,0xA9,0x17,0x00,0x07,0x00, + 0x20,0xF5,0x03,0x88,0xFF,0x21,0x90}}, /* 0x40 */ + {{0xE6,0xAE,0x8A,0xBD,0x90,0x00,0x03,0x00, + 0x3D,0x10,0x1A,0x8D,0x19,0x3E,0x2F}}, /* 0x41 */ + {{0xB9,0x8F,0x9D,0x9B,0x8A,0x00,0x06,0x00, + 0x7D,0xFF,0x60,0x83,0x5F,0x7E,0x90}}, /* 0x42 */ + {{0xC3,0x8F,0x87,0x9B,0x0B,0x00,0x07,0x00, + 0x82,0xFF,0x60,0x83,0x5F,0x83,0x90}}, /* 0x43 */ + {{0xAD,0x7F,0x91,0x8E,0x9C,0x00,0x02,0x82, + 0x49,0xF5,0x00,0x83,0xFF,0x4A,0x90}}, /* 0x44 */ + {{0xCD,0x9F,0x91,0xA7,0x19,0x00,0x07,0x60, + 0xE6,0xFF,0xC0,0x83,0xBF,0xE7,0x90}}, /* 0x45 */ + {{0xD3,0x9F,0x97,0xAB,0x1F,0x00,0x07,0x60, + 0xF1,0xFF,0xC0,0x83,0xBF,0xF2,0x90}}, /* 0x46 */ + {{0xD7,0x9F,0x9B,0xAC,0x1E,0x00,0x07,0x00, + 0x03,0xDE,0xC0,0x84,0xBF,0x04,0x90}} /* 0x47 */ +}; + +XGI330_CHTVRegDataStruct XGI_CHTVRegUNTSC[] = { + /* Index:000h,001h,002h,004h,003h,005h,006h,007h,008h,015h,01Fh,00Ch,00Dh,00Eh,00Fh,010h */ + {{ 0x4A,0x77,0xBB,0x94,0x84,0x48,0xFE,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 00 (640x200,640x400) */ + {{ 0x4A,0x77,0xBB,0x94,0x84,0x48,0xFE,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 01 (640x350) */ + {{ 0x4A,0x77,0xBB,0x94,0x84,0x48,0xFE,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 02 (720x400) */ + {{ 0x4A,0x77,0xBB,0x94,0x84,0x48,0xFE,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 03 (720x350) */ + {{ 0x6A,0x77,0xBB,0x6E,0x84,0x2E,0x02,0x5A,0x04,0x00,0x80,0x20,0x7E,0x80,0x97,0x00 }},/* 04 (640x480) ;;5/6/02 */ + {{ 0xCF,0x77,0xB7,0xC8,0x84,0x3B,0x02,0x5A,0x04,0x00,0x80,0x19,0x88,0xAE,0xA3,0x00 }},/* 05 (800x600) ;;1/12/02 */ + {{ 0xEE,0x77,0xBB,0x66,0x87,0x32,0x01,0x5A,0x04,0x00,0x80,0x1B,0xD4,0x2F,0x6F,0x00 }}/* 06 (1024x768) ;;5/6/02 */ + }; + +XGI330_CHTVRegDataStruct XGI_CHTVRegONTSC[]= { + /* Index:000h,001h,002h,004h,003h,005h,006h,007h,008h,015h,01Fh,00Ch,00Dh,00Eh,00Fh,010h */ + {{ 0x49,0x77,0xBB,0x7B,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 00 (640x200,640x400) */ + {{ 0x49,0x77,0xBB,0x7B,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 01 (640x350) */ + {{ 0x49,0x77,0xBB,0x7B,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 02 (720x400) */ + {{ 0x49,0x77,0xBB,0x7B,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 03 (720x350) */ + {{ 0x69,0x77,0xBB,0x6E,0x84,0x1E,0x00,0x5A,0x04,0x00,0x80,0x25,0x1A,0x80,0x26,0x00 }},/* 04 (640x480) ;;5/6/02 */ + {{ 0xCE,0x77,0xB7,0xB6,0x83,0x2C,0x02,0x5A,0x04,0x00,0x80,0x1C,0x00,0x82,0x97,0x00 }},/* 05 (800x600) ;;5/6/02 */ + {{ 0xED,0x77,0xBB,0x66,0x8C,0x21,0x02,0x5A,0x04,0x00,0x80,0x1F,0xA0,0x7E,0x73,0x00 }}/* 06 (1024x768) ;;5/6/02 */ + }; + +XGI330_CHTVRegDataStruct XGI_CHTVRegUPAL[]= { + /* Index:000h,001h,002h,004h,003h,005h,006h,007h,008h,015h,01Fh,00Ch,00Dh,00Eh,00Fh,010h */ + {{ 0x41,0x7F,0xB7,0x34,0xAD,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* ; 00 (640x200,640x400) */ + {{ 0x41,0x7F,0xB7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* ; 01 (640x350) */ + {{ 0x41,0x7F,0xB7,0x34,0xAD,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* ; 02 (720x400) */ + {{ 0x41,0x7F,0xB7,0x12,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* ; 03 (720x350) */ + {{ 0x61,0x7F,0xB7,0x99,0x84,0x35,0x04,0x5A,0x05,0x00,0x80,0x26,0x2A,0x55,0x5D,0x00 }},/* ; 04 (640x480) */ + {{ 0xC3,0x7F,0xB7,0x7A,0x84,0x40,0x02,0x5A,0x05,0x00,0x80,0x1F,0x84,0x3D,0x28,0x00 }},/* ; 05 (800x600) ;;1/12/02 */ + {{ 0xE5,0x7F,0xB7,0x1D,0xA7,0x3E,0x04,0x5A,0x05,0x00,0x80,0x20,0x3E,0xE4,0x22,0x00 }}/* ; 06 (1024x768) ;;1/12/02 */ + }; + +XGI330_CHTVRegDataStruct XGI_CHTVRegOPAL[]={ + /* Index:000,0x01,0x02,0x04,0x03,0x05,0x06,0x07,0x08,0x15,0x1F,0x0C,0x0D,0x0E,0x0F,0x10h */ + {{ 0x41,0x7F,0xB7,0x36,0xAD,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 00 (640x200,640x400) */ + {{ 0x41,0x7F,0xB7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 01 (640x350) */ + {{ 0x41,0x7F,0xB7,0x36,0xAD,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 02 (720x400) */ + {{ 0x41,0x7F,0xB7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 03 (720x350) */ + {{ 0x61,0x7F,0xB7,0x99,0x84,0x35,0x04,0x5A,0x05,0x00,0x80,0x26,0x2A,0x55,0x5D,0x00 }},/* 04 (640x480) */ + {{ 0xC1,0x7F,0xB7,0x4D,0x8C,0x1E,0x31,0x5A,0x05,0x00,0x80,0x26,0x78,0x19,0x34,0x00 }},/* 05 (800x600) ;;1/12/02 */ + {{ 0xE4,0x7F,0xB7,0x1E,0xAF,0x29,0x37,0x5A,0x05,0x00,0x80,0x25,0x8C,0xB2,0x2A,0x00 }}/* 06 (1024x768) ;;1/12/02 */ + }; + +UCHAR XGI_CH7017LV1024x768[]={0x60,0x02,0x00,0x07,0x40,0xED,0xA3, + 0xC8,0xC7,0xAC,0xE0,0x02}; +UCHAR XGI_CH7017LV1400x1050[]={0x60,0x03,0x11,0x00,0x40,0xE3,0xAD, + 0xDB,0xF6,0xAC,0xE0,0x02}; + + +/*add for new UNIVGABIOS*/ +XGI330_LCDDataStruct XGI_StLCD1024x768Data[]= +{ + { 62, 25, 800, 546,1344, 806}, + { 32, 15, 930, 546,1344, 806}, + { 62, 25, 800, 546,1344, 806}, /* chiawen for dot9 -> dot8 */ + { 104, 45, 945, 496,1344, 806}, + { 62, 25, 800, 546,1344, 806}, + { 31, 18,1008, 624,1344, 806}, + { 1, 1,1344, 806,1344, 806} +}; + +XGI330_LCDDataStruct XGI_ExtLCD1024x768Data[]= +{ + { 42, 25,1536, 419,1344, 806}, /* { 12, 5, 896, 512,1344, 806}, // alan 09/12/2003 */ + { 48, 25,1536, 369,1344, 806}, /* { 12, 5, 896, 510,1344, 806}, // alan 09/12/2003 */ + { 42, 25,1536, 419,1344, 806}, /* { 32, 15,1008, 505,1344, 806}, // alan 09/12/2003 */ + { 48, 25,1536, 369,1344, 806}, /* { 32, 15,1008, 514,1344, 806}, // alan 09/12/2003 */ + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806}, + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806}, + { 12, 5, 896, 500,1344, 806}, + { 42, 25,1024, 625,1344, 806}, + { 1, 1,1344, 806,1344, 806} +}; + +/*XGI330_LCDDataStruct XGI_St2LCD1024x768Data[]= +{ + { 62, 25, 800, 546,1344, 806}, + { 32, 15, 930, 546,1344, 806}, + { 62, 25, 800, 546,1344, 806}, + { 104, 45, 945, 496,1344, 806}, + { 62, 25, 800, 546,1344, 806}, + { 31, 18,1008, 624,1344, 806}, + { 1, 1,1344, 806,1344, 806} +};*/ + +XGI330_LCDDataStruct XGI_CetLCD1024x768Data[]= +{ + { 1,1,1344,806,1344,806 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + { 1,1,1344,806,1344,806 }, /* 01 (320x350,640x350) */ + { 1,1,1344,806,1344,806 }, /* 02 (360x400,720x400) */ + { 1,1,1344,806,1344,806 }, /* 03 (720x350) */ + { 1,1,1344,806,1344,806 }, /* 04 (640x480x60Hz) */ + { 1,1,1344,806,1344,806 }, /* 05 (800x600x60Hz) */ + { 1,1,1344,806,1344,806 } /* 06 (1024x768x60Hz) */ +}; + +XGI330_LCDDataStruct XGI_StLCD1280x1024Data[]= +{ + { 22, 5, 800, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 13, 5,1024, 675,1560,1152}, + { 16, 9,1266, 804,1688,1072}, + { 1, 1,1688,1066,1688,1066} +}; + +XGI330_LCDDataStruct XGI_ExtLCD1280x1024Data[]= +{ + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 501,1688,1066}, + { 211, 60,1024, 508,1688,1066}, + { 211, 60,1024, 500,1688,1066}, + { 211, 75,1024, 625,1688,1066}, + { 211, 120,1280, 798,1688,1066}, + { 1, 1,1688,1066,1688,1066} +}; + +XGI330_LCDDataStruct XGI_St2LCD1280x1024Data[]= +{ + { 22, 5, 800, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 176, 45, 900, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 13, 5,1024, 675,1560,1152}, + { 16, 9,1266, 804,1688,1072}, + { 1, 1,1688,1066,1688,1066} +}; + +XGI330_LCDDataStruct XGI_CetLCD1280x1024Data[]= +{ + { 1,1,1688,1066,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 1,1,1688,1066,1688,1066 }, /* 01 (320x350,640x350) */ + { 1,1,1688,1066,1688,1066 }, /* 02 (360x400,720x400) */ + { 1,1,1688,1066,1688,1066 }, /* 03 (720x350) */ + { 1,1,1688,1066,1688,1066 }, /* 04 (640x480x60Hz) */ + { 1,1,1688,1066,1688,1066 }, /* 05 (800x600x60Hz) */ + { 1,1,1688,1066,1688,1066 }, /* 06 (1024x768x60Hz) */ + { 1,1,1688,1066,1688,1066 }, /* 07 (1280x1024x60Hz) */ + { 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LCDDataStruct XGI_StLCD1400x1050Data[]= +{ + { 211,100,2100,408,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 211,64,1536,358,1688,1066 }, /* 01 (320x350,640x350) */ + { 211,100,2100,408,1688,1066 }, /* 02 (360x400,720x400) */ + { 211,64,1536,358,1688,1066 }, /* 03 (720x350) */ + { 211,48,840,488,1688,1066 }, /* 04 (640x480x60Hz) */ + { 211,72,1008,609,1688,1066 }, /* 05 (800x600x60Hz) */ + { 211,128,1400,776,1688,1066 }, /* 06 (1024x768x60Hz) */ + { 1,1,1688,1066,1688,1066 }, /* 07 (1280x1024x60Hz w/o Scaling) */ + { 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LCDDataStruct XGI_ExtLCD1400x1050Data[]= +{ + { 211,100,2100,408,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 211,64,1536,358,1688,1066 }, /* 01 (320x350,640x350) */ + { 211,100,2100,408,1688,1066 }, /* 02 (360x400,720x400) */ + { 211,64,1536,358,1688,1066 }, /* 03 (720x350) */ + { 211,48,840,488,1688,1066 }, /* 04 (640x480x60Hz) */ + { 211,72,1008,609,1688,1066 }, /* 05 (800x600x60Hz) */ + { 211,128,1400,776,1688,1066 }, /* 06 (1024x768x60Hz) */ + { 1,1,1688,1066,1688,1066 }, /* 07 (1280x1024x60Hz w/o Scaling) */ + { 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LCDDataStruct XGI_ExtLCD1600x1200Data[]= +{ + { 4,1,1620,420,2160,1250 }, /* { 3,1,2160,425,2160,1250 }, // 00 (320x200,320x400,640x200,640x400) // alan 10/14/2003 */ + { 27,7,1920,375,2160,1250 }, /* 01 (320x350,640x350) */ + { 4,1,1620,420,2160,1250 }, /* { 3,1,2160,425,2160,1250 }, // 02 (360x400,720x400) // alan 10/14/2003 */ + { 27,7,1920,375,2160,1250 }, /* 03 (720x350) */ + { 27,4,800,500,2160,1250 }, /* 04 (640x480x60Hz) */ + { 4,1,1080,625,2160,1250 }, /* 05 (800x600x60Hz) */ + { 5,2,1350,800,2160,1250 }, /* 06 (1024x768x60Hz) */ + { 27,16,1500,1064,2160,1250 }, /* 07 (1280x1024x60Hz) */ + { 9,7,1920,1106,2160,1250 }, /* 08 (1400x1050x60Hz) */ + { 1,1,2160,1250,2160,1250 } /* 09 (1600x1200x60Hz) ;302lv */ +}; + +XGI330_LCDDataStruct XGI_StLCD1600x1200Data[]= +{ + { 27,4,800,500,2160,1250 },/* 00 (320x200,320x400,640x200,640x400) */ + { 27,4,800,500,2160,1250 },/* 01 (320x350,640x350) */ + { 27,4,800,500,2160,1250 },/* 02 (360x400,720x400) */ + { 27,4,800,500,2160,1250 },/* 03 (720x350) */ + { 27,4,800,500,2160,1250 },/* 04 (320x240,640x480) */ + { 4,1,1080,625,2160,1250 },/* 05 (400x300,800x600) */ + { 5,2,1350,800,2160,1250 },/* 06 (512x384,1024x768) */ + { 135,88,1600,1100,2160,1250 },/* 07 (1280x1024) */ + { 1,1,1800,1500,2160,1250 },/* 08 (1400x1050) */ + { 1,1,2160,1250,2160,1250 } /* 09 (1600x1200) */ +}; + +XGI330_LCDDataStruct XGI_CetLCD1400x1050Data[]= +{ + { 1,1,1688,1066,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 1,1,1688,1066,1688,1066 }, /* 01 (320x350,640x350) */ + { 1,1,1688,1066,1688,1066 }, /* 02 (360x400,720x400) */ + { 1,1,1688,1066,1688,1066 }, /* 03 (720x350) */ + { 1,1,1688,1066,1688,1066 }, /* 04 (640x480x60Hz) */ + { 1,1,1688,1066,1688,1066 }, /* 05 (800x600x60Hz) */ + { 1,1,1688,1066,1688,1066 }, /* 06 (1024x768x60Hz) */ + { 1,1,1688,1066,1688,1066 }, /* 07 (1280x1024x60Hz) */ + { 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LCDDataStruct XGI_NoScalingData[]= +{ + { 1, 1, 800, 449, 800, 449}, + { 1, 1, 800, 449, 800, 449}, + { 1, 1, 900, 449, 900, 449}, + { 1, 1, 900, 449, 900, 449}, + { 1, 1, 800, 525, 800, 525}, + { 1, 1,1056, 628,1056, 628}, + { 1, 1,1344, 806,1344, 806}, + { 1, 1,1688,1066,1688,1066} +}; + +XGI330_LCDDataStruct XGI_ExtLCD1024x768x75Data[]= +{ + {42,25,1536,419,1344,806 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + {48,25,1536,369,1344,806 }, /* ; 01 (320x350,640x350) */ + {42,25,1536,419,1344,806 }, /* ; 02 (360x400,720x400) */ + {48,25,1536,369,1344,806 }, /* ; 03 (720x350) */ + {8,5,1312,500,1312,800 }, /* ; 04 (640x480x75Hz) */ + {41,25,1024,625,1312,800 }, /* ; 05 (800x600x75Hz) */ + {1,1,1312,800,1312,800 } /* ; 06 (1024x768x75Hz) */ +}; + +XGI330_LCDDataStruct XGI_StLCD1024x768x75Data[]= +{ + {42,25,1536,419,1344,806 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + {48,25,1536,369,1344,806 }, /* ; 01 (320x350,640x350) */ + {42,25,1536,419,1344,806 }, /* ; 02 (360x400,720x400) */ + {48,25,1536,369,1344,806 }, /* ; 03 (720x350) */ + {8,5,1312,500,1312,800 }, /* ; 04 (640x480x75Hz) */ + {41,25,1024,625,1312,800 }, /* ; 05 (800x600x75Hz) */ + {1,1,1312,800,1312,800 } /* ; 06 (1024x768x75Hz) */ +}; + +XGI330_LCDDataStruct XGI_CetLCD1024x768x75Data[]= +{ + {1,1,1312,800,1312,800}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {1,1,1312,800,1312,800}, /* ; 01 (320x350,640x350) */ + {1,1,1312,800,1312,800}, /* ; 02 (360x400,720x400) */ + {1,1,1312,800,1312,800}, /* ; 03 (720x350) */ + {1,1,1312,800,1312,800}, /* ; 04 (640x480x75Hz) */ + {1,1,1312,800,1312,800}, /* ; 05 (800x600x75Hz) */ + {1,1,1312,800,1312,800} /* ; 06 (1024x768x75Hz) */ +}; + +XGI330_LCDDataStruct XGI_ExtLCD1280x1024x75Data[]= +{ + {211,60,1024,501,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + {211,60,1024,508,1688,1066 }, /* ; 01 (320x350,640x350) */ + {211,60,1024,501,1688,1066 }, /* ; 02 (360x400,720x400) */ + {211,60,1024,508,1688,1066 }, /* ; 03 (720x350) */ + {211,45,768,498,1688,1066 }, /* ; 04 (640x480x75Hz) */ + {211,75,1024,625,1688,1066 }, /* ; 05 (800x600x75Hz) */ + {211,120,1280,798,1688,1066 }, /* ; 06 (1024x768x75Hz) */ + {1,1,1688,1066,1688,1066 } /* ; 07 (1280x1024x75Hz) */ +}; + +XGI330_LCDDataStruct XGI_StLCD1280x1024x75Data[]= +{ + {211,60,1024,501,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + {211,60,1024,508,1688,1066 }, /* ; 01 (320x350,640x350) */ + {211,60,1024,501,1688,1066 }, /* ; 02 (360x400,720x400) */ + {211,60,1024,508,1688,1066 }, /* ; 03 (720x350) */ + {211,45,768,498,1688,1066 }, /* ; 04 (640x480x75Hz) */ + {211,75,1024,625,1688,1066 }, /* ; 05 (800x600x75Hz) */ + {211,120,1280,798,1688,1066}, /* ; 06 (1024x768x75Hz) */ + {1,1,1688,1066,1688,1066 } /* ; 07 (1280x1024x75Hz) */ +}; + +XGI330_LCDDataStruct XGI_CetLCD1280x1024x75Data[]= +{ + {1,1,1688,1066,1688,1066}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {1,1,1688,1066,1688,1066}, /* ; 01 (320x350,640x350) */ + {1,1,1688,1066,1688,1066}, /* ; 02 (360x400,720x400) */ + {1,1,1688,1066,1688,1066}, /* ; 03 (720x350) */ + {1,1,1688,1066,1688,1066}, /* ; 04 (640x480x75Hz) */ + {1,1,1688,1066,1688,1066}, /* ; 05 (800x600x75Hz) */ + {1,1,1688,1066,1688,1066}, /* ; 06 (1024x768x75Hz) */ + {1,1,1688,1066,1688,1066} /* ; 07 (1280x1024x75Hz) */ +}; + +XGI330_LCDDataStruct XGI_NoScalingDatax75[]= +{ + {1,1,800,449,800,449 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + {1,1,800,449,800,449 }, /* ; 01 (320x350,640x350) */ + {1,1,900,449,900,449 }, /* ; 02 (360x400,720x400) */ + {1,1,900,449,900,449 }, /* ; 03 (720x350) */ + {1,1,840,500,840,500 }, /* ; 04 (640x480x75Hz) */ + {1,1,1056,625,1056,625 }, /* ; 05 (800x600x75Hz) */ + {1,1,1312,800,1312,800 }, /* ; 06 (1024x768x75Hz) */ + {1,1,1688,1066,1688,1066}, /* ; 07 (1280x1024x75Hz) */ + {1,1,1688,1066,1688,1066}, /* ; 08 (1400x1050x75Hz) ;;[ycchen] 12/19/02 */ + {1,1,2160,1250,2160,1250}, /* ; 09 (1600x1200x75Hz) */ + {1,1,1688,806,1688,806 } /* ; 0A (1280x768x75Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[]= +{ + { 9,1057,0, 771 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + { 9,1057,0, 771 }, /* ; 01 (320x350,640x350) */ + { 9,1057,0, 771 }, /* ; 02 (360x400,720x400) */ + { 9,1057,0, 771 }, /* ; 03 (720x350) */ + { 9,1057,0, 771 }, /* ; 04 (640x480x60Hz) */ + { 9,1057,0, 771 }, /* ; 05 (800x600x60Hz) */ + { 9,1057,805, 770 } /* ; 06 (1024x768x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[]= +{ + { 9,1057,737,703 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + { 9,1057,686,651 }, /* ; 01 (320x350,640x350) */ + { 9,1057,737,703 }, /* ; 02 (360x400,720x400) */ + { 9,1057,686,651 }, /* ; 03 (720x350) */ + { 9,1057,776,741 }, /* ; 04 (640x480x60Hz) */ + { 9,1057, 0 ,771 }, /* ; 05 (800x600x60Hz) */ + { 9,1057,805,770 } /* ; 06 (1024x768x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[]= +{ + { 1152,856,622,587 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + { 1152,856,597,562 }, /* ; 01 (320x350,640x350) */ + { 1152,856,622,587 }, /* ; 02 (360x400,720x400) */ + { 1152,856,597,562 }, /* ; 03 (720x350) */ + { 1152,856,662,627 }, /* ; 04 (640x480x60Hz) */ + { 1232,936,722,687 }, /* ; 05 (800x600x60Hz) */ + { 0,1048,805,770 } /* ; 06 (1024x768x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[]= +{ + { 18,1346,981,940 },/* 00 (320x200,320x400,640x200,640x400) */ + { 18,1346,926,865 },/* 01 (320x350,640x350) */ + { 18,1346,981,940 },/* 02 (360x400,720x400) */ + { 18,1346,926,865 },/* 03 (720x350) */ + { 18,1346,0,1025 },/* 04 (640x480x60Hz) */ + { 18,1346,0,1025 },/* 05 (800x600x60Hz) */ + { 18,1346,1065,1024 },/* 06 (1024x768x60Hz) */ + { 18,1346,1065,1024 }/* 07 (1280x1024x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[]= +{ + { 18,1346,970,907 },/* 00 (320x200,320x400,640x200,640x400) */ + { 18,1346,917,854 },/* 01 (320x350,640x350) */ + { 18,1346,970,907 },/* 02 (360x400,720x400) */ + { 18,1346,917,854 },/* 03 (720x350) */ + { 18,1346,0,1025 },/* 04 (640x480x60Hz) */ + { 18,1346,0,1025 },/* 05 (800x600x60Hz) */ + { 18,1346,1065,1024 },/* 06 (1024x768x60Hz) */ + { 18,1346,1065,1024 }/* 07 (1280x1024x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[]= +{ + { 1368,1008,752,711 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 1368,1008,729,688 }, /* 01 (320x350,640x350) */ + { 1368,1008,752,711 }, /* 02 (360x400,720x400) */ + { 1368,1008,729,688 }, /* 03 (720x350) */ + { 1368,1008,794,753 }, /* 04 (640x480x60Hz) */ + { 1448,1068,854,813 }, /* 05 (800x600x60Hz) */ + { 1560,1200,938,897 }, /* 06 (1024x768x60Hz) */ + { 18,1346,1065,1024 } /* 07 (1280x1024x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[]= +{ + { 9,1337,981,940 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + { 9,1337,926,884 }, /* ; 01 (320x350,640x350) alan, 2003/09/30 */ + { 9,1337,981,940 }, /* ; 02 (360x400,720x400) */ + { 9,1337,926,884 }, /* ; 03 (720x350) alan, 2003/09/30 */ + { 9,1337,0,1025 }, /* ; 04 (640x480x60Hz) */ + { 9,1337,0,1025 }, /* ; 05 (800x600x60Hz) */ + { 9,1337,1065,1024 }, /* ; 06 (1024x768x60Hz) */ + { 9,1337,1065,1024 } /* ; 07 (1280x1024x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[]= +{ + { 9,1337,970,907 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + { 9,1337,917,854 }, /* ; 01 (320x350,640x350) */ + { 9,1337,970,907 }, /* ; 02 (360x400,720x400) */ + { 9,1337,917,854 }, /* ; 03 (720x350) */ + { 9,1337,0,1025 }, /* ; 04 (640x480x60Hz) */ + { 9,1337,0,1025 }, /* ; 05 (800x600x60Hz) */ + { 9,1337,1065,1024 }, /* ; 06 (1024x768x60Hz) */ + { 9,1337,1065,1024 } /* ; 07 (1280x1024x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[]= +{ + { 1368,1008,752,711 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 1368,1008,729,688 }, /* 01 (320x350,640x350) */ + { 1368,1008,752,711 }, /* 02 (360x400,720x400) */ + { 1368,1008,729,688 }, /* 03 (720x350) */ + { 1368,1008,794,753 }, /* 04 (640x480x60Hz) */ + { 1448,1068,854,813 }, /* 05 (800x600x60Hz) */ + { 1560,1200,938,897 }, /* 06 (1024x768x60Hz) */ + { 9,1337,1065,1024 } /* 07 (1280x1024x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_StLCDDLDes1400x1050Data[]= +{ + { 18,1464,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 18,1464,0,1051 }, /* 01 (320x350,640x350) */ + { 18,1464,0,1051 }, /* 02 (360x400,720x400) */ + { 18,1464,0,1051 }, /* 03 (720x350) */ + { 18,1464,0,1051 }, /* 04 (640x480x60Hz) */ + { 18,1464,0,1051 }, /* 05 (800x600x60Hz) */ + { 18,1464,0,1051 }, /* 06 (1024x768x60Hz) */ + { 1646,1406,1053,1038 }, /* 07 (1280x1024x60Hz) */ + { 18,1464,0,1051 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1400x1050Data[]= +{ + { 18,1464,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 18,1464,0,1051 }, /* 01 (320x350,640x350) */ + { 18,1464,0,1051 }, /* 02 (360x400,720x400) */ + { 18,1464,0,1051 }, /* 03 (720x350) */ + { 18,1464,0,1051 }, /* 04 (640x480x60Hz) */ + { 18,1464,0,1051 }, /* 05 (800x600x60Hz) */ + { 18,1464,0,1051 }, /* 06 (1024x768x60Hz) */ + { 1646,1406,1053,1038 }, /* 07 (1280x1024x60Hz) */ + { 18,1464,0,1051 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_StLCDDes1400x1050Data[]= +{ + { 9,1455,0,1051 },/* 00 (320x200,320x400,640x200,640x400) */ + { 9,1455,0,1051 },/* 01 (320x350,640x350) */ + { 9,1455,0,1051 },/* 02 (360x400,720x400) */ + { 9,1455,0,1051 },/* 03 (720x350) */ + { 9,1455,0,1051 },/* 04 (640x480x60Hz) */ + { 9,1455,0,1051 },/* 05 (800x600x60Hz) */ + { 9,1455,0,1051 },/* 06 (1024x768x60Hz) */ + { 1637,1397,1053,1038 },/* 07 (1280x1024x60Hz) */ + { 9,1455,0,1051 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_ExtLCDDes1400x1050Data[]= +{ + { 9,1455,0,1051 },/* 00 (320x200,320x400,640x200,640x400) */ + { 9,1455,0,1051 },/* 01 (320x350,640x350) */ + { 9,1455,0,1051 },/* 02 (360x400,720x400) */ + { 9,1455,0,1051 },/* 03 (720x350) */ + { 9,1455,0,1051 },/* 04 (640x480x60Hz) */ + { 9,1455,0,1051 },/* 05 (800x600x60Hz) */ + { 9,1455,0,1051 },/* 06 (1024x768x60Hz) */ + { 1637,1397,1053,1038 },/* 07 (1280x1024x60Hz) */ + { 9,1455,0,1051 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[]= +{ + { 1308,1068,781,766 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 1308,1068,781,766 }, /* 01 (320x350,640x350) */ + { 1308,1068,781,766 }, /* 02 (360x400,720x400) */ + { 1308,1068,781,766 }, /* 03 (720x350) */ + { 1308,1068,781,766 }, /* 04 (640x480x60Hz) */ + { 1388,1148,841,826 }, /* 05 (800x600x60Hz) */ + { 1490,1250,925,910 }, /* 06 (1024x768x60Hz) */ + { 1646,1406,1053,1038 }, /* 07 (1280x1024x60Hz) */ + { 18,1464,0,1051 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[]= +{ + { 0,1448,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 0,1448,0,1051 }, /* 01 (320x350,640x350) */ + { 0,1448,0,1051 }, /* 02 (360x400,720x400) */ + { 0,1448,0,1051 }, /* 03 (720x350) */ + { 0,1448,0,1051 } /* 04 (640x480x60Hz) */ +}; + + + +XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[]= +{ + { 18,1682,0,1201 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 18,1682,0,1201 }, /* 01 (320x350,640x350) */ + { 18,1682,0,1201 }, /* 02 (360x400,720x400) */ + { 18,1682,0,1201 }, /* 03 (720x350) */ + { 18,1682,0,1201 }, /* 04 (640x480x60Hz) */ + { 18,1682,0,1201 }, /* 05 (800x600x60Hz) */ + { 18,1682,0,1201 }, /* 06 (1024x768x60Hz) */ + { 18,1682,0,1201 }, /* 07 (1280x1024x60Hz) */ + { 18,1682,0,1201 }, /* 08 (1400x1050x60Hz) */ + { 18,1682,0,1201 } /* 09 (1600x1200x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[]= +{ + { 18,1682,1150,1101 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 18,1682,1083,1034 }, /* 01 (320x350,640x350) */ + { 18,1682,1150,1101 }, /* 02 (360x400,720x400) */ + { 18,1682,1083,1034 }, /* 03 (720x350) */ + { 18,1682,0,1201 }, /* 04 (640x480x60Hz) */ + { 18,1682,0,1201 }, /* 05 (800x600x60Hz) */ + { 18,1682,0,1201 }, /* 06 (1024x768x60Hz) */ + { 18,1682,1232,1183 }, /* 07 (1280x1024x60Hz) */ + { 18,1682,0,1201 }, /* 08 (1400x1050x60Hz) */ + { 18,1682,0,1201 } /* 09 (1600x1200x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[]= +{ + { 9,1673,0,1201 },/* 00 (320x200,320x400,640x200,640x400) */ + { 9,1673,0,1201 },/* 01 (320x350,640x350) */ + { 9,1673,0,1201 },/* 02 (360x400,720x400) */ + { 9,1673,0,1201 },/* 03 (720x350) */ + { 9,1673,0,1201 },/* 04 (640x480x60Hz) */ + { 9,1673,0,1201 },/* 05 (800x600x60Hz) */ + { 9,1673,0,1201 },/* 06 (1024x768x60Hz) */ + { 9,1673,0,1201 },/* 07 (1280x1024x60Hz) */ + { 9,1673,0,1201 },/* 08 (1400x1050x60Hz) */ + { 9,1673,0,1201 } /* 09 (1600x1200x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_StLCDDes1600x1200Data[]= +{ + { 9,1673,1150,1101 },/* 00 (320x200,320x400,640x200,640x400) */ + { 9,1673,1083,1034 },/* 01 (320x350,640x350) */ + { 9,1673,1150,1101 },/* 02 (360x400,720x400) */ + { 9,1673,1083,1034 },/* 03 (720x350) */ + { 9,1673,0,1201 },/* 04 (640x480x60Hz) */ + { 9,1673,0,1201 },/* 05 (800x600x60Hz) */ + { 9,1673,0,1201 },/* 06 (1024x768x60Hz) */ + { 9,1673,1232,1183 },/* 07 (1280x1024x60Hz) */ + { 9,1673,0,1201 },/* 08 (1400x1050x60Hz) */ + { 9,1673,0,1201 } /* 09 (1600x1200x60Hz) */ +}; + +XGI330_LCDDataDesStruct2 XGI_NoScalingDesData[]= +{ + { 9,657,448,405,96,2 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 9,657,448,355,96,2 }, /* 01 (320x350,640x350) */ + { 9,657,448,405,96,2 }, /* 02 (360x400,720x400) */ + { 9,657,448,355,96,2 }, /* 03 (720x350) */ + { 9,657,1,483,96,2 }, /* 04 (640x480x60Hz) */ + { 9,849,627,600,128,4 }, /* 05 (800x600x60Hz) */ + { 9,1057,805,770,0136,6 }, /* 06 (1024x768x60Hz) */ + { 9,1337,0,1025,112,3 }, /* 07 (1280x1024x60Hz) */ + { 9,1457,0,1051,112,3 }, /* 08 (1400x1050x60Hz) }, //;[ycchen] 12/19/02 */ + { 9,1673,0,1201,192,3 }, /* 09 (1600x1200x60Hz) */ + { 9,1337,0,771,112,6 } /* 0A (1280x768x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768x75Data[]= /* ;;1024x768x75Hz */ +{ + {9,1049,0,769}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {9,1049,0,769}, /* ; 01 (320x350,640x350) */ + {9,1049,0,769}, /* ; 02 (360x400,720x400) */ + {9,1049,0,769}, /* ; 03 (720x350) */ + {9,1049,0,769}, /* ; 04 (640x480x75Hz) */ + {9,1049,0,769}, /* ; 05 (800x600x75Hz) */ + {9,1049,0,769} /* ; 06 (1024x768x75Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_StLCDDes1024x768x75Data[]= +{ + {9,1049,0,769}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {9,1049,0,769}, /* ; 01 (320x350,640x350) */ + {9,1049,0,769}, /* ; 02 (360x400,720x400) */ + {9,1049,0,769}, /* ; 03 (720x350) */ + {9,1049,0,769}, /* ; 04 (640x480x75Hz) */ + {9,1049,0,769}, /* ; 05 (800x600x75Hz) */ + {9,1049,0,769} /* ; 06 (1024x768x75Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[]= /* ;;1024x768x75Hz */ +{ + {1152,856,622,587}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {1152,856,597,562}, /* ; 01 (320x350,640x350) */ + {1192,896,622,587}, /* ; 02 (360x400,720x400) */ + {1192,896,597,562}, /* ; 03 (720x350) */ + {1129,857,656,625}, /* ; 04 (640x480x75Hz) */ + {1209,937,716,685}, /* ; 05 (800x600x75Hz) */ + {9,1049,0,769} /* ; 06 (1024x768x75Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024x75Data[]= /* ;;1280x1024x75Hz */ +{ + {18,1314,0,1025 },/* ; 00 (320x200,320x400,640x200,640x400) */ + {18,1314,0,1025 },/* ; 01 (320x350,640x350) */ + {18,1314,0,1025 },/* ; 02 (360x400,720x400) */ + {18,1314,0,1025 },/* ; 03 (720x350) */ + {18,1314,0,1025 },/* ; 04 (640x480x60Hz) */ + {18,1314,0,1025 },/* ; 05 (800x600x60Hz) */ + {18,1314,0,1025 },/* ; 06 (1024x768x60Hz) */ + {18,1314,0,1025 }/* ; 07 (1280x1024x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024x75Data[]= +{ + {18,1314,0,1025 },/* ; 00 (320x200,320x400,640x200,640x400) */ + {18,1314,0,1025 },/* ; 01 (320x350,640x350) */ + {18,1314,0,1025 },/* ; 02 (360x400,720x400) */ + {18,1314,0,1025 },/* ; 03 (720x350) */ + {18,1314,0,1025 },/* ; 04 (640x480x60Hz) */ + {18,1314,0,1025 },/* ; 05 (800x600x60Hz) */ + {18,1314,0,1025 },/* ; 06 (1024x768x60Hz) */ + {18,1314,0,1025 }/* ; 07 (1280x1024x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[]= /* 1280x1024x75Hz */ +{ + {1368,1008,752,711}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {1368,1008,729,688}, /* ; 01 (320x350,640x350) */ + {1408,1048,752,711}, /* ; 02 (360x400,720x400) */ + {1408,1048,729,688}, /* ; 03 (720x350) */ + {1377,985,794,753}, /* ; 04 (640x480x75Hz) */ + {1457,1065,854,813}, /* ; 05 (800x600x75Hz) */ + {1569,1177,938,897}, /* ; 06 (1024x768x75Hz) */ + {18,1314,0,1025} /* ; 07 (1280x1024x75Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024x75Data[]= /* ;;1280x1024x75Hz */ +{ + {9,1305,0,1025},/* ; 00 (320x200,320x400,640x200,640x400) */ + {9,1305,0,1025},/* ; 01 (320x350,640x350) */ + {9,1305,0,1025},/* ; 02 (360x400,720x400) */ + {9,1305,0,1025},/* ; 03 (720x350) */ + {9,1305,0,1025},/* ; 04 (640x480x60Hz) */ + {9,1305,0,1025},/* ; 05 (800x600x60Hz) */ + {9,1305,0,1025},/* ; 06 (1024x768x60Hz) */ + {9,1305,0,1025} /* ; 07 (1280x1024x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024x75Data[]= +{ + {9,1305,0,1025},/* ; 00 (320x200,320x400,640x200,640x400) */ + {9,1305,0,1025},/* ; 01 (320x350,640x350) */ + {9,1305,0,1025},/* ; 02 (360x400,720x400) */ + {9,1305,0,1025},/* ; 03 (720x350) */ + {9,1305,0,1025},/* ; 04 (640x480x60Hz) */ + {9,1305,0,1025},/* ; 05 (800x600x60Hz) */ + {9,1305,0,1025},/* ; 06 (1024x768x60Hz) */ + {9,1305,0,1025} /* ; 07 (1280x1024x60Hz) */ +}; + +XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024x75Data[]= /* 1280x1024x75Hz */ +{ + {1368,1008,752,711}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {1368,1008,729,688}, /* ; 01 (320x350,640x350) */ + {1408,1048,752,711}, /* ; 02 (360x400,720x400) */ + {1408,1048,729,688}, /* ; 03 (720x350) */ + {1377,985,794,753}, /* ; 04 (640x480x75Hz) */ + {1457,1065,854,813}, /* ; 05 (800x600x75Hz) */ + {1569,1177,938,897}, /* ; 06 (1024x768x75Hz) */ + {9,1305,0,1025} /* ; 07 (1280x1024x75Hz) */ +}; + +XGI330_LCDDataDesStruct2 XGI_NoScalingDesDatax75[]= /* Scaling LCD 75Hz */ +{ + {9,657,448,405,96,2}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {9,657,448,355,96,2}, /* ; 01 (320x350,640x350) */ + {9,738,448,405,108,2}, /* ; 02 (360x400,720x400) */ + {9,738,448,355,108,2}, /* ; 03 (720x350) */ + {9,665,0,481,64,3}, /* ; 04 (640x480x75Hz) */ + {9,825,0,601,80,3}, /* ; 05 (800x600x75Hz) */ + {9,1049,0,769,96,3}, /* ; 06 (1024x768x75Hz) */ + {9,1305,0,1025,144,3}, /* ; 07 (1280x1024x75Hz) */ + {9,1457,0,1051,112,3}, /* ; 08 (1400x1050x60Hz) ;;[ycchen] 12/19/02 */ + {9,1673,0,1201,192,3}, /* ; 09 (1600x1200x75Hz) */ + {9,1337,0,771,112,6} /* ; 0A (1280x768x60Hz) */ +}; + +XGI330_TVDataStruct XGI_StPALData[]= +{ + { 1, 1, 864, 525,1270, 400, 100, 0, 760}, + { 1, 1, 864, 525,1270, 350, 100, 0, 760}, + { 1, 1, 864, 525,1270, 400, 0, 0, 720}, + { 1, 1, 864, 525,1270, 350, 0, 0, 720}, + { 1, 1, 864, 525,1270, 480, 50, 0, 760}, + { 1, 1, 864, 525,1270, 600, 50, 0, 0} +}; + +XGI330_TVDataStruct XGI_ExtPALData[]= +{ + { 2, 1,1080, 463,1270, 500, 50, 0, 50}, + { 15, 7,1152, 413,1270, 500, 50, 0, 50}, + { 2, 1,1080, 463,1270, 500, 50, 0, 50}, + { 15, 7,1152, 413,1270, 500, 50, 0, 50}, + { 2, 1, 900, 543,1270, 500, 0, 0, 50}, + { 4, 3,1080, 663,1270, 500, 438, 0, 438}, + { 1, 1,1125, 831,1270, 500, 686, 0, 686}, /*301b*/ + { 3, 2,1080, 619,1270, 540, 438, 0, 438} +}; + +XGI330_TVDataStruct XGI_StNTSCData[]= +{ + { 1, 1, 858, 525,1270, 400, 50, 0, 760}, + { 1, 1, 858, 525,1270, 350, 50, 0, 640}, + { 1, 1, 858, 525,1270, 400, 0, 0, 720}, + { 1, 1, 858, 525,1270, 350, 0, 0, 720}, + { 1, 1, 858, 525,1270, 480, 0, 0, 760} +}; + +XGI330_TVDataStruct XGI_ExtNTSCData[]= +{ + { 9, 5, 1001, 453,1270, 420, 171, 0, 171}, + { 12, 5, 858, 403,1270, 420, 171, 0, 171}, + { 9, 5, 1001, 453,1270, 420, 171, 0, 171}, + { 12, 5, 858, 403,1270, 420, 171, 0, 171}, + { 143, 80, 836, 523,1270, 420, 224, 0, 0}, + { 143, 120,1008, 643,1270, 420, 0, 1, 0}, + { 1, 1,1120, 821,1516, 420, 0, 1, 0}, /*301b*/ + { 2, 1, 858, 503,1584, 480, 0, 1, 0}, + { 3, 2,1001, 533,1270, 420, 0, 0, 0} +}; + +XGI330_TVDataStruct XGI_St1HiTVData[]= +{ + { 1,1,892,563,690,800,0,0,0 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 1,1,892,563,690,700,0,0,0 }, /* 01 (320x350,640x350) */ + { 1,1,1000,563,785,800,0,0,0 }, /* 02 (360x400,720x400) */ + { 1,1,1000,563,785,700,0,0,0 }, /* 03 (720x350) */ + { 1,1,892,563,690,960,0,0,0 }, /* 04 (320x240,640x480) */ + { 8,5,1050,683,1648,960,0x150,1,0 } /* 05 (400x300,800x600) */ +}; + +XGI330_TVDataStruct XGI_St2HiTVData[]= +{ + { 3,1,840,483,1648,960,0x032,0,0 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 1,1,892,563,690,700,0,0,0 }, /* 01 (320x350,640x350) */ + { 3,1,840,483,1648,960,0x032,0,0 }, /* 02 (360x400,720x400) */ + { 1,1,1000,563,785,700,0,0,0 }, /* 03 (720x350) */ + { 5,2,840,563,1648,960,0x08D,1,0 }, /* 04 (320x240,640x480) */ + { 8,5,1050,683,1648,960,0x17C,1,0 } /* 05 (400x300,800x600) */ + +}; + +XGI330_TVDataStruct XGI_ExtHiTVData[]= +{ + { 6,1,840,563,1632,960,0,0,0 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 3,1,960,563,1632,960,0,0,0 }, /* 01 (320x350,640x350) */ + { 3,1,840,483,1632,960,0,0,0 }, /* 02 (360x400,720x400) */ + { 3,1,960,563,1632,960,0,0,0 }, /* 03 (720x350) */ + { 5,1,840,563,1648,960,0x166,1,0 }, /* 04 (320x240,640x480) */ + { 16,5,1050,683,1648,960,0x143,1,0 }, /* 05 (400x300,800x600) */ + { 25,12,1260,851,1648,960,0x032,0,0 }, /* 06 (512x384,1024x768) */ + { 5,4,1575,1124,1648,960,0x128,0,0 }, /* 07 (1280x1024) */ + { 4,1,1050,563,1548,960,0x143,1,0 }, /* 08 (800x480) */ + { 5,2,1400,659,1648,960,0x032,0,0 }, /* 09 (1024x576) */ + { 8,5,1750,803,1648,960,0x128,0,0 } /* 0A (1280x720) */ + +}; + +XGI330_TVDataStruct XGI_ExtYPbPr525iData[]= +{ + { 9, 5, 1001, 453,1270, 420, 171, 0, 171}, + { 12, 5, 858, 403,1270, 420, 171, 0, 171}, + { 9, 5, 1001, 453,1270, 420, 171, 0, 171}, + { 12, 5, 858, 403,1270, 420, 171, 0, 171}, + { 143, 80, 836, 523,1250, 420, 224, 0, 0}, + { 143, 120,1008, 643,1250, 420, 0, 1, 0}, + { 1, 1,1120, 821,1516, 420, 0, 1, 0}, /*301b*/ + { 2, 1, 858, 503,1584, 480, 0, 1, 0}, + { 3, 2,1001, 533,1250, 420, 0, 0, 0} +}; + +XGI330_TVDataStruct XGI_StYPbPr525iData[]= +{ + { 1, 1, 858, 525,1270, 400, 50, 0, 760}, + { 1, 1, 858, 525,1270, 350, 50, 0, 640}, + { 1, 1, 858, 525,1270, 400, 0, 0, 720}, + { 1, 1, 858, 525,1270, 350, 0, 0, 720}, + { 1, 1, 858, 525,1270, 480, 0, 0, 760}, +}; + +XGI330_TVDataStruct XGI_ExtYPbPr525pData[]= +{ + { 9, 5, 1001, 453,1270, 420, 171, 0, 171}, + { 12, 5, 858, 403,1270, 420, 171, 0, 171}, + { 9, 5, 1001, 453,1270, 420, 171, 0, 171}, + { 12, 5, 858, 403,1270, 420, 171, 0, 171}, + { 143, 80, 836, 523,1270, 420, 224, 0, 0}, + { 143, 120,1008, 643,1270, 420, 0, 1, 0}, + { 1, 1,1120, 821,1516, 420, 0, 1, 0}, /*301b*/ + { 2, 1, 858, 503,1584, 480, 0, 1, 0}, + { 3, 2,1001, 533,1270, 420, 0, 0, 0} + }; + +XGI330_TVDataStruct XGI_StYPbPr525pData[]= +{ + { 1, 1,1716, 525,1270, 400, 50, 0, 760}, + { 1, 1,1716, 525,1270, 350, 50, 0, 640}, + { 1, 1,1716, 525,1270, 400, 0, 0, 720}, + { 1, 1,1716, 525,1270, 350, 0, 0, 720}, + { 1, 1,1716, 525,1270, 480, 0, 0, 760}, +}; + +XGI330_TVDataStruct XGI_ExtYPbPr750pData[]= +{ + { 3, 1, 935, 470,1130, 680, 50, 0, 0}, /* 00 (320x200,320x400,640x200,640x400) */ + { 24, 7, 935, 420,1130, 680, 50, 0, 0}, /* 01 (320x350,640x350) */ + { 3, 1, 935, 470,1130, 680, 50, 0, 0}, /* 02 (360x400,720x400) */ + { 24, 7, 935, 420,1130, 680, 50, 0, 0}, /* 03 (720x350) */ + { 2, 1,1100, 590,1130, 640, 50, 0, 0}, /* 04 (320x240,640x480) */ + { 3, 2,1210, 690,1130, 660, 50, 0, 0}, /* 05 (400x300,800x600) */ + { 1, 1,1375, 878,1130, 640, 638, 0, 0}, /* 06 (1024x768) */ + { 2, 1, 858, 503,1130, 480, 0, 1, 0}, /* 07 (720x480) */ + { 5, 4,1815, 570,1130, 660, 50, 0, 0}, + { 5, 3,1100, 686,1130, 640, 50, 1, 0}, + { 10, 9,1320, 830,1130, 640, 50, 0, 0} +}; + +XGI330_TVDataStruct XGI_StYPbPr750pData[]= +{ + { 1, 1,1650, 750,1280, 400, 50, 0, 760}, + { 1, 1,1650, 750,1280, 350, 50, 0, 640}, + { 1, 1,1650, 750,1280, 400, 0, 0, 720}, + { 1, 1,1650, 750,1280, 350, 0, 0, 720}, + { 1, 1,1650, 750,1280, 480, 0, 0, 760}, +}; + +UCHAR XGI330_NTSCTiming[] = { + 0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c, + 0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b, + 0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17, + 0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02, + 0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50, + 0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00}; + +UCHAR XGI330_PALTiming[] = { + 0x21,0x5A,0x35,0x6e,0x04,0x38,0x3d,0x70, + 0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d, + 0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b, + 0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17, + 0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02, + 0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63, + 0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00}; + +UCHAR XGI330_HiTVExtTiming[] = +{ + 0x2D,0x60,0x2C,0x5F,0x08,0x31,0x3A,0x64, + 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D, + 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F, + 0x64,0x90,0x33,0x8C,0x18,0x36,0x3E,0x13, + 0x2A,0xDE,0x2A,0x44,0x40,0x2A,0x44,0x40, + 0x8E,0x8E,0x82,0x07,0x0B, + 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x14,0x3D,0x63,0x4F, + 0x27,0x00,0xfc,0xff,0x6a,0x00 + +}; + +UCHAR XGI330_HiTVSt1Timing[] = +{ + 0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x65, + 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D, + 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F, + 0x65,0x90,0x7B,0xA8,0x03,0xF0,0x87,0x03, + 0x11,0x15,0x11,0xCF,0x10,0x11,0xCF,0x10, + 0x35,0x35,0x3B,0x69,0x1D, + 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x04,0x86,0xAF,0x5D, + 0x0E,0x00,0xfc,0xff,0x2d,0x00 +}; + +UCHAR XGI330_HiTVSt2Timing[] = +{ + 0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x64, + 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D, + 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F, + 0x64,0x90,0x33,0x8C,0x18,0x36,0x3E,0x13, + 0x2A,0xDE,0x2A,0x44,0x40,0x2A,0x44,0x40, + 0x8E,0x8E,0x82,0x07,0x0B, + 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x14,0x3D,0x63,0x4F, + 0x27,0x00,0xFC,0xff,0x6a,0x00 +}; + +UCHAR XGI330_HiTVTextTiming[] = +{ + 0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x65, + 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D, + 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F, + 0x65,0x90,0xE7,0xBC,0x03,0x0C,0x97,0x03, + 0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20, + 0xC8,0xC8,0x3B,0xD2,0x26, + 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x04,0x96,0x72,0x5C, + 0x11,0x00,0xFC,0xFF,0x32,0x00 +}; + +UCHAR XGI330_YPbPr750pTiming[] = +{ + 0x30,0x1d,0xe8,0x09,0x09,0xed,0x0c,0x0c, + 0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, + 0xed,0x50,0x70,0x9f,0x16,0x59,0x60,0x13, + 0x27,0x0b,0x27,0xfc,0x30,0x27,0x1c,0xb0, + 0x4b,0x4b,0x6f,0x2f,0x63, + 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x14,0x73,0x00,0x40, + 0x11,0x00,0xfc,0xff,0x32,0x00 +}; + +UCHAR XGI330_YPbPr525pTiming[] = +{ + 0x3E,0x11,0x06,0x09,0x0b,0x0c,0x0c,0x0c, + 0x98,0x0a,0x01,0x0d,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, + 0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4f,0x13, + 0xad,0x11,0xad,0x1d,0x40,0x8a,0x3d,0xb8, + 0x51,0x5e,0x60,0x49,0x7d, + 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x14,0x4B,0x43,0x41, + 0x11,0x00,0xFC,0xFF,0x32,0x00 +}; + +UCHAR XGI330_YPbPr525iTiming[] = +{ + 0x1B,0x21,0x03,0x09,0x05,0x06,0x0C,0x0C, + 0x94,0x49,0x01,0x0A,0x06,0x0D,0x04,0x0A, + 0x06,0x14,0x0D,0x04,0x0A,0x00,0x85,0x1B, + 0x0C,0x50,0x00,0x97,0x00,0xDA,0x4A,0x17, + 0x7D,0x05,0x4B,0x00,0x00,0xE2,0x00,0x02, + 0x03,0x0A,0x65,0x9D,0x08, + 0x92,0x8F,0x40,0x60,0x80,0x14,0x90,0x8C, + 0x60,0x14,0x4B,0x00,0x40, + 0x44,0x00,0xDB,0x02,0x3B,0x00 + +}; + +UCHAR XGI330_HiTVGroup3Data[] = +{ + 0x00,0x1A,0x22,0x63,0x62,0x22,0x08,0x5F, + 0x05,0x21,0xB2,0xB2,0x55,0x77,0x2A,0xA6, + 0x25,0x2F,0x47,0xFA,0xC8,0xFF,0x8E,0x20, + 0x8C,0x6E,0x60,0x2E,0x58,0x48,0x72,0x44, + 0x56,0x36,0x4F,0x6E,0x3F,0x80,0x00,0x80, + 0x4F,0x7F,0x03,0xA8,0x7D,0x20,0x1A,0xA9, + 0x14,0x05,0x03,0x7E,0x64,0x31,0x14,0x75, + 0x18,0x05,0x18,0x05,0x4C,0xA8,0x01 +}; + +UCHAR XGI330_HiTVGroup3Simu[] = +{ + 0x00,0x1A,0x22,0x63,0x62,0x22,0x08,0x95, + 0xDB,0x20,0xB8,0xB8,0x55,0x47,0x2A,0xA6, + 0x25,0x2F,0x47,0xFA,0xC8,0xFF,0x8E,0x20, + 0x8C,0x6E,0x60,0x15,0x26,0xD3,0xE4,0x11, + 0x56,0x36,0x4F,0x6E,0x3F,0x80,0x00,0x80, + 0x67,0x36,0x01,0x47,0x0E,0x10,0xBE,0xB4, + 0x01,0x05,0x03,0x7E,0x65,0x31,0x14,0x75, + 0x18,0x05,0x18,0x05,0x4C,0xA8,0x01 +}; + +UCHAR XGI330_HiTVGroup3Text[] = +{ + 0x00,0x1A,0x22,0x63,0x62,0x22,0x08,0xA7, + 0xF5,0x20,0xCE,0xCE,0x55,0x47,0x2A,0xA6, + 0x25,0x2F,0x47,0xFA,0xC8,0xFF,0x8E,0x20, + 0x8C,0x6E,0x60,0x18,0x2C,0x0C,0x20,0x22, + 0x56,0x36,0x4F,0x6E,0x3F,0x80,0x00,0x80, + 0x93,0x3C,0x01,0x50,0x2F,0x10,0xF4,0xCA, + 0x01,0x05,0x03,0x7E,0x65,0x31,0x14,0x75, + 0x18,0x05,0x18,0x05,0x4C,0xA8,0x01 +}; + +UCHAR XGI330_Ren525pGroup3[] = +{ + 0x00,0x14,0x15,0x25,0x55,0x15,0x0b,0x13, + 0xB1,0x41,0x62,0x62,0xFF,0xF4,0x45,0xa6, + 0x25,0x2F,0x67,0xF6,0xbf,0xFF,0x8E,0x20, + 0xAC,0xDA,0x60,0xFe,0x6A,0x9A,0x06,0x10, + 0xd1,0x04,0x18,0x0a,0xFF,0x80,0x00,0x80, + 0x3c,0x77,0x00,0xEF,0xE0,0x10,0xB0,0xE0, + 0x10,0x4F,0x0F,0x0F,0x05,0x0F,0x08,0x6E, + 0x1a,0x1F,0x25,0x2a,0x4C,0xAA,0x01 +}; + +UCHAR XGI330_Ren750pGroup3[] = +{ + 0x00,0x14,0x15,0x25,0x55,0x15,0x0b,0x7a, + 0x54,0x41,0xE7,0xE7,0xFF,0xF4,0x45,0xa6, + 0x25,0x2F,0x67,0xF6,0xbf,0xFF,0x8E,0x20, + 0xAC,0x6A,0x60,0x2b,0x52,0xCD,0x61,0x10, + 0x51,0x04,0x18,0x0a,0x1F,0x80,0x00,0x80, + 0xFF,0xA4,0x04,0x2B,0x94,0x21,0x72,0x94, + 0x26,0x05,0x01,0x0F,0xed,0x0F,0x0A,0x64, + 0x18,0x1D,0x23,0x28,0x4C,0xAA,0x01 +}; + +XGI_PanelDelayTblStruct XGI330_PanelDelayTbl[]= +{ +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}}, +{{0x00,0x00}} +}; + +XGI330_LVDSDataStruct XGI330_LVDS320x480Data_1[]= +{ + {848, 433,400,525}, + {848, 389,400,525}, + {848, 433,400,525}, + {848, 389,400,525}, + {848, 518,400, 525}, + {1056, 628,400,525}, + {400, 525,400,525}, + {800, 449,1000, 644}, + {800, 525,1000, 635} +}; + +XGI330_LVDSDataStruct XGI330_LVDS800x600Data_1[]= +{ + {848, 433,1060, 629}, + {848, 389,1060, 629}, + {848, 433,1060, 629}, + {848, 389,1060, 629}, + {848, 518,1060, 629}, + {1056, 628,1056, 628}, + {1056, 628,1056, 628}, + {800, 449,1000, 644}, + {800, 525,1000, 635} +}; + +XGI330_LVDSDataStruct XGI330_LVDS800x600Data_2[]= +{ + {1056, 628,1056, 628}, + {1056, 628,1056, 628}, + {1056, 628,1056, 628}, + {1056, 628,1056, 628}, + {1056, 628,1056, 628}, + {1056, 628,1056, 628}, + {1056, 628,1056, 628}, + {800, 449,1000, 644}, + {800, 525,1000, 635} +}; + +XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1[]= +{ + { 960 , 438 , 1344 , 806 } , /* 00 (320x200,320x400,640x200,640x400) */ + { 960 , 388 , 1344 , 806 } , /* 01 (320x350,640x350) */ + { 1040, 438 , 1344 , 806 } , /* 02 (360x400,720x400) */ + { 1040, 388 , 1344 , 806 } , /* 03 (720x350) */ + { 960 , 518 , 1344 , 806 } , /* 04 (320x240,640x480) */ + {1120 , 638 , 1344 , 806 } , /* 05 (400x300,800x600) */ + {1344 , 806 , 1344 , 806 } /* 06 (512x384,1024x768) */ +}; + + +XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2[]= +{ + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {800, 449,1280, 801}, + {800, 525,1280, 813} +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1[]= +{ + {1048, 442,1688, 1066}, + {1048, 392,1688, 1066}, + {1048, 442,1688, 1066}, + {1048, 392,1688, 1066}, + {1048, 522,1688, 1066}, + {1208, 642,1688, 1066}, + {1432, 810,1688, 1066}, + {1688, 1066,1688, 1066} +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2[]= +{ + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {800, 449,1280, 801}, + {800, 525,1280, 813} +}; +/* +XGI330_LVDSDataStruct XGI_LVDS1280x768Data_1[]= +{ + {768,438,1408,806}, + {768,388,1408,806}, + {768,438,1408,806}, + {768,388,1408,806}, + {768,518,1408,806}, + {928,638,1408,806}, + {1408,806,1408,806}, + {1408,806,1408,806}, + {1408,806,1408,806} +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x768Data_2[]= +{ + {1408, 806,1408, 806}, + {1408, 806,1408, 806}, + {1408, 806,1408, 806}, + {1408, 806,1408, 806}, + {1408, 806,1408, 806}, + {1408, 806,1408, 806}, + {1408, 806,1408, 806}, + {1408, 806,1408, 806}, + {1408, 806,1408, 806} +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x768NData_1[]= +{ + {704, 438,1344, 806}, + {704, 388,1344, 806}, + {704, 438,1344, 806}, + {704, 388,1344, 806}, + {704, 518,1344, 806}, + {864, 638,1344, 806}, + {1088, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806} +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x768NData_2[]= +{ + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806} +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x768SData_1[]= +{ + {1048,438,1688,806}, + {1048,388,1688,806}, + {1148,438,1688,806}, + {1148,388,1688,806}, + {1048,518,1688,806}, + {1208,638,1688,806}, + {1432,806,1688,806}, + {1688,806,1688,806}, + {1688,806,1688,806} +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x768SData_2[]= +{ + {1688,806,1688,806}, + {1688,806,1688,806}, + {1688,806,1688,806}, + {1688,806,1688,806}, + {1688,806,1688,806}, + {1688,806,1688,806}, + {1688,806,1688,806}, + {1688,806,1688,806}, + {1688,806,1688,806} +}; +*/ +XGI330_LVDSDataStruct XGI_LVDS1400x1050Data_1[]= +{ + {928,416,1688,1066}, + {928,366,1688,1066}, + {928,416,1688,1066}, + {928,366,1688,1066}, + {928,496,1688,1066}, + {1088,616,1688,1066}, + {1312,784,1688,1066}, + {1568,1040,1688,1066}, + {1688,1066,1688,1066} +}; + +XGI330_LVDSDataStruct XGI_LVDS1400x1050Data_2[]= +{ + {1688,1066,1688,1066}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066} +}; + +XGI330_LVDSDataStruct XGI_LVDS1600x1200Data_1[]= +{ /* ;;[ycchen] 12/05/02 LCDHTxLCDVT=2048x1320 */ + { 1088,520,2048,1320 },/* 00 (320x200,320x400,640x200,640x400) */ + { 1088,470,2048,1320 },/* 01 (320x350,640x350) */ + { 1088,520,2048,1320 },/* 02 (360x400,720x400) */ + { 1088,470,2048,1320 },/* 03 (720x350) */ + { 1088,600,2048,1320 },/* 04 (320x240,640x480) */ + { 1248,720,2048,1320 },/* 05 (400x300,800x600) */ + { 1472,888,2048,1320 },/* 06 (512x384,1024x768) */ + { 1728,1144,2048,1320 },/* 07 (640x512,1280x1024) */ + { 1848,1170,2048,1320 },/* 08 (1400x1050) */ + { 2048,1320,2048,1320 } /* 09 (1600x1200) */ +}; + +XGI330_LVDSDataStruct XGI_LVDSNoScalingData[]= +{ + { 800,449,800,449 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 800,449,800,449 }, /* 01 (320x350,640x350) */ + { 800,449,800,449 }, /* 02 (360x400,720x400) */ + { 800,449,800,449 }, /* 03 (720x350) */ + { 800,525,800,525 }, /* 04 (640x480x60Hz) */ + { 1056,628,1056,628 }, /* 05 (800x600x60Hz) */ + { 1344,806,1344,806 }, /* 06 (1024x768x60Hz) */ + { 1688,1066,1688,1066 }, /* 07 (1280x1024x60Hz) */ + { 1688,1066,1688,1066 }, /* 08 (1400x1050x60Hz) ;;[ycchen] 12/19/02 */ + { 2160,1250,2160,1250 }, /* 09 (1600x1200x60Hz) */ + { 1688,806,1688,806 } /* 0A (1280x768x60Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1x75[]= +{ + {960,438,1312,800 }, /* 00 (320x200,320x400,640x200,640x400) */ + {960,388,1312,800 }, /* 01 (320x350,640x350) */ + {1040,438,1312,800 }, /* 02 (360x400,720x400) */ + {1040,388,1312,800 }, /* 03 (720x350) */ + {928,512,1312,800 }, /* 04 (320x240,640x480) */ + {1088,632,1312,800 }, /* 05 (400x300,800x600) */ + {1312,800,1312,800 }, /* 06 (512x384,1024x768) */ +}; + + +XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2x75[]= +{ + {1312,800,1312,800}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {1312,800,1312,800}, /* ; 01 (320x350,640x350) */ + {1312,800,1312,800}, /* ; 02 (360x400,720x400) */ + {1312,800,1312,800}, /* ; 03 (720x350) */ + {1312,800,1312,800}, /* ; 04 (320x240,640x480) */ + {1312,800,1312,800}, /* ; 05 (400x300,800x600) */ + {1312,800,1312,800}, /* ; 06 (512x384,1024x768) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1x75[]= +{ + {1048,442,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + {1048,392,1688,1066 }, /* ; 01 (320x350,640x350) */ + {1128,442,1688,1066 }, /* ; 02 (360x400,720x400) */ + {1128,392,1688,1066 }, /* ; 03 (720x350) */ + {1048,522,1688,1066 }, /* ; 04 (320x240,640x480) */ + {1208,642,1688,1066 }, /* ; 05 (400x300,800x600) */ + {1432,810,1688,1066 }, /* ; 06 (512x384,1024x768) */ + {1688,1066,1688,1066 }, /* ; 06; 07 (640x512,1280x1024) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2x75[]= +{ + {1688,1066,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + {1688,1066,1688,1066 }, /* ; 01 (320x350,640x350) */ + {1688,1066,1688,1066 }, /* ; 02 (360x400,720x400) */ + {1688,1066,1688,1066 }, /* ; 03 (720x350) */ + {1688,1066,1688,1066 }, /* ; 04 (320x240,640x480) */ + {1688,1066,1688,1066 }, /* ; 05 (400x300,800x600) */ + {1688,1066,1688,1066 }, /* ; 06 (512x384,1024x768) */ + {1688,1066,1688,1066 }, /* ; 06; 07 (640x512,1280x1024) */ +}; + +XGI330_LVDSDataStruct XGI_LVDSNoScalingDatax75[]= +{ + {800,449,800,449 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + {800,449,800,449 }, /* ; 01 (320x350,640x350) */ + {900,449,900,449 }, /* ; 02 (360x400,720x400) */ + {900,449,900,449 }, /* ; 03 (720x350) */ + {800,500,800,500 }, /* ; 04 (640x480x75Hz) */ + {1056,625,1056,625 }, /* ; 05 (800x600x75Hz) */ + {1312,800,1312,800 }, /* ; 06 (1024x768x75Hz) */ + {1688,1066,1688,1066 }, /* ; 07 (1280x1024x75Hz) */ + {1688,1066,1688,1066 }, /* ; 08 (1400x1050x75Hz) ;;[ycchen] 12/19/02 */ + {2160,1250,2160,1250 }, /* ; 09 (1600x1200x75Hz) */ + {1688,806,1688,806 }, /* ; 0A (1280x768x75Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1[]= +{ + { 0,1048, 0, 771 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 0,1048, 0, 771 }, /* 01 (320x350,640x350) */ + { 0,1048, 0, 771 }, /* 02 (360x400,720x400) */ + { 0,1048, 0, 771 }, /* 03 (720x350) */ + { 0,1048, 0, 771 }, /* 04 (640x480x60Hz) */ + { 0,1048, 0, 771 }, /* 05 (800x600x60Hz) */ + { 0,1048, 805, 770 } /* 06 (1024x768x60Hz) */ +} ; + +XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2[]= +{ + { 1142, 856, 622, 587 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 1142, 856, 597, 562 }, /* 01 (320x350,640x350) */ + { 1142, 856, 622, 587 }, /* 02 (360x400,720x400) */ + { 1142, 856, 597, 562 }, /* 03 (720x350) */ + { 1142,1048, 722, 687 }, /* 04 (640x480x60Hz) */ + { 1232, 936, 722, 687 }, /* 05 (800x600x60Hz) */ + { 0,1048, 805, 771 } /* 06 (1024x768x60Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3[]= +{ + { 320, 24, 622, 587 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 320, 24, 597, 562 }, /* 01 (320x350,640x350) */ + { 320, 24, 622, 587 }, /* 02 (360x400,720x400) */ + { 320, 24, 597, 562 }, /* 03 (720x350) */ + { 320, 24, 722, 687 } /* 04 (640x480x60Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1[]= +{ + { 0,1328, 0, 1025 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 0,1328, 0, 1025 }, /* 01 (320x350,640x350) */ + { 0,1328, 0, 1025 }, /* 02 (360x400,720x400) */ + { 0,1328, 0, 1025 }, /* 03 (720x350) */ + { 0,1328, 0, 1025 }, /* 04 (640x480x60Hz) */ + { 0,1328, 0, 1025 }, /* 05 (800x600x60Hz) */ + { 0,1328, 0, 1025 }, /* 06 (1024x768x60Hz) */ + { 0,1328, 1065, 1024 } /* 07 (1280x1024x60Hz) */ +}; + + /* The Display setting for DE Mode Panel */ +XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2[]= +{ + { 1368,1008,752,711 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 1368,1008,729,688 }, /* 01 (320x350,640x350) */ + { 1408,1048,752,711 }, /* 02 (360x400,720x400) */ + { 1408,1048,729,688 }, /* 03 (720x350) */ + { 1368,1008,794,753 }, /* 04 (640x480x60Hz) */ + { 1448,1068,854,813 }, /* 05 (800x600x60Hz) */ + { 1560,1200,938,897 }, /* 06 (1024x768x60Hz) */ + { 0000,1328,0,1025 } /* 07 (1280x1024x60Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_1[]= +{ + { 0,1448,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 0,1448,0,1051 }, /* 01 (320x350,640x350) */ + { 0,1448,0,1051 }, /* 02 (360x400,720x400) */ + { 0,1448,0,1051 }, /* 03 (720x350) */ + { 0,1448,0,1051 }, /* 04 (640x480x60Hz) */ + { 0,1448,0,1051 }, /* 05 (800x600x60Hz) */ + { 0,1448,0,1051 }, /* 06 (1024x768x60Hz) */ + { 0,1448,0,1051 }, /* 07 (1280x1024x60Hz) */ + { 0,1448,0,1051 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_2[]= +{ + { 1308,1068, 781, 766 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 1308,1068, 781, 766 }, /* 01 (320x350,640x350) */ + { 1308,1068, 781, 766 }, /* 02 (360x400,720x400) */ + { 1308,1068, 781, 766 }, /* 03 (720x350) */ + { 1308,1068, 781, 766 }, /* 04 (640x480x60Hz) */ + { 1388,1148, 841, 826 }, /* 05 (800x600x60Hz) */ + { 1490,1250, 925, 910 }, /* 06 (1024x768x60Hz) */ + { 1608,1368,1053,1038 }, /* 07 (1280x1024x60Hz) */ + { 0,1448,0,1051 } /* 08 (1400x1050x60Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1600x1200Des_1[]= +{ + { 0,1664,0,1201 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 0,1664,0,1201 }, /* 01 (320x350,640x350) */ + { 0,1664,0,1201 }, /* 02 (360x400,720x400) */ + { 0,1664,0,1201 }, /* 03 (720x350) */ + { 0,1664,0,1201 }, /* 04 (640x480x60Hz) */ + { 0,1664,0,1201 }, /* 05 (800x600x60Hz) */ + { 0,1664,0,1201 }, /* 06 (1024x768x60Hz) */ + { 0,1664,0,1201 }, /* 07 (1280x1024x60Hz) */ + { 0,1664,0,1201 }, /* 08 (1400x1050x60Hz) */ + { 0,1664,0,1201 } /* 09 (1600x1200x60Hz) */ +}; + + + +XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesData[]= +{ + { 0, 648, 448, 405, 96, 2 }, /* 00 (320x200,320x400,640x200,640x400) */ + { 0, 648, 448, 355, 96, 2 }, /* 01 (320x350,640x350) */ + { 0, 648, 448, 405, 96, 2 }, /* 02 (360x400,720x400) */ + { 0, 648, 448, 355, 96, 2 }, /* 03 (720x350) */ + { 0, 648, 1, 483, 96, 2 }, /* 04 (640x480x60Hz) */ + { 0, 840, 627, 600, 128, 4 }, /* 05 (800x600x60Hz) */ + { 0,1048, 805, 770, 136, 6 }, /* 06 (1024x768x60Hz) */ + { 0,1328,0,1025, 112, 3 }, /* 07 (1280x1024x60Hz) */ + { 0,1438,0,1051, 112, 3 }, /* 08 (1400x1050x60Hz) ;;[ycchen] 12/19/02 */ + { 0,1664,0,1201, 192, 3 }, /* 09 (1600x1200x60Hz) */ + { 0,1328,0,0771, 112, 6 } /* 0A (1280x768x60Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1x75[]= /* ; 1024x768 Full-screen */ +{ + {0,1040,0,769}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {0,1040,0,769}, /* ; 01 (320x350,640x350) */ + {0,1040,0,769}, /* ; 02 (360x400,720x400) */ + {0,1040,0,769}, /* ; 03 (720x350) */ + {0,1040,0,769}, /* ; 04 (640x480x75Hz) */ + {0,1040,0,769}, /* ; 05 (800x600x75Hz) */ + {0,1040,0,769} /* ; 06 (1024x768x75Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2x75[]= /* ; 1024x768 center-screen (Enh. Mode) */ +{ + {1142, 856,622,587 }, /* 00 (320x200,320x400,640x200,640x400) */ + {1142, 856,597,562 }, /* 01 (320x350,640x350) */ + {1142, 856,622,587 }, /* 02 (360x400,720x400) */ + {1142, 856,597,562 }, /* 03 (720x350) */ + {1142,1048,722,687 }, /* 04 (640x480x60Hz) */ + {1232, 936,722,687 }, /* 05 (800x600x60Hz) */ + { 0,1048,805,771 } /* 06 (1024x768x60Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3x75[]= /* ; 1024x768 center-screen (St.Mode) */ +{ + {320,24,622,587 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + {320,24,597,562 }, /* ; 01 (320x350,640x350) */ + {320,24,622,587 }, /* ; 02 (360x400,720x400) */ + {320,24,597,562 }, /* ; 03 (720x350) */ + {320,24,722,687 } /* ; 04 (640x480x60Hz) */ +}; + +XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1x75[]= +{ + {0,1296,0,1025}, /* ; 00 (320x200,320x400,640x200,640x400) */ + {0,1296,0,1025}, /* ; 01 (320x350,640x350) */ + {0,1296,0,1025}, /* ; 02 (360x400,720x400) */ + {0,1296,0,1025}, /* ; 03 (720x350) */ + {0,1296,0,1025}, /* ; 04 (640x480x75Hz) */ + {0,1296,0,1025}, /* ; 05 (800x600x75Hz) */ + {0,1296,0,1025}, /* ; 06 (1024x768x75Hz) */ + {0,1296,0,1025} /* ; 07 (1280x1024x75Hz) */ +}; + +/* The Display setting for DE Mode Panel */ +XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2x75[]= /* [ycchen] 02/18/03 Set DE as default */ +{ + {1368,976,752,711 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + {1368,976,729,688 }, /* ; 01 (320x350,640x350) */ + {1408,976,752,711 }, /* ; 02 (360x400,720x400) */ + {1408,976,729,688 }, /* ; 03 (720x350) */ + {1368,976,794,753 }, /* ; 04 (640x480x75Hz) */ + {1448,1036,854,813}, /* ; 05 (800x600x75Hz) */ + {1560,1168,938,897}, /* ; 06 (1024x768x75Hz) */ + {0,1296,0,1025 } /* ; 07 (1280x1024x75Hz) */ +}; + +XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesDatax75[]= /* Scaling LCD 75Hz */ +{ + { 0,648,448,405,96,2 }, /* ; 00 (320x200,320x400,640x200,640x400) */ + { 0,648,448,355,96,2 }, /* ; 01 (320x350,640x350) */ + { 0,729,448,405,108,2 }, /* ; 02 (360x400,720x400) */ + { 0,729,448,355,108,2 }, /* ; 03 (720x350) */ + { 0,656,0,481,64,3 }, /* ; 04 (640x480x75Hz) */ + { 0,816,0,601,80,3 }, /* ; 05 (800x600x75Hz) */ + { 0,1040,0,769,96,3 }, /* ; 06 (1024x768x75Hz) */ + { 0,1296,0,1025,144,3 }, /* ; 07 (1280x1024x75Hz) */ + { 0,1448,0,1051,112,3 }, /* ; 08 (1400x1050x75Hz) ;;[ycchen] 12/19/02 */ + { 0,1664,0,1201,192,3 }, /* ; 09 (1600x1200x75Hz) */ + { 0,1328,0,771,112,6 } /* ; 0A (1280x768x75Hz) */ +}; + +XGI330_LVDSDataStruct XGI330_LVDS640x480Data_1[]= +{ + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 525, 800, 525}, + {1056, 628,1056, 628}, + {1056, 628,1056, 628}, + {1056, 628,1056, 628}, + {1056, 628,1056, 628} +}; + +XGI330_CHTVDataStruct XGI_CHTVUNTSCData[]= +{ + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {784, 600, 784, 600}, + {1064, 750,1064, 750} +}; + +XGI330_CHTVDataStruct XGI_CHTVONTSCData[]= +{ + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {784, 525, 784, 525}, + {1040, 700,1040, 700} +}; + +XGI330_CHTVDataStruct XGI_CHTVUPALData[]= +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {840, 750, 840, 750}, + {936, 836, 936, 836} +}; + +XGI330_CHTVDataStruct XGI_CHTVOPALData[]= +{ + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {1008, 625,1008, 625}, + {840, 625, 840, 625}, + {960, 750, 960, 750} +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_H[]= +{ + /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x4B,0x27,0x8F,0x32,0x1B,0x00,0x45,0x00 }}, /* 00 (320x) */ + {{ 0x4B,0x27,0x8F,0x2B,0x03,0x00,0x44,0x00 }}, /* 01 (360x) */ + {{ 0x55,0x31,0x99,0x46,0x1D,0x00,0x55,0x00 }}, /* 02 (400x) */ + {{ 0x63,0x3F,0x87,0x4A,0x93,0x00,0x01,0x00 }}, /* 03 (512x) */ + {{ 0x73,0x4F,0x97,0x55,0x86,0x00,0x05,0x00 }}, /* 04 (640x) */ + {{ 0x73,0x4F,0x97,0x55,0x86,0x00,0x05,0x00 }}, /* 05 (720x) */ + {{ 0x87,0x63,0x8B,0x69,0x1A,0x00,0x26,0x00 }}, /* 06 (800x) */ + {{ 0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00 }} /* 07 (1024x) */ +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_1_H[]= +{ + /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }}, /* 00 (320x) */ + {{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }}, /* 01 (360x) */ + {{ 0x60,0x31,0x84,0x3A,0x88,0x00,0x01,0x00 }}, /* 02 (400x) */ + {{ 0x6E,0x3F,0x92,0x48,0x96,0x00,0x01,0x00 }}, /* 03 (512x) */ + {{ 0x7E,0x4F,0x82,0x58,0x06,0x00,0x06,0x00 }}, /* 04 (640x) */ + {{ 0x7E,0x4F,0x82,0x58,0x06,0x00,0x06,0x00 }}, /* 05 (720x) */ + {{ 0x92,0x63,0x96,0x6C,0x1A,0x00,0x06,0x00 }}, /* 06 (800x) */ + {{ 0xAE,0x7F,0x92,0x88,0x96,0x00,0x02,0x00 }}, /* 07 (1024x) */ + {{ 0xCE,0x9F,0x92,0xA8,0x16,0x00,0x07,0x00 }} /* 08 (1280x) */ +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_2_H[]= +{ + /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }}, /* 00 (320x) */ + {{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }}, /* 01 (360x) */ + {{ 0x63,0x31,0x87,0x3D,0x8E,0x00,0x01,0x00 }}, /* 02 (400x) */ + {{ 0x63,0x3F,0x87,0x45,0x96,0x00,0x01,0x00 }}, /* 03 (512x) */ + {{ 0xA3,0x4F,0x87,0x6E,0x9F,0x00,0x06,0x00 }}, /* 04 (640x) */ + {{ 0xA3,0x4F,0x87,0x6E,0x9F,0x00,0x06,0x00 }}, /* 05 (720x) */ + {{ 0xA3,0x63,0x87,0x78,0x89,0x00,0x02,0x00 }}, /* 06 (800x) */ + {{ 0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00 }} /* 07 (1024x) */ +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_2_H[]= +{ + /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x7E,0x3B,0x9A,0x44,0x12,0x00,0x01,0x00 }}, /* 00 (320x) */ + {{ 0x7E,0x3B,0x9A,0x44,0x12,0x00,0x01,0x00 }}, /* 01 (360x) */ + {{ 0x7E,0x40,0x84,0x49,0x91,0x00,0x01,0x00 }}, /* 02 (400x) */ + {{ 0x7E,0x47,0x93,0x50,0x9E,0x00,0x01,0x00 }}, /* 03 (512x) */ + {{ 0xCE,0x77,0x8A,0x80,0x8E,0x00,0x02,0x00 }}, /* 04 (640x) */ + {{ 0xCE,0x77,0x8A,0x80,0x8E,0x00,0x02,0x00 }}, /* 05 (720x) */ + {{ 0xCE,0x81,0x94,0x8A,0x98,0x00,0x02,0x00 }}, /* 06 (800x) */ + {{ 0xCE,0x8F,0x82,0x98,0x06,0x00,0x07,0x00 }}, /* 07 (1024x) */ + {{ 0xCE,0x9F,0x92,0xA8,0x16,0x00,0x07,0x00 }} /* 08 (1280x) */ +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11400x1050_1_H[]= +{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x47,0x27,0x8B,0x2C,0x1A,0x00,0x05,0x00 }}, /* 00 (320x) */ + {{ 0x47,0x27,0x8B,0x30,0x1E,0x00,0x05,0x00 }}, /* 01 (360x) */ + {{ 0x51,0x31,0x95,0x36,0x04,0x00,0x01,0x00 }}, /* 02 (400x) */ + {{ 0x5F,0x3F,0x83,0x44,0x92,0x00,0x01,0x00 }}, /* 03 (512x) */ + {{ 0x6F,0x4F,0x93,0x54,0x82,0x00,0x05,0x00 }}, /* 04 (640x) */ + {{ 0x6F,0x4F,0x93,0x54,0x82,0x00,0x05,0x00 }}, /* 05 (720x) */ + {{ 0x83,0x63,0x87,0x68,0x16,0x00,0x06,0x00 }}, /* 06 (800x) */ + {{ 0x9F,0x7F,0x83,0x84,0x92,0x00,0x02,0x00 }}, /* 07 (1024x) */ + {{ 0xBF,0x9F,0x83,0xA4,0x12,0x00,0x07,0x00 }}, /* 08 (1280x) */ + {{ 0xCE,0xAE,0x92,0xB3,0x01,0x00,0x03,0x00 }} /* 09 (1400x) */ +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11400x1050_2_H[]= +{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x76,0x3F,0x83,0x45,0x8C,0x00,0x41,0x00 }}, /* 00 (320x) */ + {{ 0x76,0x3F,0x83,0x45,0x8C,0x00,0x41,0x00 }}, /* 01 (360x) */ + {{ 0x76,0x31,0x9A,0x48,0x9F,0x00,0x41,0x00 }}, /* 02 (400x) */ + {{ 0x76,0x3F,0x9A,0x4F,0x96,0x00,0x41,0x00 }}, /* 03 (512x) */ + {{ 0xCE,0x7E,0x82,0x87,0x9E,0x00,0x02,0x00 }}, /* 04 (640x) */ + {{ 0xCE,0x7E,0x82,0x87,0x9E,0x00,0x02,0x00 }}, /* 05 (720x) */ + {{ 0xCE,0x63,0x92,0x96,0x04,0x00,0x07,0x00 }}, /* 06 (800x) */ + {{ 0xCE,0x7F,0x92,0xA4,0x12,0x00,0x07,0x00 }}, /* 07 (1024x) */ + {{ 0xCE,0x9F,0x92,0xB4,0x02,0x00,0x03,0x00 }}, /* 08 (1280x) */ + {{ 0xCE,0xAE,0x92,0xBC,0x0A,0x00,0x03,0x00 }} /* 09 (1400x) */ +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11600x1200_1_H[]= +/* ;302lv channelA [ycchen] 12/05/02 LCDHT=2048 */ +{ /* ; CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x5B,0x27,0x9F,0x32,0x0A,0x00,0x01,0x00 }},/* 00 (320x) */ + {{ 0x5B,0x27,0x9F,0x32,0x0A,0x00,0x01,0x00 }},/* 01 (360x) */ + {{ 0x65,0x31,0x89,0x3C,0x94,0x00,0x01,0x00 }},/* 02 (400x) */ + {{ 0x73,0x3F,0x97,0x4A,0x82,0x00,0x05,0x00 }},/* 03 (512x) */ + {{ 0x83,0x4F,0x87,0x51,0x09,0x00,0x06,0x00 }},/* 04 (640x) */ + {{ 0x83,0x4F,0x87,0x51,0x09,0x00,0x06,0x00 }},/* 05 (720x) */ + {{ 0x97,0x63,0x9B,0x65,0x1D,0x00,0x06,0xF0 }},/* 06 (800x) */ + {{ 0xB3,0x7F,0x97,0x81,0x99,0x00,0x02,0x00 }},/* 07 (1024x) */ + {{ 0xD3,0x9F,0x97,0xA1,0x19,0x00,0x07,0x00 }},/* 08 (1280x) */ + {{ 0xE2,0xAE,0x86,0xB9,0x91,0x00,0x03,0x00 }},/* 09 (1400x) */ + {{ 0xFB,0xC7,0x9F,0xC9,0x81,0x00,0x07,0x00 }} /* 0A (1600x) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_1_V[]= +{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A+CR09(5->7) */ + {{ 0x97,0x1F,0x60,0x87,0x5D,0x83,0x10 }}, /* 00 (x350) */ + {{ 0xB4,0x1F,0x92,0x89,0x8F,0xB5,0x30 }}, /* 01 (x400) */ + {{ 0x04,0x3E,0xE2,0x89,0xDF,0x05,0x00 }}, /* 02 (x480) */ + {{ 0x7C,0xF0,0x5A,0x8F,0x57,0x7D,0xA0 }}, /* 03 (x600) */ + {{ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90 }} /* 04 (x768) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_2_V[]= +{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */ + {{ 0x24,0xBB,0x31,0x87,0x5D,0x25,0x30 }}, /* 00 (x350) */ + {{ 0x24,0xBB,0x4A,0x80,0x8F,0x25,0x30 }}, /* 01 (x400) */ + {{ 0x24,0xBB,0x72,0x88,0xDF,0x25,0x30 }}, /* 02 (x480) */ + {{ 0x24,0xF1,0xAE,0x84,0x57,0x25,0xB0 }}, /* 03 (x600) */ + {{ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90 }} /* 04 (x768) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_1_V[]= +{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */ + {{ 0x86,0x1F,0x5E,0x82,0x5D,0x87,0x00 }}, /* 00 (x350) */ + {{ 0xB8,0x1F,0x90,0x84,0x8F,0xB9,0x30 }}, /* 01 (x400) */ + {{ 0x08,0x3E,0xE0,0x84,0xDF,0x09,0x00 }}, /* 02 (x480) */ + {{ 0x80,0xF0,0x58,0x8C,0x57,0x81,0xA0 }}, /* 03 (x600) */ + {{ 0x28,0xF5,0x00,0x84,0xFF,0x29,0x90 }}, /* 04 (x768) */ + {{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* 05 (x1024) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_2_V[]= +{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */ + {{ 0x28,0xD2,0xAF,0x83,0xAE,0xD8,0xA1 }}, /* 00 (x350) */ + {{ 0x28,0xD2,0xC8,0x8C,0xC7,0xF2,0x81 }}, /* 01 (x400) */ + {{ 0x28,0xD2,0xF0,0x84,0xEF,0x1A,0xB1 }}, /* 02 (x480) */ + {{ 0x28,0xDE,0x2C,0x8F,0x2B,0x56,0x91 }}, /* 03 (x600) */ + {{ 0x28,0xDE,0x80,0x83,0x7F,0xAA,0x91 }}, /* 04 (x768) */ + {{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* 05 (x1024) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11400x1050_1_V[]= +{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */ + {{ 0x6C,0x1F,0x60,0x84,0x5D,0x6D,0x10 }}, /* 00 (x350) */ + {{ 0x9E,0x1F,0x93,0x86,0x8F,0x9F,0x30 }}, /* 01 (x400) */ + {{ 0xEE,0x1F,0xE2,0x86,0xDF,0xEF,0x10 }}, /* 02 (x480) */ + {{ 0x66,0xF0,0x5A,0x8e,0x57,0x67,0xA0 }}, /* 03 (x600) */ + {{ 0x0E,0xF5,0x02,0x86,0xFF,0x0F,0x90 }}, /* 04 (x768) */ + {{ 0x0E,0x5A,0x02,0x86,0xFF,0x0F,0x89 }}, /* 05 (x1024) */ + {{ 0x28,0x10,0x1A,0x80,0x19,0x29,0x0F }} /* 06 (x1050) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11400x1050_2_V[]= +{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */ + {{ 0x28,0x92,0xB6,0x83,0xB5,0xCF,0x81 }}, /* 00 (x350) */ + {{ 0x28,0x92,0xD5,0x82,0xD4,0xEE,0x81 }}, /* 01 (x400) */ + {{ 0x28,0x92,0xFD,0x8A,0xFC,0x16,0xB1 }}, /* 02 (x480) */ + {{ 0x28,0xD4,0x39,0x86,0x57,0x29,0x81 }}, /* 03 (x600) */ + {{ 0x28,0xD4,0x8D,0x9A,0xFF,0x29,0xA1 }}, /* 04 (x768) */ + {{ 0x28,0x5A,0x0D,0x9A,0xFF,0x29,0xA9 }}, /* 05 (x1024) */ + {{ 0x28,0x10,0x1A,0x87,0x19,0x29,0x8F }} /* 06 (x1050) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11600x1200_1_V[]= +{ + /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A+CR09(5->7) */ + {{ 0xd4,0x1F,0x81,0x84,0x5D,0xd5,0x10 }}, /* 00 (x350) */ + {{ 0x06,0x3e,0xb3,0x86,0x8F,0x07,0x20 }}, /* 01 (x400) */ + {{ 0x56,0xba,0x03,0x86,0xDF,0x57,0x00 }}, /* 02 (x480) */ + {{ 0xce,0xF0,0x7b,0x8e,0x57,0xcf,0xa0 }}, /* 03 (x600) */ + {{ 0x76,0xF5,0x23,0x86,0xFF,0x77,0x90 }}, /* 04 (x768) */ + {{ 0x76,0x5A,0x23,0x86,0xFF,0x77,0x89 }}, /* 05 (x1024) */ + {{ 0x90,0x10,0x1A,0x8E,0x19,0x91,0x2F }}, /* 06 (x1050) */ + {{ 0x26,0x11,0xd3,0x86,0xaF,0x27,0x3f }} /* 07 (x1200) */ +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_Hx75[]= +{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x4B,0x27,0x8F,0x32,0x1B,0x00,0x45,0x00 }},/* ; 00 (320x) */ + {{ 0x4B,0x27,0x8F,0x2B,0x03,0x00,0x44,0x00 }},/* ; 01 (360x) */ + {{ 0x55,0x31,0x99,0x46,0x1D,0x00,0x55,0x00 }},/* ; 02 (400x) */ + {{ 0x63,0x3F,0x87,0x4A,0x93,0x00,0x01,0x00 }},/* ; 03 (512x) */ + {{ 0x6F,0x4F,0x93,0x54,0x80,0x00,0x05,0x00 }},/* ; 04 (640x) */ + {{ 0x6F,0x4F,0x93,0x54,0x80,0x00,0x05,0x00 }},/* ; 05 (720x) */ + {{ 0x83,0x63,0x87,0x68,0x14,0x00,0x26,0x00 }},/* ; 06 (800x) */ + {{ 0x9F,0x7F,0x83,0x85,0x91,0x00,0x02,0x00 }} /* ; 07 (1024x) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_1_Vx75[]= +{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A+CR09(5->7) */ + {{ 0x97,0x1F,0x60,0x87,0x5D,0x83,0x10 }},/* ; 00 (x350) */ + {{ 0xB4,0x1F,0x92,0x89,0x8F,0xB5,0x30 }},/* ; 01 (x400) */ + {{ 0xFE,0x1F,0xE0,0x84,0xDF,0xFF,0x10 }},/* ; 02 (x480) */ + {{ 0x76,0xF0,0x58,0x8C,0x57,0x77,0xA0 }},/* ; 03 (x600) */ + {{ 0x1E,0xF5,0x00,0x83,0xFF,0x1F,0x90 }} /* ; 04 (x768) */ +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_2_Hx75[]= +{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }},/* ; 00 (320x) */ + {{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }},/* ; 01 (360x) */ + {{ 0x63,0x31,0x87,0x3D,0x8E,0x00,0x01,0x00 }},/* ; 02 (400x) */ + {{ 0x63,0x3F,0x87,0x45,0x96,0x00,0x01,0x00 }},/* ; 03 (512x) */ + {{ 0xA3,0x4F,0x87,0x6E,0x9F,0x00,0x06,0x00 }},/* ; 04 (640x) */ + {{ 0xA3,0x4F,0x87,0x6E,0x9F,0x00,0x06,0x00 }},/* ; 05 (720x) */ + {{ 0xA3,0x63,0x87,0x78,0x89,0x00,0x02,0x00 }},/* ; 06 (800x) */ + {{ 0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00 }} /* ; 07 (1024x) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_2_Vx75[]= +{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */ + {{ 0x24,0xBB,0x31,0x87,0x5D,0x25,0x30 }},/* ; 00 (x350) */ + {{ 0x24,0xBB,0x4A,0x80,0x8F,0x25,0x30 }},/* ; 01 (x400) */ + {{ 0x24,0xBB,0x72,0x88,0xDF,0x25,0x30 }},/* ; 02 (x480) */ + {{ 0x24,0xF1,0xAE,0x84,0x57,0x25,0xB0 }},/* ; 03 (x600) */ + {{ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90 }} /* ; 04 (x768) */ +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_1_Hx75[]= +{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }},/* ; 00 (320x) */ + {{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }},/* ; 01 (360x) */ + {{ 0x60,0x31,0x84,0x3A,0x88,0x00,0x01,0x00 }},/* ; 02 (400x) */ + {{ 0x6E,0x3F,0x92,0x48,0x96,0x00,0x01,0x00 }},/* ; 03 (512x) */ + {{ 0x7E,0x4F,0x82,0x54,0x06,0x00,0x06,0x00 }},/* ; 04 (640x) */ + {{ 0x7E,0x4F,0x82,0x54,0x06,0x00,0x06,0x00 }},/* ; 05 (720x) */ + {{ 0x92,0x63,0x96,0x68,0x1A,0x00,0x06,0x00 }},/* ; 06 (800x) */ + {{ 0xAE,0x7F,0x92,0x84,0x96,0x00,0x02,0x00 }},/* ; 07 (1024x) */ + {{ 0xCE,0x9F,0x92,0xA5,0x17,0x00,0x07,0x00 }} /* ; 08 (1280x) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_1_Vx75[]= +{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */ + {{ 0x86,0xD1,0xBC,0x80,0xBB,0xE5,0x00 }},/* ; 00 (x350) */ + {{ 0xB8,0x1F,0x90,0x84,0x8F,0xB9,0x30 }},/* ; 01 (x400) */ + {{ 0x08,0x3E,0xE0,0x84,0xDF,0x09,0x00 }},/* ; 02 (x480) */ + {{ 0x80,0xF0,0x58,0x8C,0x57,0x81,0xA0 }},/* ; 03 (x600) */ + {{ 0x28,0xF5,0x00,0x84,0xFF,0x29,0x90 }},/* ; 04 (x768) */ + {{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* ; 05 (x1024) */ +}; + +XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_2_Hx75[]= +{ + /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ + {{ 0x7E,0x3B,0x9A,0x44,0x12,0x00,0x01,0x00 }},/* ; 00 (320x) */ + {{ 0x7E,0x3B,0x9A,0x44,0x12,0x00,0x01,0x00 }},/* ; 01 (360x) */ + {{ 0x7E,0x40,0x84,0x49,0x91,0x00,0x01,0x00 }},/* ; 02 (400x) */ + {{ 0x7E,0x47,0x93,0x50,0x9E,0x00,0x01,0x00 }},/* ; 03 (512x) */ + {{ 0xCE,0x77,0x8A,0x80,0x8E,0x00,0x02,0x00 }},/* ; 04 (640x) */ + {{ 0xCE,0x77,0x8A,0x80,0x8E,0x00,0x02,0x00 }},/* ; 05 (720x) */ + {{ 0xCE,0x81,0x94,0x8A,0x98,0x00,0x02,0x00 }},/* ; 06 (800x) */ + {{ 0xCE,0x8F,0x82,0x98,0x06,0x00,0x07,0x00 }},/* ; 07 (1024x) */ + {{ 0xCE,0x9F,0x92,0xA8,0x16,0x00,0x07,0x00 }} /* ; 08 (1280x) */ +}; + +XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_2_Vx75[]= +{ + /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */ + {{ 0x28,0xD2,0xAF,0x83,0xAE,0xD8,0xA1 }},/* ; 00 (x350) */ + {{ 0x28,0xD2,0xC8,0x8C,0xC7,0xF2,0x81 }},/* ; 01 (x400) */ + {{ 0x28,0xD2,0xF0,0x84,0xEF,0x1A,0xB1 }},/* ; 02 (x480) */ + {{ 0x28,0xDE,0x2C,0x8F,0x2B,0x56,0x91 }},/* ; 03 (x600) */ + {{ 0x28,0xDE,0x80,0x83,0x7F,0xAA,0x91 }},/* ; 04 (x768) */ + {{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* ; 05 (x1024) */ +}; + +XGI_LVDSCRT1DataStruct XGI_CHTVCRT1UNTSC[]= +{ + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,0x00 }}, + {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, + 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,0x00 }}, + {{0x5d,0x4f,0x81,0x53,0x9c,0x56,0xba, + 0x18,0x84,0xdf,0x57,0x00,0x00,0x01,0x00 }}, + {{0x80,0x63,0x84,0x6c,0x17,0xec,0xf0, + 0x90,0x8c,0x57,0xed,0x20,0x00,0x06,0x01 }} +}; + +XGI_LVDSCRT1DataStruct XGI_CHTVCRT1ONTSC[]= +{ + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,0x00 }}, + {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, + 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,0x00 }}, + {{0x5d,0x4f,0x81,0x56,0x9c,0x0b,0x3e, + 0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01,0x00 }}, + {{0x7d,0x63,0x81,0x6a,0x16,0xba,0xf0, + 0x7f,0x86,0x57,0xbb,0x00,0x00,0x06,0x01 }} +}; + +XGI_LVDSCRT1DataStruct XGI_CHTVCRT1UPAL[]= +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05,0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05,0x00 }}, + {{0x64,0x4f,0x88,0x55,0x80,0xec,0xba, + 0x50,0x84,0xdf,0xed,0x00,0x00,0x05,0x00 }}, + {{0x70,0x63,0x94,0x68,0x8d,0x42,0xf1, + 0xc8,0x8c,0x57,0xe9,0x20,0x00,0x05,0x01 }} +}; + +XGI_LVDSCRT1DataStruct XGI_CHTVCRT1OPAL[]= +{ + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05,0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,0x00 }}, + {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, + 0xde,0x81,0x5d,0x70,0x00,0x00,0x05,0x00 }}, + {{0x64,0x4f,0x88,0x55,0x80,0x6f,0xba, + 0x20,0x83,0xdf,0x70,0x00,0x00,0x05,0x00 }}, + {{0x73,0x63,0x97,0x69,0x8e,0xec,0xf0, + 0x90,0x8c,0x57,0xed,0x20,0x00,0x05,0x01 }} +}; + +/*add for new UNIVGABIOS*/ +XGI330_LCDDataTablStruct XGI_LCDDataTable[]= +{ + {Panel1024x768,0x0019,0x0001,0}, /* XGI_ExtLCD1024x768Data */ + {Panel1024x768,0x0019,0x0000,1}, /* XGI_StLCD1024x768Data */ + {Panel1024x768,0x0018,0x0010,2}, /* XGI_CetLCD1024x768Data */ + {Panel1280x1024,0x0019,0x0001,3}, /* XGI_ExtLCD1280x1024Data */ + {Panel1280x1024,0x0019,0x0000,4}, /* XGI_StLCD1280x1024Data */ + {Panel1280x1024,0x0018,0x0010,5}, /* XGI_CetLCD1280x1024Data */ + {Panel1400x1050,0x0019,0x0001,6}, /* XGI_ExtLCD1400x1050Data */ + {Panel1400x1050,0x0019,0x0000,7}, /* XGI_StLCD1400x1050Data */ + {Panel1400x1050,0x0018,0x0010,8}, /* XGI_CetLCD1400x1050Data */ + {Panel1600x1200,0x0019,0x0001,9}, /* XGI_ExtLCD1600x1200Data */ + {Panel1600x1200,0x0019,0x0000,10}, /* XGI_StLCD1600x1200Data */ + {PanelRef60Hz,0x0008,0x0008,11}, /* XGI_NoScalingData */ + {Panel1024x768x75,0x0019,0x0001,12}, /* XGI_ExtLCD1024x768x75Data */ + {Panel1024x768x75,0x0019,0x0000,13}, /* XGI_StLCD1024x768x75Data */ + {Panel1024x768x75,0x0018,0x0010,14}, /* XGI_CetLCD1024x768x75Data */ + {Panel1280x1024x75,0x0019,0x0001,15}, /* XGI_ExtLCD1280x1024x75Data */ + {Panel1280x1024x75,0x0019,0x0000,16}, /* XGI_StLCD1280x1024x75Data */ + {Panel1280x1024x75,0x0018,0x0010,17}, /* XGI_CetLCD1280x1024x75Data */ + {PanelRef75Hz,0x0008,0x0008,18}, /* XGI_NoScalingDatax75 */ + {0xFF,0x0000,0x0000,0} /* End of table */ +}; + +XGI330_LCDDataTablStruct XGI_LCDDesDataTable[]= +{ + {Panel1024x768,0x0019,0x0001,0}, /* XGI_ExtLCDDes1024x768Data */ + {Panel1024x768,0x0019,0x0000,1}, /* XGI_StLCDDes1024x768Data */ + {Panel1024x768,0x0018,0x0010,2}, /* XGI_CetLCDDes1024x768Data */ + {Panel1280x1024,0x0019,0x0001,3}, /* XGI_ExtLCDDes1280x1024Data */ + {Panel1280x1024,0x0019,0x0000,4}, /* XGI_StLCDDes1280x1024Data */ + {Panel1280x1024,0x0018,0x0010,5}, /* XGI_CetLCDDes1280x1024Data */ + {Panel1400x1050,0x0019,0x0001,6}, /* XGI_ExtLCDDes1400x1050Data */ + {Panel1400x1050,0x0019,0x0000,7}, /* XGI_StLCDDes1400x1050Data */ + {Panel1400x1050,0x0418,0x0010,8}, /* XGI_CetLCDDes1400x1050Data */ + {Panel1400x1050,0x0418,0x0410,9}, /* XGI_CetLCDDes1400x1050Data2 */ + {Panel1600x1200,0x0019,0x0001,10}, /* XGI_ExtLCDDes1600x1200Data */ + {Panel1600x1200,0x0019,0x0000,11}, /* XGI_StLCDDes1600x1200Data */ + {PanelRef60Hz,0x0008,0x0008,12}, /* XGI_NoScalingDesData */ + {Panel1024x768x75,0x0019,0x0001,13}, /* XGI_ExtLCDDes1024x768x75Data */ + {Panel1024x768x75,0x0019,0x0000,14}, /* XGI_StLCDDes1024x768x75Data */ + {Panel1024x768x75,0x0018,0x0010,15}, /* XGI_CetLCDDes1024x768x75Data */ + {Panel1280x1024x75,0x0019,0x0001,16}, /* XGI_ExtLCDDes1280x1024x75Data */ + {Panel1280x1024x75,0x0019,0x0000,17}, /* XGI_StLCDDes1280x1024x75Data */ + {Panel1280x1024x75,0x0018,0x0010,18}, /* XGI_CetLCDDes1280x1024x75Data */ + {PanelRef75Hz,0x0008,0x0008,19}, /* XGI_NoScalingDesDatax75 */ + {0xFF,0x0000,0x0000,0} +}; + +XGI330_LCDDataTablStruct XGI_EPLLCDCRT1Ptr_H[]= +{ + {Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDSCRT11024x768_1_H */ + {Panel1024x768,0x0018,0x0010,1}, /* XGI_LVDSCRT11024x768_2_H */ + {Panel1280x1024,0x0018,0x0000,2}, /* XGI_LVDSCRT11280x1024_1_H */ + {Panel1280x1024,0x0018,0x0010,3}, /* XGI_LVDSCRT11280x1024_2_H */ + {Panel1400x1050,0x0018,0x0000,4}, /* XGI_LVDSCRT11400x1050_1_H */ + {Panel1400x1050,0x0018,0x0010,5}, /* XGI_LVDSCRT11400x1050_2_H */ + {Panel1600x1200,0x0018,0x0000,6}, /* XGI_LVDSCRT11600x1200_1_H */ + {Panel1024x768x75,0x0018,0x0000,7}, /* XGI_LVDSCRT11024x768_1_Hx75 */ + {Panel1024x768x75,0x0018,0x0010,8}, /* XGI_LVDSCRT11024x768_2_Hx75 */ + {Panel1280x1024x75,0x0018,0x0000,9}, /* XGI_LVDSCRT11280x1024_1_Hx75 */ + {Panel1280x1024x75,0x0018,0x0010,10}, /* XGI_LVDSCRT11280x1024_2_Hx75 */ + {0xFF,0x0000,0x0000,0} +}; + +XGI330_LCDDataTablStruct XGI_EPLLCDCRT1Ptr_V[]= +{ + {Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDSCRT11024x768_1_V */ + {Panel1024x768,0x0018,0x0010,1}, /* XGI_LVDSCRT11024x768_2_V */ + {Panel1280x1024,0x0018,0x0000,2}, /* XGI_LVDSCRT11280x1024_1_V */ + {Panel1280x1024,0x0018,0x0010,3}, /* XGI_LVDSCRT11280x1024_2_V */ + {Panel1400x1050,0x0018,0x0000,4}, /* XGI_LVDSCRT11400x1050_1_V */ + {Panel1400x1050,0x0018,0x0010,5}, /* XGI_LVDSCRT11400x1050_2_V */ + {Panel1600x1200,0x0018,0x0000,6}, /* XGI_LVDSCRT11600x1200_1_V */ + {Panel1024x768x75,0x0018,0x0000,7}, /* XGI_LVDSCRT11024x768_1_Vx75 */ + {Panel1024x768x75,0x0018,0x0010,8}, /* XGI_LVDSCRT11024x768_2_Vx75 */ + {Panel1280x1024x75,0x0018,0x0000,9}, /* XGI_LVDSCRT11280x1024_1_Vx75 */ + {Panel1280x1024x75,0x0018,0x0010,10}, /* XGI_LVDSCRT11280x1024_2_Vx75 */ + {0xFF,0x0000,0x0000,0} +}; + +XGI330_LCDDataTablStruct XGI_EPLLCDDataPtr[]= +{ + {Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDS1024x768Data_1 */ + {Panel1024x768,0x0018,0x0010,1}, /* XGI_LVDS1024x768Data_2 */ + {Panel1280x1024,0x0018,0x0000,2}, /* XGI_LVDS1280x1024Data_1 */ + {Panel1280x1024,0x0018,0x0010,3}, /* XGI_LVDS1280x1024Data_2 */ + {Panel1400x1050,0x0018,0x0000,4}, /* XGI_LVDS1400x1050Data_1 */ + {Panel1400x1050,0x0018,0x0010,5}, /* XGI_LVDS1400x1050Data_2 */ + {Panel1600x1200,0x0018,0x0000,6}, /* XGI_LVDS1600x1200Data_1 */ + {PanelRef60Hz,0x0008,0x0008,7}, /* XGI_LVDSNoScalingData */ + {Panel1024x768x75,0x0018,0x0000,8}, /* XGI_LVDS1024x768Data_1x75 */ + {Panel1024x768x75,0x0018,0x0010,9}, /* XGI_LVDS1024x768Data_2x75 */ + {Panel1280x1024x75,0x0018,0x0000,10}, /* XGI_LVDS1280x1024Data_1x75 */ + {Panel1280x1024x75,0x0018,0x0010,11}, /* XGI_LVDS1280x1024Data_2x75 */ + {PanelRef75Hz,0x0008,0x0008,12}, /* XGI_LVDSNoScalingDatax75 */ + {0xFF,0x0000,0x0000,0} +}; + +XGI330_LCDDataTablStruct XGI_EPLLCDDesDataPtr[]= +{ + {Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDS1024x768Des_1 */ + {Panel1024x768,0x0618,0x0410,1}, /* XGI_LVDS1024x768Des_3 */ + {Panel1024x768,0x0018,0x0010,2}, /* XGI_LVDS1024x768Des_2 */ + {Panel1280x1024,0x0018,0x0000,3}, /* XGI_LVDS1280x1024Des_1 */ + {Panel1280x1024,0x0018,0x0010,4}, /* XGI_LVDS1280x1024Des_2 */ + {Panel1400x1050,0x0018,0x0000,5}, /* XGI_LVDS1400x1050Des_1 */ + {Panel1400x1050,0x0018,0x0010,6}, /* XGI_LVDS1400x1050Des_2 */ + {Panel1600x1200,0x0018,0x0000,7}, /* XGI_LVDS1600x1200Des_1 */ + {PanelRef60Hz,0x0008,0x0008,8}, /* XGI_LVDSNoScalingDesData */ + {Panel1024x768x75,0x0018,0x0000,9}, /* XGI_LVDS1024x768Des_1x75 */ + {Panel1024x768x75,0x0618,0x0410,10}, /* XGI_LVDS1024x768Des_3x75 */ + {Panel1024x768x75,0x0018,0x0010,11}, /* XGI_LVDS1024x768Des_2x75 */ + {Panel1280x1024x75,0x0018,0x0000,12}, /* XGI_LVDS1280x1024Des_1x75 */ + {Panel1280x1024x75,0x0018,0x0010,13}, /* XGI_LVDS1280x1024Des_2x75 */ + {PanelRef75Hz,0x0008,0x0008,14}, /* XGI_LVDSNoScalingDesDatax75 */ + {0xFF,0x0000,0x0000,0} +}; + +XGI330_LCDDataTablStruct XGI_EPLCHLCDRegPtr[]= +{ + {Panel1024x768,0x0000,0x0000,0}, /* XGI_CH7017LV1024x768 */ + {Panel1400x1050,0x0000,0x0000,1}, /* XGI_CH7017LV1400x1050 */ + {0xFF,0x0000,0x0000,0} +}; + +XGI330_TVDataTablStruct XGI_TVDataTable[]= +{ + {0x09E1,0x0001,0}, /* XGI_ExtPALData */ + {0x09E1,0x0000,1}, /* XGI_ExtNTSCData */ + {0x09E1,0x0801,2}, /* XGI_StPALData */ + {0x09E1,0x0800,3}, /* XGI_StNTSCData */ + {0x49E0,0x0100,4}, /* XGI_ExtHiTVData */ + {0x49E0,0x4100,5}, /* XGI_St2HiTVData */ + {0x49E0,0x4900,13}, /* XGI_St1HiTVData */ + {0x09E0,0x0020,6}, /* XGI_ExtYPbPr525iData */ + {0x09E0,0x0040,7}, /* XGI_ExtYPbPr525pData */ + {0x09E0,0x0080,8}, /* XGI_ExtYPbPr750pData */ + {0x09E0,0x0820,9}, /* XGI_StYPbPr525iData */ + {0x09E0,0x0840,10}, /* XGI_StYPbPr525pData */ + {0x09E0,0x0880,11}, /* XGI_StYPbPr750pData */ + {0xffff,0x0000,12} /* END */ +}; + +USHORT TVLenList[]= +{ + LVDSCRT1Len_H, + LVDSCRT1Len_V, + LVDSDataLen, + 0, + TVDataLen, + 0, + 0, + CHTVRegLen +} ; + +/* Chrontel 7017 TV CRT1 Timing List */ +XGI330_TVDataTablStruct XGI_EPLCHTVCRT1Ptr[]= +{ + {0x0011,0x0000,0}, /* XGI_CHTVCRT1UNTSC */ + {0x0011,0x0010,1}, /* XGI_CHTVCRT1ONTSC */ + {0x0011,0x0001,2}, /* XGI_CHTVCRT1UPAL */ + {0x0011,0x0011,3}, /* XGI_CHTVCRT1OPAL */ + {0xFFFF,0x0000,4} +}; + +/* ;;Chrontel 7017 TV Timing List */ +XGI330_TVDataTablStruct XGI_EPLCHTVDataPtr[]= +{ + {0x0011,0x0000,0}, /* XGI_CHTVUNTSCData */ + {0x0011,0x0010,1}, /* XGI_CHTVONTSCData */ + {0x0011,0x0001,2}, /* XGI_CHTVUPALData */ + {0x0011,0x0011,3}, /* XGI_CHTVOPALData */ + {0xFFFF,0x0000,4} +}; + +/* ;;Chrontel 7017 TV Reg. List */ +XGI330_TVDataTablStruct XGI_EPLCHTVRegPtr[]= +{ + {0x0011,0x0000,0}, /* XGI_CHTVRegUNTSC */ + {0x0011,0x0010,1}, /* XGI_CHTVRegONTSC */ + {0x0011,0x0001,2}, /* XGI_CHTVRegUPAL */ + {0x0011,0x0011,3}, /* XGI_CHTVRegOPAL */ + {0xFFFF,0x0000,4} +}; + +USHORT LCDLenList[]= +{ + LVDSCRT1Len_H, + LVDSCRT1Len_V, + LVDSDataLen, + LCDDesDataLen, + LCDDataLen, + LCDDesDataLen, + 0, + LCDDesDataLen, + LCDDesDataLen, + 0 +} ; + +XGI330_LCDCapStruct XGI660_LCDDLCapList[]= /* 660, Dual link */ +{ +/* LCDCap1024x768 */ + {Panel1024x768, DefaultLCDCap, 0, 0x014, 0x88, 0x06, VCLK65, + 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}, +/* LCDCap1280x1024 */ + {Panel1280x1024, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x053, 0x70, 0x03, VCLK108_2, + 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1400x1050 */ + {Panel1400x1050, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x053, 0x70, 0x03, VCLK108_2, + 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1600x1200 */ + {Panel1600x1200, LCDDualLink+DefaultLCDCap, LCDToFull, 0x053, 0xC0, 0x03, VCLK162, + 0x43, 0x22, 0x70, 0x24, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1024x768x75 */ + {Panel1024x768x75, DefaultLCDCap, 0, 0x014, 0x60, 0, VCLK78_75, + 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}, +/* LCDCap1280x1024x75 */ + {Panel1280x1024x75, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x053, 0x90, 0x03, VCLK135_5, + 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCapDefault */ + {0xFF, DefaultLCDCap, 0, 0x053, 0x88, 0x06, VCLK65, + 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10} +}; + +XGI330_LCDCapStruct XGI_LCDDLCapList[]= /* Dual link only */ +{ +/* LCDCap1024x768 */ + {Panel1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65, + 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}, +/* LCDCap1280x1024 */ + {Panel1280x1024, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x012, 0x70, 0x03, VCLK108_2, + 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1400x1050 */ + {Panel1400x1050, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x012, 0x70, 0x03, VCLK108_2, + 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1600x1200 */ + {Panel1600x1200, LCDDualLink+DefaultLCDCap, LCDToFull, 0x012, 0xC0, 0x03, VCLK162, + 0x43, 0x22, 0x70, 0x24, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1024x768x75 */ + {Panel1024x768x75, DefaultLCDCap, 0, 0x012, 0x60, 0, VCLK78_75, + 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}, +/* LCDCap1280x1024x75 */ + {Panel1280x1024x75, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x012, 0x90, 0x03, VCLK135_5, + 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCapDefault */ + {0xFF, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65, + 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10} +}; + +XGI330_LCDCapStruct XGI660_LCDCapList[]= +{ +/* LCDCap1024x768 */ + {Panel1024x768, DefaultLCDCap, 0, 0x014, 0x88, 0x06, VCLK65, + 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}, +/* LCDCap1280x1024 */ + {Panel1280x1024, DefaultLCDCap, StLCDBToA, 0x053, 0x70, 0x03, VCLK108_2, + 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1400x1050 */ + {Panel1400x1050, DefaultLCDCap, StLCDBToA, 0x053, 0x70, 0x03, VCLK108_2, + 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1600x1200 */ + {Panel1600x1200, DefaultLCDCap, LCDToFull, 0x053, 0xC0, 0x03, VCLK162, + 0x5A, 0x23, 0x5A, 0x23, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1024x768x75 */ + {Panel1024x768x75, DefaultLCDCap, 0, 0x014, 0x60, 0, VCLK78_75, + 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}, +/* LCDCap1280x1024x75 */ + {Panel1280x1024x75,+DefaultLCDCap, StLCDBToA, 0x053, 0x90, 0x03, VCLK135_5, + 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCapDefault */ + {0xFF, DefaultLCDCap, 0, 0x053, 0x88, 0x06, VCLK65, + 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10} +}; + +XGI330_LCDCapStruct XGI_LCDCapList[]= +{ +/* LCDCap1024x768 */ + {Panel1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65, + 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}, +/* LCDCap1280x1024 */ + {Panel1280x1024, DefaultLCDCap, StLCDBToA, 0x012, 0x70, 0x03, VCLK108_2, + 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1400x1050 */ + {Panel1400x1050, DefaultLCDCap, StLCDBToA, 0x012, 0x70, 0x03, VCLK108_2, + 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1600x1200 */ + {Panel1600x1200, DefaultLCDCap, LCDToFull, 0x012, 0xC0, 0x03, VCLK162, + 0x5A, 0x23, 0x5A, 0x23, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCap1024x768x75 */ + {Panel1024x768x75, DefaultLCDCap, 0, 0x012, 0x60, 0, VCLK78_75, + 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}, +/* LCDCap1280x1024x75 */ + {Panel1280x1024x75, DefaultLCDCap, StLCDBToA, 0x012, 0x90, 0x03, VCLK135_5, + 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10}, +/* LCDCapDefault */ + {0xFF, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65, + 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00, + 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10} +}; + +XGI21_LVDSCapStruct XGI21_LCDCapList[]= +{ + {DisableLCD24bpp + LCDPolarity, + 2160,1250,1600,1200, 64, 1, 192, 3, + 0x70,0x24,0x20,0x04,0x0A,0x02,0xC8 + }, + {DisableLCD24bpp + LCDPolarity, + 1688,1066,1280,1024, 48, 1, 112, 3, + 0x70,0x44,0x20,0x04,0x0A,0x02,0xC8 + }, + {DisableLCD24bpp + LCDPolarity + (LCDPolarity << 8), + 1344, 806,1024, 768, 24, 3, 136, 6, + 0x6C,0x65,0x20,0x04,0x0A,0x02,0xC8 + }, + {DisableLCD24bpp + LCDPolarity, + 1056, 628, 800, 600, 40, 1, 128, 4, + 0x42,0xE2,0x20,0x14,0x0A,0x02,0x00 + }, + {DisableLCD24bpp + LCDPolarity, + 928, 525, 800, 480, 40, 13, 48, 3, + 0x52,0xC5,0x20,0x14,0x0A,0x02,0x00 + }, + {DisableLCD24bpp + LCDPolarity + (LCDPolarity << 8), + 800, 525, 640, 480, 16, 10, 96, 2, + 0x1B,0xE1,0x20,0x04,0x0A,0x02,0xC8 + } + +}; + +XGI_Ext2Struct XGI330_RefIndex[]= +{ +{Support32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175, 0x00,0x10,0x59, 320, 200},/* 00 */ +{Support32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175, 0x00,0x10,0x00, 320, 400},/* 01 */ +{Support32Bpp + SupportAllCRT2 + SyncNN, RES320x240, VCLK25_175, 0x04,0x20,0x50, 320, 240},/* 02 */ +{Support32Bpp + SupportAllCRT2 + SyncPP, RES400x300, VCLK40, 0x05,0x32,0x51, 400, 300},/* 03 */ +{Support32Bpp + NoSupportTV + SyncNN + SupportTV1024, RES512x384, VCLK65, 0x06,0x43,0x52, 512, 384},/* 04 */ +{Support32Bpp + SupportAllCRT2 + SyncPN, RES640x400, VCLK25_175, 0x00,0x14,0x2f, 640, 400},/* 05 */ +{Support32Bpp + SupportAllCRT2 + SyncNN, RES640x480x60, VCLK25_175, 0x04,0x24,0x2e, 640, 480},/* 06 640x480x60Hz (LCD 640x480x60z) */ +{Support32Bpp + NoSupportHiVisionTV + SyncNN, RES640x480x72, VCLK31_5, 0x04,0x24,0x2e, 640, 480},/* 07 640x480x72Hz (LCD 640x480x70Hz) */ +{Support32Bpp + NoSupportHiVisionTV + SyncNN, RES640x480x75, VCLK31_5, 0x47,0x24,0x2e, 640, 480},/* 08 640x480x75Hz (LCD 640x480x75Hz) */ +{Support32Bpp + SupportRAMDAC2 + SyncNN, RES640x480x85, VCLK36, 0x8A,0x24,0x2e, 640, 480},/* 09 640x480x85Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x100, VCLK43_163, 0x00,0x24,0x2e, 640, 480},/* 0a 640x480x100Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x120, VCLK52_406, 0x00,0x24,0x2e, 640, 480},/* 0b 640x480x120Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x160, VCLK72_852, 0x00,0x24,0x2e, 640, 480},/* 0c 640x480x160Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncNN, RES640x480x200, VCLK86_6, 0x00,0x24,0x2e, 640, 480},/* 0d 640x480x200Hz */ +{Support32Bpp + NoSupportLCD + SyncPP, RES800x600x56, VCLK36, 0x05,0x36,0x6a, 800, 600},/* 0e 800x600x56Hz */ +{Support32Bpp + NoSupportTV + SyncPP, RES800x600x60, VCLK40, 0x05,0x36,0x6a, 800, 600},/* 0f 800x600x60Hz (LCD 800x600x60Hz) */ +{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES800x600x72, VCLK50, 0x48,0x36,0x6a, 800, 600},/* 10 800x600x72Hz (LCD 800x600x70Hz) */ +{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES800x600x75, VCLK49_5, 0x8B,0x36,0x6a, 800, 600},/* 11 800x600x75Hz (LCD 800x600x75Hz) */ +{Support32Bpp + SupportRAMDAC2 + SyncPP, RES800x600x85, VCLK56_25, 0x00,0x36,0x6a, 800, 600},/* 12 800x600x85Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x100, VCLK68_179, 0x00,0x36,0x6a, 800, 600},/* 13 800x600x100Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x120, VCLK83_95, 0x00,0x36,0x6a, 800, 600},/* 14 800x600x120Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x160, VCLK116_406,0x00,0x36,0x6a, 800, 600},/* 15 800x600x160Hz */ +{Support32Bpp + InterlaceMode + SyncPP, RES1024x768x43, VCLK44_9, 0x00,0x47,0x37,1024, 768},/* 16 1024x768x43Hz */ +{Support32Bpp + NoSupportTV + SyncNN + SupportTV1024, RES1024x768x60, VCLK65, 0x06,0x47,0x37,1024, 768},/* 17 1024x768x60Hz (LCD 1024x768x60Hz) */ +{Support32Bpp + NoSupportHiVisionTV + SyncNN, RES1024x768x70, VCLK75, 0x49,0x47,0x37,1024, 768},/* 18 1024x768x70Hz (LCD 1024x768x70Hz) */ +{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES1024x768x75, VCLK78_75, 0x00,0x47,0x37,1024, 768},/* 19 1024x768x75Hz (LCD 1024x768x75Hz) */ +{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1024x768x85, VCLK94_5, 0x8C,0x47,0x37,1024, 768},/* 1a 1024x768x85Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x100, VCLK113_309,0x00,0x47,0x37,1024, 768},/* 1b 1024x768x100Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x120, VCLK139_054,0x00,0x47,0x37,1024, 768},/* 1c 1024x768x120Hz */ +{Support32Bpp + SupportLCD + SyncPP, RES1280x960x60, VCLK108_2, 0x08,0x58,0x7b,1280, 960},/* 1d 1280x960x60Hz */ +{Support32Bpp + InterlaceMode + SyncPP, RES1280x1024x43, VCLK78_75, 0x00,0x58,0x3a,1280,1024},/* 1e 1280x1024x43Hz */ +{Support32Bpp + NoSupportTV + SyncPP, RES1280x1024x60, VCLK108_2, 0x07,0x58,0x3a,1280,1024},/* 1f 1280x1024x60Hz (LCD 1280x1024x60Hz) */ +{Support32Bpp + NoSupportTV + SyncPP, RES1280x1024x75, VCLK135_5, 0x00,0x58,0x3a,1280,1024},/* 20 1280x1024x75Hz (LCD 1280x1024x75Hz) */ +{Support32Bpp + SyncPP, RES1280x1024x85, VCLK157_5, 0x00,0x58,0x3a,1280,1024},/* 21 1280x1024x85Hz */ +{Support32Bpp + SupportLCD + SyncPP + SupportCRT2in301C, RES1600x1200x60, VCLK162, 0x09,0x7A,0x3c,1600,1200},/* 22 1600x1200x60Hz */ +{Support32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x65, VCLK175, 0x00,0x69,0x3c,1600,1200},/* 23 1600x1200x65Hz */ +{Support32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x70, VCLK189, 0x00,0x69,0x3c,1600,1200},/* 24 1600x1200x70Hz */ +{Support32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x75, VCLK202_5, 0x00,0x69,0x3c,1600,1200},/* 25 1600x1200x75Hz */ +{Support32Bpp + SyncPP, RES1600x1200x85, VCLK229_5, 0x00,0x69,0x3c,1600,1200},/* 26 1600x1200x85Hz */ +{Support32Bpp + SyncPP, RES1600x1200x100,VCLK269_655,0x00,0x69,0x3c,1600,1200},/* 27 1600x1200x100Hz */ +{Support32Bpp + SyncPP, RES1600x1200x120,VCLK323_586,0x00,0x69,0x3c,1600,1200},/* 28 1600x1200x120Hz */ +{Support32Bpp + SupportLCD + SyncNP, RES1920x1440x60, VCLK234, 0x00,0x00,0x68,1920,1440},/* 29 1920x1440x60Hz */ +{Support32Bpp + SyncPN, RES1920x1440x65, VCLK254_817,0x00,0x00,0x68,1920,1440},/* 2a 1920x1440x65Hz */ +{Support32Bpp + SyncPN, RES1920x1440x70, VCLK277_015,0x00,0x00,0x68,1920,1440},/* 2b 1920x1440x70Hz */ +{Support32Bpp + SyncPN, RES1920x1440x75, VCLK291_132,0x00,0x00,0x68,1920,1440},/* 2c 1920x1440x75Hz */ +{Support32Bpp + SyncPN, RES1920x1440x85, VCLK330_615,0x00,0x00,0x68,1920,1440},/* 2d 1920x1440x85Hz */ +{Support16Bpp + SyncPN, RES1920x1440x100,VCLK388_631,0x00,0x00,0x68,1920,1440},/* 2e 1920x1440x100Hz */ +{Support32Bpp + SupportLCD + SyncPN, RES2048x1536x60, VCLK266_952,0x00,0x00,0x6c,2048,1536},/* 2f 2048x1536x60Hz */ +{Support32Bpp + SyncPN, RES2048x1536x65, VCLK291_766,0x00,0x00,0x6c,2048,1536},/* 30 2048x1536x65Hz */ +{Support32Bpp + SyncPN, RES2048x1536x70, VCLK315_195,0x00,0x00,0x6c,2048,1536},/* 31 2048x1536x70Hz */ +{Support32Bpp + SyncPN, RES2048x1536x75, VCLK340_477,0x00,0x00,0x6c,2048,1536},/* 32 2048x1536x75Hz */ +{Support16Bpp + SyncPN, RES2048x1536x85, VCLK375_847,0x00,0x00,0x6c,2048,1536},/* 33 2048x1536x85Hz */ +{Support32Bpp + SupportHiVisionTV + SupportRAMDAC2 + SyncPP + SupportYPbPr, RES800x480x60, VCLK39_77, 0x08,0x00,0x70, 800, 480},/* 34 800x480x60Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPP, RES800x480x75, VCLK49_5, 0x08,0x00,0x70, 800, 480},/* 35 800x480x75Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPP, RES800x480x85, VCLK56_25, 0x08,0x00,0x70, 800, 480},/* 36 800x480x85Hz */ +{Support32Bpp + SupportHiVisionTV + SupportRAMDAC2 + SyncPP + SupportYPbPr, RES1024x576x60, VCLK65, 0x09,0x00,0x71,1024, 576},/* 37 1024x576x60Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1024x576x75, VCLK78_75, 0x09,0x00,0x71,1024, 576},/* 38 1024x576x75Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1024x576x85, VCLK94_5, 0x09,0x00,0x71,1024, 576},/* 39 1024x576x85Hz */ +{Support32Bpp + SupportHiVisionTV + SupportRAMDAC2 + SyncPP + SupportYPbPr, RES1280x720x60, VCLK108_2, 0x0A,0x00,0x75,1280, 720},/* 3a 1280x720x60Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1280x720x75, VCLK135_5, 0x0A,0x00,0x75,1280, 720},/* 3b 1280x720x75Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1280x720x85, VCLK157_5, 0x0A,0x00,0x75,1280, 720},/* 3c 1280x720x85Hz */ +{Support32Bpp + SupportTV + SyncNN, RES720x480x60, VCLK28_322, 0x06,0x00,0x31, 720, 480},/* 3d 720x480x60Hz */ +{Support32Bpp + SupportTV + SyncPP, RES720x576x56, VCLK36, 0x06,0x00,0x32, 720, 576},/* 3e 720x576x56Hz */ +{Support32Bpp + InterlaceMode + NoSupportLCD + SyncPP, RES856x480x79I, VCLK35_2, 0x00,0x00,0x00, 856, 480},/* 3f 856x480x79I */ +{Support32Bpp + NoSupportLCD + SyncNN, RES856x480x60, VCLK35_2, 0x00,0x00,0x00, 856, 480},/* 40 856x480x60Hz */ +{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES1280x768x60, VCLK79_411, 0x08,0x48,0x23,1280, 768},/* 41 1280x768x60Hz */ +{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES1400x1050x60, VCLK122_61, 0x08,0x69,0x26,1400,1050},/* 42 1400x1050x60Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1152x864x60, VCLK80_350, 0x37,0x00,0x20,1152, 864},/* 43 1152x864x60Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1152x864x75, VCLK107_385,0x37,0x00,0x20,1152, 864},/* 44 1152x864x75Hz */ +{Support32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x75, VCLK125_999,0x3A,0x88,0x7b,1280, 960},/* 45 1280x960x75Hz */ +{Support32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x85, VCLK148_5, 0x0A,0x88,0x7b,1280, 960},/* 46 1280x960x85Hz */ +{Support32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x120, VCLK217_325,0x3A,0x88,0x7b,1280, 960},/* 47 1280x960x120Hz */ +{Support32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x160, VCLK139_054,0x30,0x47,0x37,1024, 768},/* 48 1024x768x160Hz */ +}; + + + +XGI330_VCLKDataStruct XGI330_VCLKData[]= +{ + { 0x1b,0xe1, 25}, /* 0x0 */ + { 0x4e,0xe4, 28}, /* 0x1 */ + { 0x57,0xe4, 31}, /* 0x2 */ + { 0xc3,0xc8, 36}, /* 0x3 */ + { 0x42,0xe2, 40}, /* 0x4 */ + { 0xfe,0xcd, 43}, /* 0x5 */ + { 0x5d,0xc4, 44}, /* 0x6 */ + { 0x52,0xe2, 49}, /* 0x7 */ + { 0x53,0xe2, 50}, /* 0x8 */ + { 0x74,0x67, 52}, /* 0x9 */ + { 0x6d,0x66, 56}, /* 0xa */ + { 0x6c,0xc3, 65}, /* 0xb */ + { 0x46,0x44, 67}, /* 0xc */ + { 0xb1,0x46, 68}, /* 0xd */ + { 0xd3,0x4a, 72}, /* 0xe */ + { 0x29,0x61, 75}, /* 0xf */ + { 0x6e,0x46, 76}, /* 0x10 */ + { 0x2b,0x61, 78}, /* 0x11 */ + { 0x31,0x42, 79}, /* 0x12 */ + { 0xab,0x44, 83}, /* 0x13 */ + { 0x46,0x25, 84}, /* 0x14 */ + { 0x78,0x29, 86}, /* 0x15 */ + { 0x62,0x44, 94}, /* 0x16 */ + { 0x2b,0x41,104}, /* 0x17 */ + { 0x3a,0x23,105}, /* 0x18 */ + { 0x70,0x44,108}, /* 0x19 */ + { 0x3c,0x23,109}, /* 0x1a */ + { 0x5e,0x43,113}, /* 0x1b */ + { 0xbc,0x44,116}, /* 0x1c */ + { 0xe0,0x46,132}, /* 0x1d */ + { 0x54,0x42,135}, /* 0x1e */ + { 0xea,0x2a,139}, /* 0x1f */ + { 0x41,0x22,157}, /* 0x20 */ + { 0x70,0x24,162}, /* 0x21 */ + { 0x30,0x21,175}, /* 0x22 */ + { 0x4e,0x22,189}, /* 0x23 */ + { 0xde,0x26,194}, /* 0x24 */ + { 0x62,0x06,202}, /* 0x25 */ + { 0x3f,0x03,229}, /* 0x26 */ + { 0xb8,0x06,234}, /* 0x27 */ + { 0x34,0x02,253}, /* 0x28 */ + { 0x58,0x04,255}, /* 0x29 */ + { 0x24,0x01,265}, /* 0x2a */ + { 0x9b,0x02,267}, /* 0x2b */ + { 0x70,0x05,270}, /* 0x2c */ + { 0x25,0x01,272}, /* 0x2d */ + { 0x9c,0x02,277}, /* 0x2e */ + { 0x27,0x01,286}, /* 0x2f */ + { 0x3c,0x02,291}, /* 0x30 */ + { 0xef,0x0a,292}, /* 0x31 */ + { 0xf6,0x0a,310}, /* 0x32 */ + { 0x95,0x01,315}, /* 0x33 */ + { 0xf0,0x09,324}, /* 0x34 */ + { 0xfe,0x0a,331}, /* 0x35 */ + { 0xf3,0x09,332}, /* 0x36 */ + { 0xea,0x08,340}, /* 0x37 */ + { 0xe8,0x07,376}, /* 0x38 */ + { 0xde,0x06,389}, /* 0x39 */ + { 0x52,0x2a, 54}, /* 0x3a */ + { 0x52,0x6a, 27}, /* 0x3b */ + { 0x62,0x24, 70}, /* 0x3c */ + { 0x62,0x64, 70}, /* 0x3d */ + { 0xa8,0x4c, 30}, /* 0x3e */ + { 0x20,0x26, 33}, /* 0x3f */ + { 0x31,0xc2, 39}, /* 0x40 */ + { 0x60,0x36, 30}, /* 0x41 */ + { 0x40,0x4A, 28}, /* 0x42 */ + { 0x9F,0x46, 44}, /* 0x43 */ + { 0x97,0x2C, 26}, /* 0x44 */ + { 0x44,0xE4, 25}, /* 0x45 */ + { 0x7E,0x32, 47}, /* 0x46 */ + { 0x08,0x24, 31}, /* 0x47 */ + { 0x97,0x2c, 26}, /* 0x48 */ + { 0xCE,0x3c, 39}, /* 0x49 */ + { 0x52,0x4A, 36}, /* 0x4a */ + { 0x2C,0x61, 95}, /* 0x4b */ + { 0x78,0x27,108}, /* 0x4c */ + { 0x66,0x43,123}, /* 0x4d */ + { 0x2c,0x61, 80}, /* 0x4e */ + { 0x3b,0x61,108} /* 0x4f */ +}; + +XGI_VBVCLKDataStruct XGI330_VBVCLKData[]= +{ + { 0x1b,0xe1, 25}, /* 0x0 */ + { 0x4e,0xe4, 28}, /* 0x1 */ + { 0x57,0xe4, 31}, /* 0x2 */ + { 0xc3,0xc8, 36}, /* 0x3 */ + { 0x42,0x47, 40}, /* 0x4 */ + { 0xfe,0xcd, 43}, /* 0x5 */ + { 0x5d,0xc4, 44}, /* 0x6 */ + { 0x52,0x47, 49}, /* 0x7 */ + { 0x53,0x47, 50}, /* 0x8 */ + { 0x74,0x67, 52}, /* 0x9 */ + { 0x6d,0x66, 56}, /* 0xa */ + { 0x5a,0x64, 65}, /* 0xb */ + { 0x46,0x44, 67}, /* 0xc */ + { 0xb1,0x46, 68}, /* 0xd */ + { 0xd3,0x4a, 72}, /* 0xe */ + { 0x29,0x61, 75}, /* 0xf */ + { 0x6d,0x46, 75}, /* 0x10 */ + { 0x41,0x43, 78}, /* 0x11 */ + { 0x31,0x42, 79}, /* 0x12 */ + { 0xab,0x44, 83}, /* 0x13 */ + { 0x46,0x25, 84}, /* 0x14 */ + { 0x78,0x29, 86}, /* 0x15 */ + { 0x62,0x44, 94}, /* 0x16 */ + { 0x2b,0x22,104}, /* 0x17 */ + { 0x49,0x24,105}, /* 0x18 */ + { 0xf8,0x2f,108}, /* 0x19 */ + { 0x3c,0x23,109}, /* 0x1a */ + { 0x5e,0x43,113}, /* 0x1b */ + { 0xbc,0x44,116}, /* 0x1c */ + { 0xe0,0x46,132}, /* 0x1d */ + { 0xd4,0x28,135}, /* 0x1e */ + { 0xea,0x2a,139}, /* 0x1f */ + { 0x41,0x22,157}, /* 0x20 */ + { 0x70,0x24,162}, /* 0x21 */ + { 0x30,0x21,175}, /* 0x22 */ + { 0x4e,0x22,189}, /* 0x23 */ + { 0xde,0x26,194}, /* 0x24 */ + { 0x70,0x07,202}, /* 0x25 */ + { 0x3f,0x03,229}, /* 0x26 */ + { 0xb8,0x06,234}, /* 0x27 */ + { 0x34,0x02,253}, /* 0x28 */ + { 0x58,0x04,255}, /* 0x29 */ + { 0x24,0x01,265}, /* 0x2a */ + { 0x9b,0x02,267}, /* 0x2b */ + { 0x70,0x05,270}, /* 0x2c */ + { 0x25,0x01,272}, /* 0x2d */ + { 0x9c,0x02,277}, /* 0x2e */ + { 0x27,0x01,286}, /* 0x2f */ + { 0x3c,0x02,291}, /* 0x30 */ + { 0xef,0x0a,292}, /* 0x31 */ + { 0xf6,0x0a,310}, /* 0x32 */ + { 0x95,0x01,315}, /* 0x33 */ + { 0xf0,0x09,324}, /* 0x34 */ + { 0xfe,0x0a,331}, /* 0x35 */ + { 0xf3,0x09,332}, /* 0x36 */ + { 0xea,0x08,340}, /* 0x37 */ + { 0xe8,0x07,376}, /* 0x38 */ + { 0xde,0x06,389}, /* 0x39 */ + { 0x52,0x2a, 54}, /* 0x3a */ + { 0x52,0x6a, 27}, /* 0x3b */ + { 0x62,0x24, 70}, /* 0x3c */ + { 0x62,0x64, 70}, /* 0x3d */ + { 0xa8,0x4c, 30}, /* 0x3e */ + { 0x20,0x26, 33}, /* 0x3f */ + { 0x31,0xc2, 39}, /* 0x40 */ + { 0x2e,0x48, 25}, /* 0x41 */ + { 0x24,0x46, 25}, /* 0x42 */ + { 0x26,0x64, 28}, /* 0x43 */ + { 0x37,0x64, 40}, /* 0x44 */ + { 0xa1,0x42,108}, /* 0x45 */ + { 0x37,0x61,100}, /* 0x46 */ + { 0x78,0x27,108}, /* 0x47 */ + { 0x5e,0x64,68}, /* 0x48 chiawen for fuj1280x768*/ + { 0x70,0x44,108}, /* 0x49 chiawen for 1400x1050*/ +}; + +UCHAR XGI330_ScreenOffset[]={ 0x14,0x19,0x20,0x28,0x32,0x40,0x50,0x64,0x78,0x80,0x2d,0x35,0x57,0x48 }; + +XGI_StResInfoStruct XGI330_StResInfo[]= +{ + { 640,400}, + { 640,350}, + { 720,400}, + { 720,350}, + { 640,480} +}; + +XGI_ModeResInfoStruct XGI330_ModeResInfo[]= +{ + { 320, 200, 8, 8}, + { 320, 240, 8, 8}, + { 320, 400, 8, 8}, + { 400, 300, 8, 8}, + { 512, 384, 8, 8}, + { 640, 400, 8,16}, + { 640, 480, 8,16}, + { 800, 600, 8,16}, + { 1024, 768, 8,16}, + { 1280,1024, 8,16}, + { 1600,1200, 8,16}, + { 1920,1440, 8,16}, + { 2048,1536, 8,16}, + { 720, 480, 8,16}, + { 720, 576, 8,16}, + { 1280, 960, 8,16}, + { 800, 480, 8,16}, + { 1024, 576, 8,16}, + { 1280, 720, 8,16}, + { 856, 480, 8,16}, + { 1280, 768, 8,16}, + { 1400,1050, 8,16}, + { 1152, 864, 8,16} +}; + +UCHAR XGI330_OutputSelect =0x40; +UCHAR XGI330_SoftSetting = 0x30; +UCHAR XGI330_SR07=0x18; +UCHAR XGI330New_SR15[8][8]={ +{0x0,0x4,0x60,0x60}, +{0xf,0xf,0xf,0xf}, +{0xba,0xba,0xba,0xba}, +{0xa9,0xa9,0xac,0xac}, +{0xa0,0xa0,0xa0,0xa8}, +{0x0,0x0,0x2,0x2}, +{0x30,0x30,0x40,0x40}, +{0x0,0xa5,0xfb,0xf6} +}; + +UCHAR XGI330New_CR40[5][8]={ +{0x77,0x77,0x44,0x44}, +{0x77,0x77,0x44,0x44}, +{0x0,0x0,0x0,0x0}, +{0x5b,0x5b,0xab,0xab}, +{0x0,0x0,0xf0,0xf8} +}; + +UCHAR XGI330_CR49[]={0xaa,0x88}; +UCHAR XGI330_SR1F=0x0; +UCHAR XGI330_SR21=0xa3; +UCHAR XGI330_650_SR21=0xa7; +UCHAR XGI330_SR22=0xfb; +UCHAR XGI330_SR23=0xf6; +UCHAR XGI330_SR24=0xd; + +UCHAR XGI660_SR21=0xa3;/* 2003.0312 */ +UCHAR XGI660_SR22=0xf3;/* 2003.0312 */ + +UCHAR XGI330_LVDS_SR32=0x00; /* ynlai for 650 LVDS */ +UCHAR XGI330_LVDS_SR33=0x00; /* chiawen for 650 LVDS */ +UCHAR XGI330_650_SR31=0x40; +UCHAR XGI330_650_SR33=0x04; +UCHAR XGI330_CRT2Data_1_2 = 0x0; +UCHAR XGI330_CRT2Data_4_D = 0x0; +UCHAR XGI330_CRT2Data_4_E = 0x0; +UCHAR XGI330_CRT2Data_4_10 = 0x80; +USHORT XGI330_RGBSenseData = 0xd1; +USHORT XGI330_VideoSenseData = 0xb9; +USHORT XGI330_YCSenseData = 0xb3; +USHORT XGI330_RGBSenseData2 = 0x0190; /*301b*/ +USHORT XGI330_VideoSenseData2 = 0x0110; +USHORT XGI330_YCSenseData2 = 0x016B; +UCHAR XGI330_NTSCPhase[] = {0x21,0xed,0x8a,0x8}; +UCHAR XGI330_PALPhase[] = {0x2a,0x5,0xd3,0x0}; +UCHAR XGI330_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6};/*301b*/ +UCHAR XGI330_PALPhase2[] = {0x2a,0x09,0x86,0xe9}; +UCHAR XGI330_PALMPhase[] = {0x21,0xE4,0x2E,0x9B}; /*palmn*/ +UCHAR XGI330_PALNPhase[] = {0x21,0xF4,0x3E,0xBA}; +UCHAR XG40_I2CDefinition = 0x00 ; +UCHAR XG20_CR97 = 0x10 ; + +UCHAR XG21_DVOSetting = 0x00 ; +UCHAR XG21_CR2E = 0x00 ; +UCHAR XG21_CR2F = 0x00 ; +UCHAR XG21_CR46 = 0x00 ; +UCHAR XG21_CR47 = 0x00 ; + +UCHAR XG27_CR97 = 0xC1 ; +UCHAR XG27_SR36 = 0x30 ; +UCHAR XG27_CR8F = 0x0C ; +UCHAR XG27_CRD0[] = {0,0,0,0,0,0,0,0x82,0x00,0x66,0x01,0x00} ; +UCHAR XG27_CRDE[] = {0,0} ; +UCHAR XG27_SR40 = 0x04 ; +UCHAR XG27_SR41 = 0x00 ; + +UCHAR XGI330_CHTVVCLKUNTSC[]={0x00 }; + +UCHAR XGI330_CHTVVCLKONTSC[]={0x00 }; + +UCHAR XGI330_CHTVVCLKUPAL[]={0x00 }; + +UCHAR XGI330_CHTVVCLKOPAL[]={0x00 }; + +UCHAR XGI7007_CHTVVCLKUNTSC[]={CH7007TVVCLK30_2, + CH7007TVVCLK30_2, + CH7007TVVCLK30_2, + CH7007TVVCLK30_2, + CH7007TVVCLK28_1, + CH7007TVVCLK47_8 + }; + +UCHAR XGI7007_CHTVVCLKONTSC[]={CH7007TVVCLK26_4, + CH7007TVVCLK26_4, + CH7007TVVCLK26_4, + CH7007TVVCLK26_4, + CH7007TVVCLK24_6, + CH7007TVVCLK43_6 + }; + +UCHAR XGI7007_CHTVVCLKUPAL[]={CH7007TVVCLK31_5, + CH7007TVVCLK31_5, + CH7007TVVCLK31_5, + CH7007TVVCLK31_5, + CH7007TVVCLK26_2, + CH7007TVVCLK39 + }; + +UCHAR XGI7007_CHTVVCLKOPAL[]={CH7007TVVCLK31_5, + CH7007TVVCLK31_5, + CH7007TVVCLK31_5, + CH7007TVVCLK31_5, + CH7007TVVCLK26_2, + CH7007TVVCLK36 + }; + +XGI330_VCLKDataStruct XGI_CH7007VCLKData[]= +{ + { 0x60,0x36,30}, /* 0 30.2 MHZ */ + { 0x40,0x4A,28}, /* 1 28.19 MHZ */ + { 0x9F,0x46,44}, /* 2 43.6 MHZ */ + { 0x97,0x2C,26}, /* 3 26.4 MHZ */ + { 0x44,0xE4,25}, /* 4 24.6 MHZ */ + { 0x7E,0x32,47}, /* 5 47.832 MHZ */ + { 0x8A,0x24,31}, /* 6 31.5 MHZ */ + { 0x97,0x2C,26}, /* 7 26.2 MHZ */ + { 0xCE,0x3C,39}, /* 8 39 MHZ */ + { 0x52,0x4A,36}, /* 9 36 MHZ */ + { 0xFF,0x00,0 } /* End mark */ +}; + +XGI330_VCLKDataStruct XGI_VCLKData[]= +{ + /* SR2B,SR2C,SR2D */ + { 0x1B,0xE1,25 },/* 00 (25.175MHz) */ + + { 0x4E,0xE4,28 },/* 01 (28.322MHz) */ + + { 0x57,0xE4,31 },/* 02 (31.500MHz) */ + + { 0xC3,0xC8,36 },/* 03 (36.000MHz) */ + + { 0x42,0xE2,40 },/* 04 (40.000MHz) */ + + { 0xFE,0xCD,43 },/* 05 (43.163MHz) */ + + { 0x5D,0xC4,44 },/* 06 (44.900MHz) */ + + { 0x52,0xE2,49 },/* 07 (49.500MHz) */ + + { 0x53,0xE2,50 },/* 08 (50.000MHz) */ + + { 0x74,0x67,52 },/* 09 (52.406MHz) */ + + { 0x6D,0x66,56 },/* 0A (56.250MHz) */ + + { 0x6C,0xC3,65 },/* 0B (65.000MHz) */ + + { 0x46,0x44,67 },/* 0C (67.765MHz) */ + + { 0xB1,0x46,68 },/* 0D (68.179MHz) */ + + { 0xD3,0x4A,72 },/* 0E (72.852MHz) */ + + { 0x29,0x61,75 },/* 0F (75.000MHz) */ + + { 0x6E,0x46,76 },/* 10 (75.800MHz) */ + + { 0x2B,0x61,78 },/* 11 (78.750MHz) */ + + { 0x31,0x42,79 },/* 12 (79.411MHz) */ + + { 0xAB,0x44,83 },/* 13 (83.950MHz) */ + + { 0x46,0x25,84 },/* 14 (84.800MHz) */ + + { 0x78,0x29,86 },/* 15 (86.600MHz) */ + + { 0x62,0x44,94 },/* 16 (94.500MHz) */ + + { 0x2B,0x41,104 },/* 17 (104.998MHz) */ + + { 0x3A,0x23,105 },/* 18 (105.882MHz) */ + + { 0x70,0x44,108 },/* 19 (107.862MHz) */ + + { 0x3C,0x23,109 },/* 1A (109.175MHz) */ + + { 0x5E,0x43,113 },/* 1B (113.309MHz) */ + + { 0xBC,0x44,116 },/* 1C (116.406MHz) */ + + { 0xE0,0x46,132 },/* 1D (132.258MHz) */ + + { 0x54,0x42,135 },/* 1E (135.500MHz) */ + + { 0x9C,0x22,139 },/* 1F (139.275MHz) */ + + { 0x41,0x22,157 },/* 20 (157.500MHz) */ + + { 0x70,0x24,162 },/* 21 (161.793MHz) */ + + { 0x30,0x21,175 },/* 22 (175.000MHz) */ + + { 0x4E,0x22,189 },/* 23 (188.520MHz) */ + + { 0xDE,0x26,194 },/* 24 (194.400MHz) */ + + { 0x62,0x06,202 },/* 25 (202.500MHz) */ + + { 0x3F,0x03,229 },/* 26 (229.500MHz) */ + + { 0xB8,0x06,234 },/* 27 (233.178MHz) */ + + { 0x34,0x02,253 },/* 28 (252.699MHz) */ + + { 0x58,0x04,255 },/* 29 (254.817MHz) */ + + { 0x24,0x01,265 },/* 2A (265.728MHz) */ + + { 0x9B,0x02,267 },/* 2B (266.952MHz) */ + + { 0x70,0x05,270 },/* 2C (269.65567MHz) */ + + { 0x25,0x01,272 },/* 2D (272.04199MHz) */ + + { 0x9C,0x02,277 },/* 2E (277.015MHz) */ + + { 0x27,0x01,286 },/* 2F (286.359985MHz) */ + + { 0xB3,0x04,291 },/* 30 (291.13266MHz) */ + + { 0xBC,0x05,292 },/* 31 (291.766MHz) */ + + { 0xF6,0x0A,310 },/* 32 (309.789459MHz) */ + + { 0x95,0x01,315 },/* 33 (315.195MHz) */ + + { 0xF0,0x09,324 },/* 34 (323.586792MHz) */ + + { 0xFE,0x0A,331 },/* 35 (330.615631MHz) */ + + { 0xF3,0x09,332 },/* 36 (332.177612MHz) */ + + { 0x5E,0x03,340 },/* 37 (340.477MHz) */ + + { 0xE8,0x07,376 },/* 38 (375.847504MHz) */ + + { 0xDE, 0x06,389 },/* 39 (388.631439MHz) */ + + { 0x52,0x2A,54 },/* 3A (54.000MHz) */ + + { 0x52,0x6A,27 },/* 3B (27.000MHz) */ + + { 0x62,0x24,70 },/* 3C (70.874991MHz) */ + + { 0x62,0x64,70 },/* 3D (70.1048912MHz) */ + + { 0xA8,0x4C,30 },/* 3E (30.1048912MHz) */ + + { 0x20,0x26,33 },/* 3F (33.7499957MHz) */ + + { 0x31,0xc2,39 },/* 40 (39.77MHz) */ + + { 0x11,0x21,30 },/* 41 (30MHz) }// NTSC 1024X768 */ + + { 0x2E,0x48,25 },/* 42 (25.175MHz) }// ScaleLCD */ + + { 0x24,0x46,25 },/* 43 (25.175MHz) */ + + { 0x26,0x64,28 },/* 44 (28.322MHz) */ + + { 0x37,0x64,40 },/* 45 (40.000MHz) */ + + { 0xA1,0x42,108 },/* 46 (95.000MHz) }// QVGA */ + + { 0x37,0x61,100 },/* 47 (100.00MHz) */ + + { 0x78,0x27,108 },/* 48 (108.200MHz) */ + + { 0xBF,0xC8,35 },/* 49 (35.2MHz) */ + + { 0x66,0x43,123 },/* 4A (122.61Mhz) */ + + { 0x2C,0x61,80 },/* 4B (80.350Mhz) */ + + { 0x3B,0x61,108 },/* 4C (107.385Mhz) */ + + +/* { 0x60,0x36,30 },// 4D (30.200MHz) }// No use + + { 0x60,0x36,30 },// 4E (30.200MHz) }// No use + + { 0x60,0x36,30 },// 4F (30.200MHz) }// No use + + { 0x60,0x36,30 },// 50 (30.200MHz) }// CHTV + + { 0x40,0x4A,28 },// 51 (28.190MHz) + + { 0x9F,0x46,44 },// 52 (43.600MHz) + + { 0x97,0x2C,26 },// 53 (26.400MHz) + + { 0x44,0xE4,25 },// 54 (24.600MHz) + + { 0x7E,0x32,47 },// 55 (47.832MHz) + + { 0x8A,0x24,31 },// 56 (31.500MHz) + + { 0x97,0x2C,26 },// 57 (26.200MHz) + + { 0xCE,0x3C,39 },// 58 (39.000MHz) + + { 0x52,0x4A,36 },// 59 (36.000MHz) + +*/ + { 0x69,0x61,191 }, /* 4D (190.96MHz ) */ + { 0x4F,0x22,192 }, /* 4E (192.069MHz) */ + { 0x28,0x26,322 }, /* 4F (322.273MHz) */ + { 0x5C,0x6B,27 }, /* 50 (27.74HMz) */ + { 0x57,0x24,126 }, /* 51 (125.999MHz) */ + { 0x5C,0x42,148 }, /* 52 (148.5MHz) */ + { 0x42,0x61,120 }, /* 53 (120.839MHz) */ + { 0x62,0x61,178 }, /* 54 (178.992MHz) */ + { 0x59,0x22,217 }, /* 55 (217.325MHz) */ + { 0x29,0x01,300 }, /* 56 (299.505Mhz) */ + { 0x52,0x63,74 }, /* 57 (74.25MHz) */ + + + { 0xFF,0x00,0 }/* End mark */ + } ; + +XGI330_VCLKDataStruct XGI_VBVCLKData[]= +{ + { 0x1B,0xE1,25 },/* 00 (25.175MHz) */ + + { 0x4E,0xE4,28 },/* 01 (28.322MHz) */ + + { 0x57,0xE4,31 },/* 02 (31.500MHz) */ + + { 0xC3,0xC8,36 },/* 03 (36.000MHz) */ + + { 0x42,0x47,40 },/* 04 (40.000MHz) */ + + { 0xFE,0xCD,43 },/* 05 (43.163MHz) */ + + { 0x5D,0xC4,44 },/* 06 (44.900MHz) */ + + { 0x52,0x47,49 },/* 07 (49.500MHz) */ + + { 0x53,0x47,50 },/* 08 (50.000MHz) */ + + { 0x74,0x67,52 },/* 09 (52.406MHz) */ + + { 0x6D,0x66,56 },/* 0A (56.250MHz) */ + + { 0x35,0x62,65 },/* 0B (65.000MHz) */ + + { 0x46,0x44,67 },/* 0C (67.765MHz) */ + + { 0xB1,0x46,68 },/* 0D (68.179MHz) */ + + { 0xD3,0x4A,72 },/* 0E (72.852MHz) */ + + { 0x29,0x61,75 },/* 0F (75.000MHz) */ + + { 0x6D,0x46,75 },/* 10 (75.800MHz) */ + + { 0x41,0x43,78 },/* 11 (78.750MHz) */ + + { 0x31,0x42,79 },/* 12 (79.411MHz) */ + + { 0xAB,0x44,83 },/* 13 (83.950MHz) */ + + { 0x46,0x25,84 },/* 14 (84.800MHz) */ + + { 0x78,0x29,86 },/* 15 (86.600MHz) */ + + { 0x62,0x44,94 },/* 16 (94.500MHz) */ + + { 0x2B,0x22,104 },/* 17 (104.998MHz) */ + + { 0x49,0x24,105 },/* 18 (105.882MHz) */ + + { 0xF8,0x2F,108 },/* 19 (108.279MHz) */ + + { 0x3C,0x23,109 },/* 1A (109.175MHz) */ + + { 0x5E,0x43,113 },/* 1B (113.309MHz) */ + + { 0xBC,0x44,116 },/* 1C (116.406MHz) */ + + { 0xE0,0x46,132 },/* 1D (132.258MHz) */ + + { 0xD4,0x28,135 },/* 1E (135.220MHz) */ + + { 0xEA,0x2A,139 },/* 1F (139.275MHz) */ + + { 0x41,0x22,157 },/* 20 (157.500MHz) */ + + { 0x70,0x24,162 },/* 21 (161.793MHz) */ + + { 0x30,0x21,175 },/* 22 (175.000MHz) */ + + { 0x4E,0x22,189 },/* 23 (188.520MHz) */ + + { 0xDE,0x26,194 },/* 24 (194.400MHz) */ + + { 0x70,0x07,202 },/* 25 (202.500MHz) */ + + { 0x3F,0x03,229 },/* 26 (229.500MHz) */ + + { 0xB8,0x06,234 },/* 27 (233.178MHz) */ + + { 0x34,0x02,253 },/* 28 (252.699997 MHz) */ + + { 0x58,0x04,255 },/* 29 (254.817MHz) */ + + { 0x24,0x01,265 },/* 2A (265.728MHz) */ + + { 0x9B,0x02,267 },/* 2B (266.952MHz) */ + + { 0x70,0x05,270 },/* 2C (269.65567 MHz) */ + + { 0x25,0x01,272 },/* 2D (272.041992 MHz) */ + + { 0x9C,0x02,277 },/* 2E (277.015MHz) */ + + { 0x27,0x01,286 },/* 2F (286.359985 MHz) */ + + { 0x3C,0x02,291 },/* 30 (291.132660 MHz) */ + + { 0xEF,0x0A,292 },/* 31 (291.766MHz) */ + + { 0xF6,0x0A,310 },/* 32 (309.789459 MHz) */ + + { 0x95,0x01,315 },/* 33 (315.195MHz) */ + + { 0xF0,0x09,324 },/* 34 (323.586792 MHz) */ + + { 0xFE,0x0A,331 },/* 35 (330.615631 MHz) */ + + { 0xF3,0x09,332 },/* 36 (332.177612 MHz) */ + + { 0xEA,0x08,340 },/* 37 (340.477MHz) */ + + { 0xE8,0x07,376 },/* 38 (375.847504 MHz) */ + + { 0xDE,0x06,389 },/* 39 (388.631439 MHz) */ + + { 0x52,0x2A,54 },/* 3A (54.000MHz) */ + + { 0x52,0x6A,27 },/* 3B (27.000MHz) */ + + + { 0x62,0x24,70 },/* 3C (70.874991MHz) */ + + + { 0x62,0x64,70 },/* 3D (70.1048912MHz) */ + + { 0xA8,0x4C,30 },/* 3E (30.1048912MHz) */ + + { 0x20,0x26,33 },/* 3F (33.7499957MHz) */ + + { 0x31,0xc2,39 },/* 40 (39.77MHz) */ + + { 0x11,0x21,30 },/* 41 (30MHz) }// NTSC 1024X768 */ + + { 0x2E,0x48,25 },/* 42 (25.175MHz) }// ScaleLCD */ + + { 0x24,0x46,25 },/* 43 (25.175MHz) */ + + { 0x26,0x64,28 },/* 44 (28.322MHz) */ + + { 0x37,0x64,40 },/* 45 (40.000MHz) */ + + { 0xA1,0x42,108 },/* 46 (95.000MHz) }// QVGA */ + + { 0x37,0x61,100 },/* 47 (100.00MHz) */ + + { 0x78,0x27,108 },/* 48 (108.200MHz) */ + + { 0xBF,0xC8,35 },/* 49 (35.2MHz) */ + + { 0x66,0x43,123 },/* 4A (122.61Mhz) */ + + { 0x2C,0x61,80 },/* 4B (80.350Mhz) */ + + { 0x3B,0x61,108 },/* 4C (107.385Mhz) */ + +/* + { 0x60,0x36,30 },// 4D (30.200MHz) }// No use + + { 0x60,0x36,30 },// 4E (30.200MHz) }// No use + + { 0x60,0x36,30 },// 4F (30.200MHz) }// No use + + { 0x60,0x36,30 },// 50 (30.200MHz) }// CHTV + + { 0x40,0x4A,28 },// 51 (28.190MHz) + + { 0x9F,0x46,44 },// 52 (43.600MHz) + + { 0x97,0x2C,26 },// 53 (26.400MHz) + + { 0x44,0xE4,25 },// 54 (24.600MHz) + + { 0x7E,0x32,47 },// 55 (47.832MHz) + + { 0x8A,0x24,31 },// 56 (31.500MHz) + + { 0x97,0x2C,26 },// 57 (26.200MHz) + + { 0xCE,0x3C,39 },// 58 (39.000MHz) + + { 0x52,0x4A,36 },// 59 (36.000MHz) +*/ + { 0x69,0x61,191 }, /* 4D (190.96MHz ) */ + { 0x4F,0x22,192 }, /* 4E (192.069MHz) */ + { 0x28,0x26,322 }, /* 4F (322.273MHz) */ + { 0x5C,0x6B,27 }, /* 50 (27.74HMz) */ + { 0x57,0x24,126 }, /* 51 (125.999MHz) */ + { 0x5C,0x42,148 }, /* 52 (148.5MHz) */ + { 0x42,0x61,120 }, /* 53 (120.839MHz) */ + { 0x62,0x61,178 }, /* 54 (178.992MHz) */ + { 0x59,0x22,217 }, /* 55 (217.325MHz) */ + { 0x29,0x01,300 }, /* 56 (299.505Mhz) */ + { 0x52,0x63,74 }, /* 57 (74.25MHz) */ + + + { 0xFF,0x00,0 } /* End mark */ +}; + +UCHAR XGI660_TVDelayList[]= +{ + 0x44, /* ; 0 ExtNTSCDelay */ + 0x44, /* ; 1 StNTSCDelay */ + 0x44, /* ; 2 ExtPALDelay */ + 0x44, /* ; 3 StPALDelay */ + 0x44, /* ; 4 ExtHiTVDelay(1080i) */ + 0x44, /* ; 5 StHiTVDelay(1080i) */ + 0x44, /* ; 6 ExtYPbPrDelay(525i) */ + 0x44, /* ; 7 StYPbPrDealy(525i) */ + 0x44, /* ; 8 ExtYPbPrDelay(525p) */ + 0x44, /* ; 9 StYPbPrDealy(525p) */ + 0x44, /* ; A ExtYPbPrDelay(750p) */ + 0x44 /* ; B StYPbPrDealy(750p) */ +}; + +UCHAR XGI660_TVDelayList2[]= +{ + 0x44, /* ; 0 ExtNTSCDelay */ + 0x44, /* ; 1 StNTSCDelay */ + 0x44, /* ; 2 ExtPALDelay */ + 0x44, /* ; 3 StPALDelay */ + 0x44, /* ; 4 ExtHiTVDelay */ + 0x44, /* ; 5 StHiTVDelay */ + 0x44, /* ; 6 ExtYPbPrDelay(525i) */ + 0x44, /* ; 7 StYPbPrDealy(525i) */ + 0x44, /* ; 8 ExtYPbPrDelay(525p) */ + 0x44, /* ; 9 StYPbPrDealy(525p) */ + 0x44, /* ; A ExtYPbPrDelay(750p) */ + 0x44 /* ; B StYPbPrDealy(750p) */ +}; + +UCHAR XGI301TVDelayList[]= +{ + 0x22, /* ; 0 ExtNTSCDelay */ + 0x22, /* ; 1 StNTSCDelay */ + 0x22, /* ; 2 ExtPALDelay */ + 0x22, /* ; 3 StPALDelay */ + 0x88, /* ; 4 ExtHiTVDelay(1080i) */ + 0xBB, /* ; 5 StHiTVDelay(1080i) */ + 0x22, /* ; 6 ExtYPbPrDelay(525i) */ + 0x22, /* ; 7 StYPbPrDealy(525i) */ + 0x22, /* ; 8 ExtYPbPrDelay(525p) */ + 0x22, /* ; 9 StYPbPrDealy(525p) */ + 0x22, /* ; A ExtYPbPrDelay(750p) */ + 0x22 /* B StYPbPrDealy(750p) */ +}; + +UCHAR XGI301TVDelayList2[]= +{ + 0x22, /* ; 0 ExtNTSCDelay */ + 0x22, /* ; 1 StNTSCDelay */ + 0x22, /* ; 2 ExtPALDelay */ + 0x22, /* ; 3 StPALDelay */ + 0x22, /* ; 4 ExtHiTVDelay */ + 0x22, /* ; 5 StHiTVDelay */ + 0x22, /* ; 6 ExtYPbPrDelay(525i) */ + 0x22, /* ; 7 StYPbPrDealy(525i) */ + 0x22, /* ; 8 ExtYPbPrDelay(525p) */ + 0x22, /* ; 9 StYPbPrDealy(525p) */ + 0x22, /* ; A ExtYPbPrDelay(750p) */ + 0x22 /* ; B StYPbPrDealy(750p) */ +}; + + +UCHAR TVAntiFlickList[]= +{/* NTSCAntiFlicker */ + 0x04, /* ; 0 Adaptive */ + 0x00, /* ; 1 new anti-flicker ? */ +/* PALAntiFlicker */ + 0x04, /* ; 0 Adaptive */ + 0x08, /* ; 1 new anti-flicker ? */ +/* HiTVAntiFlicker */ + 0x04, /* ; 0 ? */ + 0x00 /* ; 1 new anti-flicker ? */ +}; + + +UCHAR TVEdgeList[]= +{ + 0x00, /* ; 0 NTSC No Edge enhance */ + 0x04, /* ; 1 NTSC Adaptive Edge enhance */ + 0x00, /* ; 0 PAL No Edge enhance */ + 0x04, /* ; 1 PAL Adaptive Edge enhance */ + 0x00, /* ; 0 HiTV */ + 0x00 /* ; 1 HiTV */ +}; + +ULONG TVPhaseList[]= +{ 0x08BAED21, /* ; 0 NTSC phase */ + 0x00E3052A, /* ; 1 PAL phase */ + 0x9B2EE421, /* ; 2 PAL-M phase */ + 0xBA3EF421, /* ; 3 PAL-N phase */ + 0xA7A28B1E, /* ; 4 NTSC 1024x768 */ + 0xE00A831E, /* ; 5 PAL-M 1024x768 */ + 0x00000000, /* ; 6 reserved */ + 0x00000000, /* ; 7 reserved */ + 0xD67BF021, /* ; 8 NTSC phase */ + 0xE986092A, /* ; 9 PAL phase */ + 0xA4EFE621, /* ; A PAL-M phase */ + 0x4694F621, /* ; B PAL-N phase */ + 0x8BDE711C, /* ; C NTSC 1024x768 */ + 0xE00A831E /* ; D PAL-M 1024x768 */ +}; + +UCHAR NTSCYFilter1[]= +{ + 0x00,0xF4,0x10,0x38 ,/* 0 : 320x text mode */ + 0x00,0xF4,0x10,0x38 ,/* 1 : 360x text mode */ + 0xEB,0x04,0x25,0x18 ,/* 2 : 640x text mode */ + 0xF1,0x04,0x1F,0x18 ,/* 3 : 720x text mode */ + 0x00,0xF4,0x10,0x38 ,/* 4 : 320x gra. mode */ + 0xEB,0x04,0x25,0x18 ,/* 5 : 640x gra. mode */ + 0xEB,0x15,0x25,0xF6 /* 6 : 800x gra. mode */ +}; + +UCHAR PALYFilter1[]= +{ + 0x00,0xF4,0x10,0x38, /* 0 : 320x text mode */ + 0x00,0xF4,0x10,0x38 ,/* 1 : 360x text mode */ + 0xF1,0xF7,0x1F,0x32 ,/* 2 : 640x text mode */ + 0xF3,0x00,0x1D,0x20 ,/* 3 : 720x text mode */ + 0x00,0xF4,0x10,0x38 ,/* 4 : 320x gra. mode */ + 0xF1,0xF7,0x1F,0x32 ,/* 5 : 640x gra. mode */ + 0xFC,0xFB,0x14,0x2A /* 6 : 800x gra. mode */ +}; + +UCHAR PALMYFilter1[]= +{ + 0x00,0xF4,0x10,0x38, /* 0 : 320x text mode */ + 0x00,0xF4,0x10,0x38, /* 1 : 360x text mode */ + 0xEB,0x04,0x10,0x18, /* 2 : 640x text mode */ + 0xF7,0x06,0x19,0x14, /* 3 : 720x text mode */ + 0x00,0xF4,0x10,0x38, /* 4 : 320x gra. mode */ + 0xEB,0x04,0x25,0x18, /* 5 : 640x gra. mode */ + 0xEB,0x15,0x25,0xF6, /* 6 : 800x gra. mode */ + 0xFF,0xFF,0xFF,0xFF /* End of Table */ +}; + +UCHAR PALNYFilter1[]= +{ + 0x00,0xF4,0x10,0x38, /* 0 : 320x text mode */ + 0x00,0xF4,0x10,0x38, /* 1 : 360x text mode */ + 0xEB,0x04,0x10,0x18, /* 2 : 640x text mode */ + 0xF7,0x06,0x19,0x14, /* 3 : 720x text mode */ + 0x00,0xF4,0x10,0x38, /* 4 : 320x gra. mode */ + 0xEB,0x04,0x25,0x18, /* 5 : 640x gra. mode */ + 0xEB,0x15,0x25,0xF6, /* 6 : 800x gra. mode */ + 0xFF,0xFF,0xFF,0xFF /* End of Table */ +}; + +UCHAR NTSCYFilter2[]= +{ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */ + 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 2 : 640x text mode */ + 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 3 : 720x text mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 4 : 320x gra. mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 5 : 640x gra. mode */ + 0x01,0x01,0xFC,0xF8,0x08,0x26,0x38, /* 6 : 800x gra. mode */ + 0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */ +}; + +UCHAR PALYFilter2[]= +{ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */ + 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 2 : 640x text mode */ + 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 3 : 720x text mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 4 : 320x gra. mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 5 : 640x gra. mode */ + 0x01,0x01,0xFC,0xF8,0x08,0x26,0x38, /* 6 : 800x gra. mode */ + 0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */ +}; + +UCHAR PALMYFilter2[]= +{ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */ + 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 2 : 640x text mode */ + 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 3 : 720x text mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 4 : 320x gra. mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 5 : 640x gra. mode */ + 0x01,0x01,0xFC,0xF8,0x08,0x26,0x38, /* 6 : 800x gra. mode */ + 0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */ +}; + +UCHAR PALNYFilter2[]= +{ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */ + 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 2 : 640x text mode */ + 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 3 : 720x text mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 4 : 320x gra. mode */ + 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 5 : 640x gra. mode */ + 0x01,0x01,0xFC,0xF8,0x08,0x26,0x38, /* 6 : 800x gra. mode */ + 0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */ +}; + +UCHAR XGI_NTSC1024AdjTime[]= +{ + 0xa7,0x07,0xf2,0x6e,0x17,0x8b,0x73,0x53, + 0x13,0x40,0x34,0xF4,0x63,0xBB,0xCC,0x7A, + 0x58,0xe4,0x73,0xd0,0x13 +}; + +XGI301C_Tap4TimingStruct HiTVTap4Timing[]= +{ + {0,{ + 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F, /* ; C0-C7 */ + 0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, /* ; C8-CF */ + 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E, /* ; D0-D7 */ + 0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, /* ; D8-DF */ + 0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C, /* ; E0-E7 */ + 0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C, /* ; EA-EF */ + 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C, /* ; F0-F7 */ + 0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E /* ; F8-FF */ + } + } +}; + +XGI301C_Tap4TimingStruct EnlargeTap4Timing[]= +{ + {0,{ + 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F, /* ; C0-C7 */ + 0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, /* ; C8-CF */ + 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E, /* ; D0-D7 */ + 0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, /* ; D8-DF */ + 0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C, /* ; E0-E7 */ + 0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C, /* ; EA-EF */ + 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C, /* ; F0-F7 */ + 0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E /* ; F8-FF */ + } + } +}; + +XGI301C_Tap4TimingStruct NoScaleTap4Timing[]= +{ + {0,{ + 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F, /* ; C0-C7 */ + 0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, /* ; C8-CF */ + 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E, /* ; D0-D7 */ + 0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, /* ; D8-DF */ + 0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C, /* ; E0-E7 */ + 0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C, /* ; EA-EF */ + 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C, /* ; F0-F7 */ + 0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E /* ; F8-FF */ + } + } +}; + +XGI301C_Tap4TimingStruct PALTap4Timing[]= +{ + {600, { + 0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E, /* ; C0-C7 */ + 0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D, /* ; C8-CF */ + 0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C, /* ; D0-D7 */ + 0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D, /* ; D8-DF */ + 0x7D,0x13,0x13,0x7D,0x7D,0x11,0x14,0x7E, /* ; E0-E7 */ + 0x7D,0x0F,0x16,0x7E,0x7D,0x0E,0x17,0x7E, /* ; EA-EF */ + 0x7D,0x0C,0x18,0x7F,0x7D,0x0A,0x18,0x01, /* ; F0-F7 */ + 0x7D,0x08,0x19,0x02,0x7D,0x06,0x19,0x04 /* ; F8-FF */ + } + }, + {768, { + 0x08,0x12,0x08,0x7E,0x07,0x12,0x09,0x7E, /* ; C0-C7 */ + 0x06,0x12,0x0A,0x7E,0x05,0x11,0x0B,0x7F, /* ; C8-CF */ + 0x04,0x11,0x0C,0x7F,0x03,0x11,0x0C,0x00, /* ; D0-D7 */ + 0x03,0x10,0x0D,0x00,0x02,0x0F,0x0E,0x01, /* ; D8-DF */ + 0x01,0x0F,0x0F,0x01,0x01,0x0E,0x0F,0x02, /* ; E0-E7 */ + 0x00,0x0D,0x10,0x03,0x7F,0x0C,0x11,0x04, /* ; EA-EF */ + 0x7F,0x0C,0x11,0x04,0x7F,0x0B,0x11,0x05, /* ; F0-F7 */ + 0x7E,0x0A,0x12,0x06,0x7E,0x09,0x12,0x07 /* ; F8-FF */ + } + }, + {0xFFFF, + { + 0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E, /* ; C0-C7 */ + 0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D, /* ; C8-CF */ + 0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D, /* ; D0-D7 */ + 0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C, /* ; D8-DF */ + 0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D, /* ; E0-E7 */ + 0x7C,0x10,0x17,0x7D,0x7C,0x0D,0x18,0x7F, /* ; EA-EF */ + 0x7D,0x0B,0x19,0x7F,0x7D,0x09,0x1A,0x00, /* ; F0-F7 */ + 0x7D,0x07,0x1A,0x02,0x7E,0x05,0x1B,0x02 /* ; F8-FF */ + } + } +}; + +XGI301C_Tap4TimingStruct NTSCTap4Timing[]= +{ + {480, { + 0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D, /* ; C0-C7 */ + 0x01,0x1A,0x08,0x7D,0x00,0x19,0x0A,0x7D, /* ; C8-CF */ + 0x7F,0x19,0x0C,0x7C,0x7E,0x18,0x0E,0x7C, /* ; D0-D7 */ + 0x7E,0x17,0x10,0x7B,0x7D,0x15,0x12,0x7C, /* ; D8-DF */ + 0x7D,0x13,0x13,0x7D,0x7C,0x12,0x15,0x7D, /* ; E0-E7 */ + 0x7C,0x10,0x17,0x7D,0x7C,0x0E,0x18,0x7E, /* ; EA-EF */ + 0x7D,0x0C,0x19,0x7E,0x7D,0x0A,0x19,0x00, /* ; F0-F7 */ + 0x7D,0x08,0x1A,0x01,0x7E,0x06,0x1A,0x02 /* ; F8-FF */ + } + }, + {600, { + 0x07,0x14,0x07,0x7E,0x06,0x14,0x09,0x7D, /* ; C0-C7 */ + 0x05,0x14,0x0A,0x7D,0x04,0x13,0x0B,0x7E, /* ; C8-CF */ + 0x03,0x13,0x0C,0x7E,0x02,0x12,0x0D,0x7F, /* ; D0-D7 */ + 0x01,0x12,0x0E,0x7F,0x01,0x11,0x0F,0x7F, /* ; D8-DF */ + 0x01,0x10,0x10,0x00,0x7F,0x0F,0x11,0x01, /* ; E0-E7 */ + 0x7F,0x0E,0x12,0x01,0x7E,0x0D,0x12,0x03, /* ; EA-EF */ + 0x7E,0x0C,0x13,0x03,0x7E,0x0B,0x13,0x04, /* ; F0-F7 */ + 0x7E,0x0A,0x14,0x04,0x7D,0x09,0x14,0x06 /* ; F8-FF */ + } + }, + {0xFFFF, + { + 0x09,0x0F,0x09,0x7F,0x08,0x0F,0x09,0x00, /* ; C0-C7 */ + 0x07,0x0F,0x0A,0x00,0x06,0x0F,0x0A,0x01, /* ; C8-CF */ + 0x06,0x0E,0x0B,0x01,0x05,0x0E,0x0B,0x02, /* ; D0-D7 */ + 0x04,0x0E,0x0C,0x02,0x04,0x0D,0x0C,0x03, /* ; D8-DF */ + 0x03,0x0D,0x0D,0x03,0x02,0x0C,0x0D,0x05, /* ; E0-E7 */ + 0x02,0x0C,0x0E,0x04,0x01,0x0B,0x0E,0x06, /* ; EA-EF */ + 0x01,0x0B,0x0E,0x06,0x00,0x0A,0x0F,0x07, /* ; F0-F7 */ + 0x00,0x0A,0x0F,0x07,0x00,0x09,0x0F,0x08 /* ; F8-FF */ + } + } +}; + +XGI301C_Tap4TimingStruct YPbPr525pTap4Timing[]= +{ + {480, { + 0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D, /* ; C0-C7 */ + 0x01,0x1A,0x08,0x7D,0x00,0x19,0x0A,0x7D, /* ; C8-CF */ + 0x7F,0x19,0x0C,0x7C,0x7E,0x18,0x0E,0x7C, /* ; D0-D7 */ + 0x7E,0x17,0x10,0x7B,0x7D,0x15,0x12,0x7C, /* ; D8-DF */ + 0x7D,0x13,0x13,0x7D,0x7C,0x12,0x15,0x7D, /* ; E0-E7 */ + 0x7C,0x10,0x17,0x7D,0x7C,0x0E,0x18,0x7E, /* ; EA-EF */ + 0x7D,0x0C,0x19,0x7E,0x7D,0x0A,0x19,0x00, /* ; F0-F7 */ + 0x7D,0x08,0x1A,0x01,0x7E,0x06,0x1A,0x02 /* ; F8-FF */ + } + }, + {600, { + 0x07,0x14,0x07,0x7E,0x06,0x14,0x09,0x7D, /* ; C0-C7 */ + 0x05,0x14,0x0A,0x7D,0x04,0x13,0x0B,0x7E, /* ; C8-CF */ + 0x03,0x13,0x0C,0x7E,0x02,0x12,0x0D,0x7F, /* ; D0-D7 */ + 0x01,0x12,0x0E,0x7F,0x01,0x11,0x0F,0x7F, /* ; D8-DF */ + 0x01,0x10,0x10,0x00,0x7F,0x0F,0x11,0x01, /* ; E0-E7 */ + 0x7F,0x0E,0x12,0x01,0x7E,0x0D,0x12,0x03, /* ; EA-EF */ + 0x7E,0x0C,0x13,0x03,0x7E,0x0B,0x13,0x04, /* ; F0-F7 */ + 0x7E,0x0A,0x14,0x04,0x7D,0x09,0x14,0x06 /* ; F8-FF */ + } + }, + {0xFFFF, + { + 0x09,0x0F,0x09,0x7F,0x08,0x0F,0x09,0x00, /* ; C0-C7 */ + 0x07,0x0F,0x0A,0x00,0x06,0x0F,0x0A,0x01, /* ; C8-CF */ + 0x06,0x0E,0x0B,0x01,0x05,0x0E,0x0B,0x02, /* ; D0-D7 */ + 0x04,0x0E,0x0C,0x02,0x04,0x0D,0x0C,0x03, /* ; D8-DF */ + 0x03,0x0D,0x0D,0x03,0x02,0x0C,0x0D,0x05, /* ; E0-E7 */ + 0x02,0x0C,0x0E,0x04,0x01,0x0B,0x0E,0x06, /* ; EA-EF */ + 0x01,0x0B,0x0E,0x06,0x00,0x0A,0x0F,0x07, /* ; F0-F7 */ + 0x00,0x0A,0x0F,0x07,0x00,0x09,0x0F,0x08 /* ; F8-FF */ + } + } +}; + +XGI301C_Tap4TimingStruct YPbPr525iTap4Timing[]= +{ + {480, { + 0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D, /* ; C0-C7 */ + 0x01,0x1A,0x08,0x7D,0x00,0x19,0x0A,0x7D, /* ; C8-CF */ + 0x7F,0x19,0x0C,0x7C,0x7E,0x18,0x0E,0x7C, /* ; D0-D7 */ + 0x7E,0x17,0x10,0x7B,0x7D,0x15,0x12,0x7C, /* ; D8-DF */ + 0x7D,0x13,0x13,0x7D,0x7C,0x12,0x15,0x7D, /* ; E0-E7 */ + 0x7C,0x10,0x17,0x7D,0x7C,0x0E,0x18,0x7E, /* ; EA-EF */ + 0x7D,0x0C,0x19,0x7E,0x7D,0x0A,0x19,0x00, /* ; F0-F7 */ + 0x7D,0x08,0x1A,0x01,0x7E,0x06,0x1A,0x02 /* ; F8-FF */ + } + }, + {600, { + 0x07,0x14,0x07,0x7E,0x06,0x14,0x09,0x7D, /* ; C0-C7 */ + 0x05,0x14,0x0A,0x7D,0x04,0x13,0x0B,0x7E, /* ; C8-CF */ + 0x03,0x13,0x0C,0x7E,0x02,0x12,0x0D,0x7F, /* ; D0-D7 */ + 0x01,0x12,0x0E,0x7F,0x01,0x11,0x0F,0x7F, /* ; D8-DF */ + 0x01,0x10,0x10,0x00,0x7F,0x0F,0x11,0x01, /* ; E0-E7 */ + 0x7F,0x0E,0x12,0x01,0x7E,0x0D,0x12,0x03, /* ; EA-EF */ + 0x7E,0x0C,0x13,0x03,0x7E,0x0B,0x13,0x04, /* ; F0-F7 */ + 0x7E,0x0A,0x14,0x04,0x7D,0x09,0x14,0x06 /* ; F8-FF */ + } + }, + {0xFFFF, + { + 0x09,0x0F,0x09,0x7F,0x08,0x0F,0x09,0x00, /* ; C0-C7 */ + 0x07,0x0F,0x0A,0x00,0x06,0x0F,0x0A,0x01, /* ; C8-CF */ + 0x06,0x0E,0x0B,0x01,0x05,0x0E,0x0B,0x02, /* ; D0-D7 */ + 0x04,0x0E,0x0C,0x02,0x04,0x0D,0x0C,0x03, /* ; D8-DF */ + 0x03,0x0D,0x0D,0x03,0x02,0x0C,0x0D,0x05, /* ; E0-E7 */ + 0x02,0x0C,0x0E,0x04,0x01,0x0B,0x0E,0x06, /* ; EA-EF */ + 0x01,0x0B,0x0E,0x06,0x00,0x0A,0x0F,0x07, /* ; F0-F7 */ + 0x00,0x0A,0x0F,0x07,0x00,0x09,0x0F,0x08 /* ; F8-FF */ + } + } +}; + +XGI301C_Tap4TimingStruct YPbPr750pTap4Timing[]= +{ {0xFFFF, + { + 0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E, /* ; C0-C7 */ + 0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D, /* ; C8-CF */ + 0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C, /* ; D0-D7 */ + 0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D, /* ; D8-DF */ + 0x7D,0x13,0x13,0x7D,0x7D,0x11,0x14,0x7E, /* ; E0-E7 */ + 0x7D,0x0F,0x16,0x7E,0x7D,0x0E,0x17,0x7E, /* ; EA-EF */ + 0x7D,0x0C,0x18,0x7F,0x7D,0x0A,0x18,0x01, /* ; F0-F7 */ + 0x7D,0x08,0x19,0x02,0x7D,0x06,0x19,0x04 /* F8-FF */ + } + } +}; diff --git a/drivers/staging/xgifb/vb_util.c b/drivers/staging/xgifb/vb_util.c new file mode 100644 index 000000000000..87531b49b739 --- /dev/null +++ b/drivers/staging/xgifb/vb_util.c @@ -0,0 +1,263 @@ +#include "osdef.h" +#include "vb_def.h" +#include "vgatypes.h" +#include "vb_struct.h" + +#ifdef LINUX_KERNEL +#include "XGIfb.h" +#include <asm/io.h> +#include <linux/types.h> +#endif + +#ifdef TC +#include <stdio.h> +#include <string.h> +#include <conio.h> +#include <dos.h> +#endif + +#ifdef WIN2000 +#include <dderror.h> +#include <devioctl.h> +#include <miniport.h> +#include <ntddvdeo.h> +#include <video.h> + +#include "xgiv.h" +#include "dd_i2c.h" +#include "tools.h" +#endif + +#ifdef LINUX_XF86 +#include "xf86.h" +#include "xf86PciInfo.h" +#include "xgi.h" +#include "xgi_regs.h" +#endif + + + + +void XGINew_SetReg1( ULONG , USHORT , USHORT ) ; +void XGINew_SetReg2( ULONG , USHORT , USHORT ) ; +void XGINew_SetReg3( ULONG , USHORT ) ; +void XGINew_SetReg4( ULONG , ULONG ) ; +UCHAR XGINew_GetReg1( ULONG , USHORT) ; +UCHAR XGINew_GetReg2( ULONG ) ; +ULONG XGINew_GetReg3( ULONG ) ; +void XGINew_ClearDAC( PUCHAR ) ; +void XGINew_SetRegANDOR(ULONG Port,USHORT Index,USHORT DataAND,USHORT DataOR); +void XGINew_SetRegOR(ULONG Port,USHORT Index,USHORT DataOR); +void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND); + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetReg1 */ +/* Input : */ +/* Output : */ +/* Description : SR CRTC GR */ +/* --------------------------------------------------------------------- */ +void XGINew_SetReg1( ULONG port , USHORT index , USHORT data ) +{ +#ifdef LINUX_XF86 + OutPortByte( ( PUCHAR )(ULONG)port , index ) ; + OutPortByte( ( PUCHAR )(ULONG)port + 1 , data ) ; +#else + OutPortByte( port , index ) ; + OutPortByte( port + 1 , data ) ; +#endif +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetReg2 */ +/* Input : */ +/* Output : */ +/* Description : AR( 3C0 ) */ +/* --------------------------------------------------------------------- */ +/*void XGINew_SetReg2( ULONG port , USHORT index , USHORT data ) +{ + InPortByte( ( PUCHAR )port + 0x3da - 0x3c0 ) ; + OutPortByte( XGINew_P3c0 , index ) ; + OutPortByte( XGINew_P3c0 , data ) ; + OutPortByte( XGINew_P3c0 , 0x20 ) ; +}*/ + + +/* --------------------------------------------------------------------- */ +/* Function : */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetReg3( ULONG port , USHORT data ) +{ + OutPortByte( port , data ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetReg4 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetReg4( ULONG port , ULONG data ) +{ + OutPortLong( port , data ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_GetReg1 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +UCHAR XGINew_GetReg1( ULONG port , USHORT index ) +{ + UCHAR data ; + +#ifdef LINUX_XF86 + OutPortByte( ( PUCHAR )(ULONG)port , index ) ; + data = InPortByte( ( PUCHAR )(ULONG)port + 1 ) ; +#else + OutPortByte( port , index ) ; + data = InPortByte( port + 1 ) ; +#endif + + return( data ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_GetReg2 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +UCHAR XGINew_GetReg2( ULONG port ) +{ + UCHAR data ; + + data = InPortByte( port ) ; + + return( data ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_GetReg3 */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +ULONG XGINew_GetReg3( ULONG port ) +{ + ULONG data ; + + data = InPortLong( port ) ; + + return( data ) ; +} + + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetRegANDOR */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetRegANDOR( ULONG Port , USHORT Index , USHORT DataAND , USHORT DataOR ) +{ + USHORT temp ; + + temp = XGINew_GetReg1( Port , Index ) ; /* XGINew_Part1Port index 02 */ + temp = ( temp & ( DataAND ) ) | DataOR ; + XGINew_SetReg1( Port , Index , temp ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetRegAND */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND) +{ + USHORT temp ; + + temp = XGINew_GetReg1( Port , Index ) ; /* XGINew_Part1Port index 02 */ + temp &= DataAND ; + XGINew_SetReg1( Port , Index , temp ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : XGINew_SetRegOR */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void XGINew_SetRegOR( ULONG Port , USHORT Index , USHORT DataOR ) +{ + USHORT temp ; + + temp = XGINew_GetReg1( Port , Index ) ; /* XGINew_Part1Port index 02 */ + temp |= DataOR ; + XGINew_SetReg1( Port , Index , temp ) ; +} + + +/* --------------------------------------------------------------------- */ +/* Function : NewDelaySecond */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void NewDelaySeconds( int seconds ) +{ +#ifdef WIN2000 + int j ; +#endif + int i ; + + + for( i = 0 ; i < seconds ; i++ ) + { +#ifdef TC + delay( 1000 ) ; +#endif + +#ifdef WIN2000 + + for ( j = 0 ; j < 20000 ; j++ ) + VideoPortStallExecution( 50 ) ; +#endif + +#ifdef WINCE_HEADER +#endif + +#ifdef LINUX_KERNEL +#endif + } +} + + +/* --------------------------------------------------------------------- */ +/* Function : Newdebugcode */ +/* Input : */ +/* Output : */ +/* Description : */ +/* --------------------------------------------------------------------- */ +void Newdebugcode( UCHAR code ) +{ +// OutPortByte ( 0x80 , code ) ; + /* OutPortByte ( 0x300 , code ) ; */ + /* NewDelaySeconds( 0x3 ) ; */ +} + + + diff --git a/drivers/staging/xgifb/vb_util.h b/drivers/staging/xgifb/vb_util.h new file mode 100644 index 000000000000..91779d8cfdc6 --- /dev/null +++ b/drivers/staging/xgifb/vb_util.h @@ -0,0 +1,15 @@ +#ifndef _VBUTIL_ +#define _VBUTIL_ +extern void NewDelaySeconds( int ); +extern void Newdebugcode( UCHAR ); +extern void XGINew_SetReg1(ULONG, USHORT, USHORT); +extern void XGINew_SetReg3(ULONG, USHORT); +extern UCHAR XGINew_GetReg1(ULONG, USHORT); +extern UCHAR XGINew_GetReg2(ULONG); +extern void XGINew_SetReg4(ULONG, ULONG); +extern ULONG XGINew_GetReg3(ULONG); +extern void XGINew_SetRegOR(ULONG Port,USHORT Index,USHORT DataOR); +extern void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND); +extern void XGINew_SetRegANDOR(ULONG Port,USHORT Index,USHORT DataAND,USHORT DataOR); +#endif + diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h new file mode 100644 index 000000000000..295ea860ae47 --- /dev/null +++ b/drivers/staging/xgifb/vgatypes.h @@ -0,0 +1,325 @@ + +#ifndef _VGATYPES_ +#define _VGATYPES_ + +#include "osdef.h" + +#ifdef LINUX_XF86 +#include "xf86Version.h" +#include "xf86Pci.h" +#endif + +#ifdef LINUX_KERNEL /* We don't want the X driver to depend on kernel source */ +#include <linux/ioctl.h> +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CHAR +typedef char CHAR; +#endif + +#ifndef SHORT +typedef short SHORT; +#endif + +#ifndef LONG +typedef long LONG; +#endif + +#ifndef UCHAR +typedef unsigned char UCHAR; +#endif + +#ifndef USHORT +typedef unsigned short USHORT; +#endif + +#ifndef ULONG +typedef unsigned long ULONG; +#endif + +#ifndef PUCHAR +typedef UCHAR *PUCHAR; +#endif + +#ifndef PUSHORT +typedef USHORT *PUSHORT; +#endif + +#ifndef PLONGU +typedef ULONG *PULONG; +#endif + +#ifndef VOID +typedef void VOID; +#endif + +#ifndef PVOID +typedef void *PVOID; +#endif + +#ifndef BOOLEAN +typedef UCHAR BOOLEAN; +#endif +/* +#ifndef bool +typedef UCHAR bool; +#endif +*/ +#ifdef LINUX_KERNEL +typedef unsigned long XGIIOADDRESS; +#endif + +#ifdef LINUX_XF86 +#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0) +typedef unsigned char IOADDRESS; +typedef unsigned char XGIIOADDRESS; +#else +typedef IOADDRESS XGIIOADDRESS; +#endif +#endif + +#ifndef VBIOS_VER_MAX_LENGTH +#define VBIOS_VER_MAX_LENGTH 4 +#endif + +#ifndef WIN2000 + +#ifndef LINUX_KERNEL /* For the linux kernel, this is defined in xgifb.h */ +#ifndef XGI_CHIP_TYPE +typedef enum _XGI_CHIP_TYPE { + XGI_VGALegacy = 0, +#ifdef LINUX_XF86 + XGI_530, + XGI_OLD, +#endif + XGI_300, + XGI_630, + XGI_640, + XGI_315H, + XGI_315, + XGI_315PRO, + XGI_550, + XGI_650, + XGI_650M, + XGI_740, + XGI_330, + XGI_661, + XGI_660, + XGI_760, + XG40 = 32, + XG41, + XG42, + XG45, + XG20 = 48, + XG21, + XG27, + MAX_XGI_CHIP +} XGI_CHIP_TYPE; +#endif +#endif + +#ifndef XGI_VB_CHIP_TYPE +typedef enum _XGI_VB_CHIP_TYPE { + VB_CHIP_Legacy = 0, + VB_CHIP_301, + VB_CHIP_301B, + VB_CHIP_301LV, + VB_CHIP_302, + VB_CHIP_302B, + VB_CHIP_302LV, + VB_CHIP_301C, + VB_CHIP_302ELV, + VB_CHIP_UNKNOWN, /* other video bridge or no video bridge */ + MAX_VB_CHIP +} XGI_VB_CHIP_TYPE; +#endif + +#ifndef XGI_LCD_TYPE +typedef enum _XGI_LCD_TYPE { + LCD_INVALID = 0, + LCD_320x480, /* FSTN, DSTN */ + LCD_640x480, + LCD_640x480_2, /* FSTN, DSTN */ + LCD_640x480_3, /* FSTN, DSTN */ + LCD_800x600, + LCD_848x480, + LCD_1024x600, + LCD_1024x768, + LCD_1152x768, + LCD_1152x864, + LCD_1280x720, + LCD_1280x768, + LCD_1280x800, + LCD_1280x960, + LCD_1280x1024, + LCD_1400x1050, + LCD_1600x1200, + LCD_1680x1050, + LCD_1920x1440, + LCD_2048x1536, + LCD_CUSTOM, + LCD_UNKNOWN +} XGI_LCD_TYPE; +#endif + +#endif /* not WIN2000 */ + +#ifndef PXGI_DSReg +typedef struct _XGI_DSReg +{ + UCHAR jIdx; + UCHAR jVal; +} XGI_DSReg, *PXGI_DSReg; +#endif + +#ifndef XGI_HW_DEVICE_INFO + +typedef struct _XGI_HW_DEVICE_INFO XGI_HW_DEVICE_INFO, *PXGI_HW_DEVICE_INFO; + +typedef BOOLEAN (*PXGI_QUERYSPACE) (PXGI_HW_DEVICE_INFO, ULONG, ULONG, ULONG *); + +struct _XGI_HW_DEVICE_INFO +{ + ULONG ulExternalChip; /* NO VB or other video bridge*/ + /* if ujVBChipID = VB_CHIP_UNKNOWN, */ +#ifdef LINUX_XF86 + PCITAG PciTag; /* PCI Tag */ +#endif + + PUCHAR pjVirtualRomBase; /* ROM image */ + + BOOLEAN UseROM; /* Use the ROM image if provided */ + + PVOID pDevice; + + PUCHAR pjVideoMemoryAddress;/* base virtual memory address */ + /* of Linear VGA memory */ + + ULONG ulVideoMemorySize; /* size, in bytes, of the memory on the board */ + + PUCHAR pjIOAddress; /* base I/O address of VGA ports (0x3B0) */ + + PUCHAR pjCustomizedROMImage; + + PUCHAR pj2ndVideoMemoryAddress; + ULONG ul2ndVideoMemorySize; + + PUCHAR pj2ndIOAddress; +/*#ifndef WIN2000 + XGIIOADDRESS pjIOAddress; // base I/O address of VGA ports (0x3B0) +#endif */ + UCHAR jChipType; /* Used to Identify Graphics Chip */ + /* defined in the data structure type */ + /* "XGI_CHIP_TYPE" */ + + UCHAR jChipRevision; /* Used to Identify Graphics Chip Revision */ + + UCHAR ujVBChipID; /* the ID of video bridge */ + /* defined in the data structure type */ + /* "XGI_VB_CHIP_TYPE" */ + + BOOLEAN bNewScratch; + + ULONG ulCRT2LCDType; /* defined in the data structure type */ + + ULONG usExternalChip; /* NO VB or other video bridge (other than */ + /* video bridge) */ + + BOOLEAN bIntegratedMMEnabled;/* supporting integration MM enable */ + + BOOLEAN bSkipDramSizing; /* True: Skip video memory sizing. */ + + BOOLEAN bSkipSense; + + BOOLEAN bIsPowerSaving; /* True: XGIInit() is invoked by power management, + otherwise by 2nd adapter's initialzation */ + + PXGI_DSReg pSR; /* restore SR registers in initial function. */ + /* end data :(idx, val) = (FF, FF). */ + /* Note : restore SR registers if */ + /* bSkipDramSizing = TRUE */ + + PXGI_DSReg pCR; /* restore CR registers in initial function. */ + /* end data :(idx, val) = (FF, FF) */ + /* Note : restore cR registers if */ + /* bSkipDramSizing = TRUE */ +/* +#endif +*/ + + PXGI_QUERYSPACE pQueryVGAConfigSpace; + + PXGI_QUERYSPACE pQueryNorthBridgeSpace; + + UCHAR szVBIOSVer[VBIOS_VER_MAX_LENGTH]; + +}; +#endif + +/* Addtional IOCTL for communication xgifb <> X driver */ +/* If changing this, xgifb.h must also be changed (for xgifb) */ + +#ifdef LINUX_XF86 /* We don't want the X driver to depend on the kernel source */ + +/* ioctl for identifying and giving some info (esp. memory heap start) */ +#define XGIFB_GET_INFO 0x80046ef8 /* Wow, what a terrible hack... */ + +/* Structure argument for XGIFB_GET_INFO ioctl */ +typedef struct _XGIFB_INFO xgifb_info, *pxgifb_info; + +struct _XGIFB_INFO { + CARD32 xgifb_id; /* for identifying xgifb */ +#ifndef XGIFB_ID +#define XGIFB_ID 0x53495346 /* Identify myself with 'XGIF' */ +#endif + CARD32 chip_id; /* PCI ID of detected chip */ + CARD32 memory; /* video memory in KB which xgifb manages */ + CARD32 heapstart; /* heap start (= xgifb "mem" argument) in KB */ + CARD8 fbvidmode; /* current xgifb mode */ + + CARD8 xgifb_version; + CARD8 xgifb_revision; + CARD8 xgifb_patchlevel; + + CARD8 xgifb_caps; /* xgifb's capabilities */ + + CARD32 xgifb_tqlen; /* turbo queue length (in KB) */ + + CARD32 xgifb_pcibus; /* The card's PCI ID */ + CARD32 xgifb_pcislot; + CARD32 xgifb_pcifunc; + + CARD8 xgifb_lcdpdc; + + CARD8 xgifb_lcda; + + CARD32 xgifb_vbflags; + CARD32 xgifb_currentvbflags; + + CARD32 xgifb_scalelcd; + CARD32 xgifb_specialtiming; + + CARD8 xgifb_haveemi; + CARD8 xgifb_emi30,xgifb_emi31,xgifb_emi32,xgifb_emi33; + CARD8 xgifb_haveemilcd; + + CARD8 xgifb_lcdpdca; + + CARD8 reserved[212]; /* for future use */ +}; +#endif + +#endif + -- GitLab From a4cff8b82a3cd0c95348ad4ae28cee7a918a35cd Mon Sep 17 00:00:00 2001 From: Sreedhara DS <sreedhara.ds@intel.com> Date: Tue, 1 Jun 2010 12:50:06 +0100 Subject: [PATCH 637/842] Staging: mid: Intel MID touch screen driver Touchscreen driver used by intel mid devices. Some clean up by Alan Cox. This driver is basically ready for upstreaming properly but is tied wrongly to the SPI layer and needs firmware/SFI changes to fix that. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/mrst-touchscreen/Kconfig | 7 + drivers/staging/mrst-touchscreen/Makefile | 3 + drivers/staging/mrst-touchscreen/TODO | 2 + .../mrst-touchscreen/intel-mid-touch.c | 864 ++++++++++++++++++ 6 files changed, 879 insertions(+) create mode 100644 drivers/staging/mrst-touchscreen/Kconfig create mode 100644 drivers/staging/mrst-touchscreen/Makefile create mode 100644 drivers/staging/mrst-touchscreen/TODO create mode 100644 drivers/staging/mrst-touchscreen/intel-mid-touch.c diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 2a1a7c296429..883c88f3de7a 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -143,5 +143,7 @@ source "drivers/staging/adis16255/Kconfig" source "drivers/staging/xgifb/Kconfig" +source "drivers/staging/mrst-touchscreen/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 4a02c0df9ced..352ca2a973c2 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -52,3 +52,4 @@ obj-$(CONFIG_CXT1E1) += cxt1e1/ obj-$(CONFIG_TI_ST) += ti-st/ obj-$(CONFIG_ADIS16255) += adis16255/ obj-$(CONFIG_FB_XGI) += xgifb/ +obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/ diff --git a/drivers/staging/mrst-touchscreen/Kconfig b/drivers/staging/mrst-touchscreen/Kconfig new file mode 100644 index 000000000000..c2af49217084 --- /dev/null +++ b/drivers/staging/mrst-touchscreen/Kconfig @@ -0,0 +1,7 @@ +config TOUCHSCREEN_INTEL_MID + tristate "Intel MID platform resistive touchscreen" + depends on INTEL_SCU_IPC + default y + help + Say Y here if you have a Intel MID based touchscreen + If unsure, say N. diff --git a/drivers/staging/mrst-touchscreen/Makefile b/drivers/staging/mrst-touchscreen/Makefile new file mode 100644 index 000000000000..2d638b0d70bf --- /dev/null +++ b/drivers/staging/mrst-touchscreen/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) := intel_mid_touch.o + + diff --git a/drivers/staging/mrst-touchscreen/TODO b/drivers/staging/mrst-touchscreen/TODO new file mode 100644 index 000000000000..7157028d634a --- /dev/null +++ b/drivers/staging/mrst-touchscreen/TODO @@ -0,0 +1,2 @@ +- Move the driver to not think it is SPI (requires fixing some of the SFI + and firmware side) diff --git a/drivers/staging/mrst-touchscreen/intel-mid-touch.c b/drivers/staging/mrst-touchscreen/intel-mid-touch.c new file mode 100644 index 000000000000..1db00975a594 --- /dev/null +++ b/drivers/staging/mrst-touchscreen/intel-mid-touch.c @@ -0,0 +1,864 @@ +/* + * intel_mid_touch.c - Intel MID Resistive Touch Screen Driver + * + * Copyright (C) 2008 Intel Corp + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; ifnot, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com) + * Ramesh Agarwal (ramesh.agarwal@intel.com) + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * TODO: + * kill off mrstouch_debug eventually + * review conversion of r/m/w sequences + * Replace interrupt mutex abuse + * Kill of mrstouchdevp pointer + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/param.h> +#include <linux/spi/spi.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <asm/intel_scu_ipc.h> + + +#if defined(MRSTOUCH_DEBUG) +#define mrstouch_debug(fmt, args...)\ + do { \ + printk(KERN_DEBUG "\n[MRSTOUCH(%d)] - ", __LINE__); \ + printk(KERN_DEBUG fmt, ##args); \ + } while (0); +#else +#define mrstouch_debug(fmt, args...) +#endif + +/* PMIC Interrupt registers */ +#define PMIC_REG_ID1 0x00 /*PMIC ID1 register */ + +/* PMIC Interrupt registers */ +#define PMIC_REG_INT 0x04 /*PMIC interrupt register */ +#define PMIC_REG_MINT 0x05 /*PMIC interrupt mask register */ + +/* ADC Interrupt registers */ +#define PMIC_REG_ADCINT 0x5F /*ADC interrupt register */ +#define PMIC_REG_MADCINT 0x60 /*ADC interrupt mask register */ + +/* ADC Control registers */ +#define PMIC_REG_ADCCNTL1 0x61 /*ADC control register */ + +/* ADC Channel Selection registers */ +#define PMICADDR0 0xA4 +#define END_OF_CHANNEL 0x1F + +/* ADC Result register */ +#define PMIC_REG_ADCSNS0H 0x64 + +/* ADC channels for touch screen */ +#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */ +#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */ +#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */ +#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */ + +/* Touch screen coordinate constants */ +#define TOUCH_PRESSURE 50 +#define TOUCH_PRESSURE_FS 100 + +#define XMOVE_LIMIT 5 +#define YMOVE_LIMIT 5 +#define XYMOVE_CNT 3 + +#define MAX_10BIT ((1<<10)-1) + +/* Touch screen channel BIAS constants */ +#define XBIAS 0x20 +#define YBIAS 0x40 +#define ZBIAS 0x80 + +/* Touch screen coordinates */ +#define MIN_X 10 +#define MAX_X 1024 +#define MIN_Y 10 +#define MAX_Y 1024 +#define WAIT_ADC_COMPLETION 10 + +/* PMIC ADC round robin delays */ +#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */ +#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */ + +/* PMIC Vendor Identifiers */ +#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */ +#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */ +#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */ +#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */ + +/* Touch screen device structure */ +struct mrstouch_dev { + struct spi_device *spi; /* SPI device associated with touch screen */ + struct input_dev *input; /* input device for touchscreen*/ + char phys[32]; /* Device name */ + struct task_struct *pendet_thrd; /* PENDET interrupt handler */ + struct mutex lock; /* Sync between interrupt and PENDET handler */ + bool busy; /* Busy flag */ + u16 asr; /* Address selection register */ + int irq; /* Touch screen IRQ # */ + uint vendor; /* PMIC vendor */ + uint rev; /* PMIC revision */ + bool suspended; /* Device suspended status */ + bool disabled; /* Device disabled status */ + u16 x; /* X coordinate */ + u16 y; /* Y coordinate */ + bool pendown; /* PEN position */ +} ; + + +/* Global Pointer to Touch screen device */ +static struct mrstouch_dev *mrstouchdevp; + +/* Utility to read PMIC ID */ +static int mrstouch_pmic_id(uint *vendor, uint *rev) +{ + int err; + u8 r; + + err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r); + if (err) + return err; + + *vendor = r & 0x7; + *rev = (r >> 3) & 0x7; + + return 0; +} + +/* + * Parse ADC channels to find end of the channel configured by other ADC user + * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels + */ +static int mrstouch_chan_parse(struct mrstouch_dev *tsdev) +{ + int err, i, j, found; + u32 r32; + + found = -1; + + for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) { + if (found >= 0) + break; + + err = intel_scu_ipc_ioread32(PMICADDR0, &r32); + if (err) + return err; + + for (j = 0; j < 32; j+= 8) { + if (((r32 >> j) & 0xFF) == END_OF_CHANNEL) { + found = i; + break; + } + } + } + if (found < 0) + return 0; + + if (tsdev->vendor == PMIC_VENDOR_FS) { + if (found && found > (MRSTOUCH_MAX_CHANNELS - 18)) + return -ENOSPC; + } else { + if (found && found > (MRSTOUCH_MAX_CHANNELS - 4)) + return -ENOSPC; + } + return found; +} + +/* Utility to enable/disable pendet. + * pendet set to true enables PENDET interrupt + * pendet set to false disables PENDET interrupt + * Also clears RND mask bit +*/ +static int pendet_enable(struct mrstouch_dev *tsdev, bool pendet) +{ + u16 reg; + u8 r; + u8 pendet_enabled = 0; + int retry = 0; + int err; + + err = intel_scu_ipc_ioread16(PMIC_REG_MADCINT, ®); + if (err) + return err; + + if (pendet) { + reg &= ~0x0005; + reg |= 0x2000; /* Enable pendet */ + } else + reg &= 0xDFFF; /* Disable pendet */ + + /* Set MADCINT and update ADCCNTL1 (next reg byte) */ + err = intel_scu_ipc_iowrite16(PMIC_REG_MADCINT, reg); + if (!pendet || err) + return err; + + /* + * Sometimes even after the register write succeeds + * the PMIC register value is not updated. Retry few iterations + * to enable pendet. + */ + + err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r); + pendet_enabled = (r >> 5) & 0x01; + + retry = 0; + while (!err && !pendet_enabled) { + retry++; + msleep(10); + err = intel_scu_ipc_iowrite8(PMIC_REG_ADCCNTL1, reg >> 8); + if (err) + break; + err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r); + if (err == 0) + pendet_enabled = (r >> 5) & 0x01; + if (retry >= 10) { + dev_err(&tsdev->spi->dev, "Touch screen disabled.\n"); + return -EIO; + } + } + return 0; +} + +/* To read PMIC ADC touch screen result + * Reads ADC storage registers for higher 7 and lower 3 bits + * converts the two readings to single value and turns off gain bit + */ +static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm) +{ + int err; + u16 result; + u32 res; + + result = PMIC_REG_ADCSNS0H + offset; + + if (chan == MRST_TS_CHAN12) + result += 4; + + err = intel_scu_ipc_ioread32(result, &res); + if (err) + return err; + + /* Mash the bits up */ + + *vp = (res & 0xFF) << 3; /* Highest 7 bits */ + *vp |= (res >> 8) & 0x07; /* Lower 3 bits */ + *vp &= 0x3FF; + + res >>= 16; + + *vm = (res & 0xFF) << 3; /* Highest 7 bits */ + *vm |= (res >> 8) & 0x07; /* Lower 3 bits */ + *vm &= 0x3FF; + + return 0; +} + +/* To configure touch screen channels + * Writes touch screen channels to ADC address selection registers + */ +static int mrstouch_ts_chan_set(uint offset) +{ + int count; + u16 chan; + u16 reg[5]; + u8 data[5]; + + chan = PMICADDR0 + offset; + for (count = 0; count <= 3; count++) { + reg[count] = chan++; + data[count] = MRST_TS_CHAN10 + count; + } + reg[count] = chan; + data[count] = END_OF_CHANNEL; + + return intel_scu_ipc_writev(reg, data, 5); +} + +/* Initialize ADC */ +static int mrstouch_adc_init(struct mrstouch_dev *tsdev) +{ + int err, start; + u8 ra, rm; + + err = mrstouch_pmic_id(&tsdev->vendor, &tsdev->rev); + if (err) { + dev_err(&tsdev->spi->dev, "Unable to read PMIC id\n"); + return err; + } + + start = mrstouch_chan_parse(tsdev); + if (start < 0) { + dev_err(&tsdev->spi->dev, "Unable to parse channels\n"); + return start; + } + + tsdev->asr = start; + + mrstouch_debug("Channel offset(%d): 0x%X\n", tsdev->asr, tsdev->vendor); + + /* ADC power on, start, enable PENDET and set loop delay + * ADC loop delay is set to 4.5 ms approximately + * Loop delay more than this results in jitter in adc readings + * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET + * interrupt generation sometimes. + */ + + if (tsdev->vendor == PMIC_VENDOR_FS) { + ra = 0xE0 | ADC_LOOP_DELAY0; + rm = 0x5; + } else { + /* NEC and MAXIm not consistent with loop delay 0 */ + ra = 0xE0 | ADC_LOOP_DELAY1; + rm = 0x0; + + /* configure touch screen channels */ + err = mrstouch_ts_chan_set(tsdev->asr); + if (err) + return err; + } + err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7); + if (err == 0) + err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03); + return err; +} + +/* Reports x,y coordinates to event subsystem */ +static void mrstouch_report_xy(struct mrstouch_dev *tsdev, u16 x, u16 y, u16 z) +{ + int xdiff, ydiff; + + if (tsdev->pendown && z <= TOUCH_PRESSURE) { + /* Pen removed, report button release */ + mrstouch_debug("BTN REL(%d)", z); + input_report_key(tsdev->input, BTN_TOUCH, 0); + tsdev->pendown = false; + } + + xdiff = abs(x - tsdev->x); + ydiff = abs(y - tsdev->y); + + /* + if x and y values changes for XYMOVE_CNT readings it is considered + as stylus is moving. This is required to differentiate between stylus + movement and jitter + */ + if (x < MIN_X || x > MAX_X || y < MIN_Y || y > MAX_Y) { + /* Spurious values, release button if touched and return */ + if (tsdev->pendown) { + mrstouch_debug("BTN REL(%d)", z); + input_report_key(tsdev->input, BTN_TOUCH, 0); + tsdev->pendown = false; + } + return; + } else if (xdiff >= XMOVE_LIMIT || ydiff >= YMOVE_LIMIT) { + tsdev->x = x; + tsdev->y = y; + + input_report_abs(tsdev->input, ABS_X, x); + input_report_abs(tsdev->input, ABS_Y, y); + input_sync(tsdev->input); + } + + + if (!tsdev->pendown && z > TOUCH_PRESSURE) { + /* Pen touched, report button touch */ + mrstouch_debug("BTN TCH(%d, %d, %d)", x, y, z); + input_report_key(tsdev->input, BTN_TOUCH, 1); + tsdev->pendown = true; + } +} + + +/* Utility to start ADC, used by freescale handler */ +static int pendet_mask(void) +{ + return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02); +} + +/* Utility to stop ADC, used by freescale handler */ +static int pendet_umask(void) +{ + return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02); +} + +/* Utility to read ADC, used by freescale handler */ +static int mrstouch_pmic_fs_adc_read(struct mrstouch_dev *tsdev) +{ + int err; + u16 x, y, z, result; + u16 reg[4]; + u8 data[4]; + + result = PMIC_REG_ADCSNS0H + tsdev->asr; + + reg[0] = result + 4; + reg[1] = result + 5; + reg[2] = result + 16; + reg[3] = result + 17; + + err = intel_scu_ipc_readv(reg, data, 4); + if (err) + goto ipc_error; + + x = data[0] << 3; /* Higher 7 bits */ + x |= data[1] & 0x7; /* Lower 3 bits */ + x &= 0x3FF; + + y = data[2] << 3; /* Higher 7 bits */ + y |= data[3] & 0x7; /* Lower 3 bits */ + y &= 0x3FF; + + /* Read Z value */ + reg[0] = result + 28; + reg[1] = result + 29; + + err = intel_scu_ipc_readv(reg, data, 4); + if (err) + goto ipc_error; + + z = data[0] << 3; /* Higher 7 bits */ + z |= data[1] & 0x7; /* Lower 3 bits */ + z &= 0x3FF; + +#if defined(MRSTOUCH_PRINT_XYZP) + mrstouch_debug("X: %d, Y: %d, Z: %d", x, y, z); +#endif + + if (z >= TOUCH_PRESSURE_FS) { + mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE - 1); /* Pen Removed */ + return TOUCH_PRESSURE - 1; + } else { + mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE + 1); /* Pen Touched */ + return TOUCH_PRESSURE + 1; + } + + return 0; + +ipc_error: + dev_err(&tsdev->spi->dev, "ipc error during fs_adc read\n"); + return err; +} + +/* To handle free scale pmic pendet interrupt */ +static int pmic0_pendet(void *dev_id) +{ + int err, count; + u16 chan; + unsigned int touched; + struct mrstouch_dev *tsdev = (struct mrstouch_dev *)dev_id; + u16 reg[5]; + u8 data[5]; + + chan = PMICADDR0 + tsdev->asr; + + /* Set X BIAS */ + for (count = 0; count <= 3; count++) { + reg[count] = chan++; + data[count] = 0x2A; + } + reg[count] = chan++; /* Dummy */ + data[count] = 0; + + err = intel_scu_ipc_writev(reg, data, 5); + if (err) + goto ipc_error; + + msleep(WAIT_ADC_COMPLETION); + + /* Set Y BIAS */ + for (count = 0; count <= 3; count++) { + reg[count] = chan++; + data[count] = 0x4A; + } + reg[count] = chan++; /* Dummy */ + data[count] = 0; + + err = intel_scu_ipc_writev(reg, data, 5); + if (err) + goto ipc_error; + + msleep(WAIT_ADC_COMPLETION); + + /* Set Z BIAS */ + err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A); + if (err) + goto ipc_error; + + msleep(WAIT_ADC_COMPLETION); + + /*Read touch screen channels till pen removed + * Freescale reports constant value of z for all points + * z is high when screen is not touched and low when touched + * Map high z value to not touched and low z value to pen touched + */ + touched = mrstouch_pmic_fs_adc_read(tsdev); + while (touched > TOUCH_PRESSURE) { + touched = mrstouch_pmic_fs_adc_read(tsdev); + msleep(WAIT_ADC_COMPLETION); + } + + /* Clear all TS channels */ + chan = PMICADDR0 + tsdev->asr; + for (count = 0; count <= 4; count++) { + reg[count] = chan++; + data[count] = 0; + } + err = intel_scu_ipc_writev(reg, data, 5); + if (err) + goto ipc_error; + + for (count = 0; count <= 4; count++) { + reg[count] = chan++; + data[count] = 0; + } + err = intel_scu_ipc_writev(reg, data, 5); + if (err) + goto ipc_error; + + err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000); + if (err) + goto ipc_error; + + return 0; + +ipc_error: + dev_err(&tsdev->spi->dev, "ipc error during pendet\n"); + return err; +} + + +/* To enable X, Y and Z bias values + * Enables YPYM for X channels and XPXM for Y channels + */ +static int mrstouch_ts_bias_set(uint offset, uint bias) +{ + int count; + u16 chan, start; + u16 reg[4]; + u8 data[4]; + + chan = PMICADDR0 + offset; + start = MRST_TS_CHAN10; + + for (count = 0; count <= 3; count++) { + reg[count] = chan++; + data[count] = bias | (start + count); + } + return intel_scu_ipc_writev(reg, data, 4); +} + +/* To read touch screen channel values */ +static int mrstouch_adc_read(struct mrstouch_dev *tsdev) +{ + int err; + u16 xp, xm, yp, ym, zp, zm; + + /* configure Y bias for X channels */ + err = mrstouch_ts_bias_set(tsdev->asr, YBIAS); + if (err) + goto ipc_error; + + msleep(WAIT_ADC_COMPLETION); + + /* read x+ and x- channels */ + err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &xp, &xm); + if (err) + goto ipc_error; + + /* configure x bias for y channels */ + err = mrstouch_ts_bias_set(tsdev->asr, XBIAS); + if (err) + goto ipc_error; + + msleep(WAIT_ADC_COMPLETION); + + /* read y+ and y- channels */ + err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, &yp, &ym); + if (err) + goto ipc_error; + + /* configure z bias for x and y channels */ + err = mrstouch_ts_bias_set(tsdev->asr, ZBIAS); + if (err) + goto ipc_error; + + msleep(WAIT_ADC_COMPLETION); + + /* read z+ and z- channels */ + err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &zp, &zm); + if (err) + goto ipc_error; + +#if defined(MRSTOUCH_PRINT_XYZP) + printk(KERN_INFO "X+: %d, Y+: %d, Z+: %d\n", xp, yp, zp); +#endif + +#if defined(MRSTOUCH_PRINT_XYZM) + printk(KERN_INFO "X-: %d, Y-: %d, Z-: %d\n", xm, ym, zm); +#endif + + mrstouch_report_xy(tsdev, xp, yp, zp); /* report x and y to eventX */ + + return zp; + +ipc_error: + dev_err(&tsdev->spi->dev, "ipc error during adc read\n"); + return err; +} + +/* PENDET interrupt handler function for NEC and MAXIM */ +static void pmic12_pendet(void *data) +{ + unsigned int touched; + struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data; + + /* read touch screen channels till pen removed */ + do { + touched = mrstouch_adc_read(tsdev); + } while (touched > TOUCH_PRESSURE); +} + +/* Handler to process PENDET interrupt */ +int mrstouch_pendet(void *data) +{ + struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data; + while (1) { + /* Wait for PENDET interrupt */ + if (mutex_lock_interruptible(&tsdev->lock)) { + msleep(WAIT_ADC_COMPLETION); + continue; + } + + if (tsdev->busy) + return 0; + + tsdev->busy = true; + + if (tsdev->vendor == PMIC_VENDOR_NEC || + tsdev->vendor == PMIC_VENDOR_MAXIM) { + /* PENDET must be disabled in NEC before reading ADC */ + pendet_enable(tsdev,false); /* Disbale PENDET */ + pmic12_pendet(tsdev); + pendet_enable(tsdev, true); /*Enable PENDET */ + } else if (tsdev->vendor == PMIC_VENDOR_FS) { + pendet_umask(); /* Stop ADC */ + pmic0_pendet(tsdev); + pendet_mask(); /* Stop ADC */ + } else + dev_err(&tsdev->spi->dev, "Unsupported touchscreen: %d\n", + tsdev->vendor); + + tsdev->busy = false; + + } + return 0; +} + +/* PENDET interrupt handler */ +static irqreturn_t pendet_intr_handler(int irq, void *handle) +{ + struct mrstouch_dev *tsdev = (struct mrstouch_dev *)handle; + + mutex_unlock(&tsdev->lock); + return IRQ_HANDLED; +} + +/* Intializes input device and registers with input subsystem */ +static int ts_input_dev_init(struct mrstouch_dev *tsdev, struct spi_device *spi) +{ + int err = 0; + + mrstouch_debug("%s", __func__); + + tsdev->input = input_allocate_device(); + if (!tsdev->input) { + dev_err(&tsdev->spi->dev, "Unable to allocate input device.\n"); + return -EINVAL; + } + + tsdev->input->name = "mrst_touchscreen"; + snprintf(tsdev->phys, sizeof(tsdev->phys), + "%s/input0", dev_name(&spi->dev)); + tsdev->input->phys = tsdev->phys; + tsdev->input->dev.parent = &spi->dev; + + tsdev->input->id.vendor = tsdev->vendor; + tsdev->input->id.version = tsdev->rev; + + tsdev->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + tsdev->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(tsdev->input, ABS_X, MIN_X, MIN_Y, 0, 0); + input_set_abs_params(tsdev->input, ABS_Y, MIN_X, MIN_Y, 0, 0); + + err = input_register_device(tsdev->input); + if (err) { + dev_err(&tsdev->spi->dev, "unable to register input device\n"); + input_free_device(tsdev->input); + return err; + } + + mrstouch_debug("%s", "mrstouch initialized"); + + return 0; + +} + +/* Probe function for touch screen driver */ +static int __devinit mrstouch_probe(struct spi_device *mrstouch_spi) +{ + int err; + unsigned int myirq; + struct mrstouch_dev *tsdev; + + mrstouch_debug("%s(%p)", __func__, mrstouch_spi); + + mrstouchdevp = NULL; + myirq = mrstouch_spi->irq; + + if (!mrstouch_spi->irq) { + dev_err(&mrstouch_spi->dev, "no interrupt assigned\n"); + return -EINVAL; + } + + tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL); + if (!tsdev) { + dev_err(&mrstouch_spi->dev, "unable to allocate memory\n"); + return -ENOMEM; + } + + tsdev->irq = myirq; + mrstouchdevp = tsdev; + + err = mrstouch_adc_init(tsdev); + if (err) { + dev_err(&mrstouch_spi->dev, "ADC init failed\n"); + goto mrstouch_err_free_mem; + } + + dev_set_drvdata(&mrstouch_spi->dev, tsdev); + tsdev->spi = mrstouch_spi; + + err = ts_input_dev_init(tsdev, mrstouch_spi); + if (err) { + dev_err(&tsdev->spi->dev, "ts_input_dev_init failed"); + goto mrstouch_err_free_mem; + } + + mutex_init(&tsdev->lock); + mutex_lock(&tsdev->lock) + + mrstouch_debug("Requesting IRQ-%d", myirq); + err = request_irq(myirq, pendet_intr_handler, + 0, "mrstouch", tsdev); + if (err) { + dev_err(&tsdev->spi->dev, "unable to allocate irq\n"); + goto mrstouch_err_free_mem; + } + + tsdev->pendet_thrd = kthread_run(mrstouch_pendet, + (void *)tsdev, "pendet handler"); + if (IS_ERR(tsdev->pendet_thrd)) { + dev_err(&tsdev->spi->dev, "kthread_run failed\n"); + err = PTR_ERR(tsdev->pendet_thrd); + goto mrstouch_err_free_mem; + } + mrstouch_debug("%s", "Driver initialized"); + return 0; + +mrstouch_err_free_mem: + kfree(tsdev); + return err; +} + +static int mrstouch_suspend(struct spi_device *spi, pm_message_t msg) +{ + mrstouch_debug("%s", __func__); + mrstouchdevp->suspended = 1; + return 0; +} + +static int mrstouch_resume(struct spi_device *spi) +{ + mrstouch_debug("%s", __func__); + mrstouchdevp->suspended = 0; + return 0; +} + +static int mrstouch_remove(struct spi_device *spi) +{ + mrstouch_debug("%s", __func__); + free_irq(mrstouchdevp->irq, mrstouchdevp); + input_unregister_device(mrstouchdevp->input); + input_free_device(mrstouchdevp->input); + kfree(mrstouchdevp); + if (mrstouchdevp->pendet_thrd) + kthread_stop(mrstouchdevp->pendet_thrd); + return 0; +} + +static struct spi_driver mrstouch_driver = { + .driver = { + .name = "pmic_touch", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = mrstouch_probe, + .suspend = mrstouch_suspend, + .resume = mrstouch_resume, + .remove = mrstouch_remove, +}; + +static int __init mrstouch_module_init(void) +{ + int err; + + mrstouch_debug("%s", __func__); + err = spi_register_driver(&mrstouch_driver); + if (err) { + mrstouch_debug("%s(%d)", "SPI PENDET failed", err); + return -1; + } + + return 0; +} + +static void __exit mrstouch_module_exit(void) +{ + mrstouch_debug("%s", __func__); + spi_unregister_driver(&mrstouch_driver); + return; +} + +module_init(mrstouch_module_init); +module_exit(mrstouch_module_exit); + +MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com"); +MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver"); +MODULE_LICENSE("GPL"); -- GitLab From 6d8b0f5be5108f6a3fc922ca4acfbf10e14d6cd0 Mon Sep 17 00:00:00 2001 From: Ian Abbott <abbotti@mev.co.uk> Date: Wed, 19 May 2010 15:11:57 +0100 Subject: [PATCH 638/842] Staging: comedi: Give the addi_apci_* drivers different driver names It is not currently possible for more than one of the addi_apci_* drivers to register themselves with comedi at once because they all use the same comedi driver name "addi_common". Give them different names. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/drivers/addi-data/addi_common.c | 8 ++++++-- drivers/staging/comedi/drivers/addi_apci_035.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_1032.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_1500.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_1516.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_1564.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_16xx.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_1710.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_2016.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_2032.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_2200.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_3001.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_3120.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_3200.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_3300.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_3501.c | 2 ++ drivers/staging/comedi/drivers/addi_apci_3xxx.c | 2 ++ 17 files changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index 2c986413a81a..d7f9bf49bb75 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -68,6 +68,10 @@ You should also find the complete GPL in the COPYING file accompanying this sour #include "addi_common.h" #include "addi_amcc_s5933.h" +#ifndef ADDIDATA_DRIVER_NAME +#define ADDIDATA_DRIVER_NAME "addi_common" +#endif + /* Update-0.7.57->0.7.68MODULE_AUTHOR("ADDI-DATA GmbH <info@addi-data.com>"); */ /* Update-0.7.57->0.7.68MODULE_DESCRIPTION("Comedi ADDI-DATA module"); */ /* Update-0.7.57->0.7.68MODULE_LICENSE("GPL"); */ @@ -2528,7 +2532,7 @@ static const struct addi_board boardtypes[] = { #define n_boardtypes (sizeof(boardtypes)/sizeof(struct addi_board)) static struct comedi_driver driver_addi = { - .driver_name = "addi_common", + .driver_name = ADDIDATA_DRIVER_NAME, .module = THIS_MODULE, .attach = i_ADDI_Attach, .detach = i_ADDI_Detach, @@ -2583,7 +2587,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) v_pci_card_list_init(this_board->i_VendorId, 1); /* 1 for displaying the list.. */ pci_list_builded = 1; } - /* printk("comedi%d: addi_common: board=%s",dev->minor,this_board->pc_DriverName); */ + /* printk("comedi%d: "ADDIDATA_DRIVER_NAME": board=%s",dev->minor,this_board->pc_DriverName); */ if ((this_board->i_Dma) && (it->options[2] == 0)) { i_Dma = 1; diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c index da454e854c4c..6dfcbe803f2d 100644 --- a/drivers/staging/comedi/drivers/addi_apci_035.c +++ b/drivers/staging/comedi/drivers/addi_apci_035.c @@ -2,4 +2,6 @@ #define ADDIDATA_WATCHDOG 2 /* Or shold it be something else */ +#define ADDIDATA_DRIVER_NAME "addi_apci_035" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index fa2056e8aa0e..4722ec834f7b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_1032 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_1032" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c index 7a5cae599ef8..db3dafdcf691 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_1500 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_1500" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c index 8d414844009f..f591baff6a0b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1516.c +++ b/drivers/staging/comedi/drivers/addi_apci_1516.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_1516 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_1516" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 0351cdde1026..6f5c923ac226 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_1564 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_1564" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c index 506799041294..1d926add9e6d 100644 --- a/drivers/staging/comedi/drivers/addi_apci_16xx.c +++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_16XX 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_16xx" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_1710.c b/drivers/staging/comedi/drivers/addi_apci_1710.c index c433445913dd..df6ba8ccf56f 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1710.c +++ b/drivers/staging/comedi/drivers/addi_apci_1710.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_1710 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_1710" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_2016.c b/drivers/staging/comedi/drivers/addi_apci_2016.c index 271c47c8cad3..7266e412f0a6 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2016.c +++ b/drivers/staging/comedi/drivers/addi_apci_2016.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_2016 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_2016" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index 5108ea2a3924..f67da94119e8 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_2032 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_2032" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c index e439f835cf4f..bc7f7d653503 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2200.c +++ b/drivers/staging/comedi/drivers/addi_apci_2200.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_2200 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_2200" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_3001.c b/drivers/staging/comedi/drivers/addi_apci_3001.c index df97c305828b..d86c4209cb90 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3001.c +++ b/drivers/staging/comedi/drivers/addi_apci_3001.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_3001 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_3001" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index 9183125ddde4..0b22cf10415d 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_3120 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_3120" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c index f25a70b3290b..159313997dcf 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3200.c +++ b/drivers/staging/comedi/drivers/addi_apci_3200.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_3200 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_3200" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_3300.c b/drivers/staging/comedi/drivers/addi_apci_3300.c index 1ee4778ad45b..733c69abc43a 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3300.c +++ b/drivers/staging/comedi/drivers/addi_apci_3300.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_3300 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_3300" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index 1049e20237e8..d8a01b154e35 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_3501 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_3501" + #include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index fb9deb7083bd..942bc9e259a8 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -1,3 +1,5 @@ #define CONFIG_APCI_3XXX 1 +#define ADDIDATA_DRIVER_NAME "addi_apci_3xxx" + #include "addi-data/addi_common.c" -- GitLab From b2e68b00d5d3698c228f549c02f4f79305d2b270 Mon Sep 17 00:00:00 2001 From: Ian Abbott <abbotti@mev.co.uk> Date: Wed, 19 May 2010 15:11:58 +0100 Subject: [PATCH 639/842] Staging: comedi: addi-data: don't overwrite name for request_irq() The Addi-Data PCI drivers for Comedi use sprintf() in their comedi "attach" routine to construct a string to pass as the name in the call to request_irq(). All calls to "attach" routine share the same static buffer for this name, but the contents will differ on each call (including the comedi device number and the comedi board name). This changes the name displayed in /proc/interrupts for previous calls to request_irq() using the same buffer. Just use the board name instead; it has slightly less information (no comedi device number) but at least it doesn't change over the lifetime of the IRQ handler. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/drivers/addi-data/addi_common.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index d7f9bf49bb75..b18e81d8cf8a 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -2574,10 +2574,6 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) struct pcilst_struct *card = NULL; unsigned char pci_bus, pci_slot, pci_func; int i_Dma = 0; - static char c_Identifier[150]; - - sprintf(c_Identifier, "Addi-Data GmbH Comedi %s", - this_board->pc_DriverName); ret = alloc_private(dev, sizeof(struct addi_private)); if (ret < 0) @@ -2652,7 +2648,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) if (irq > 0) { if (request_irq(irq, v_ADDI_Interrupt, IRQF_SHARED, - c_Identifier, dev) < 0) { + this_board->pc_DriverName, dev) < 0) { printk(", unable to allocate IRQ %u, DISABLING IT", irq); irq = 0; /* Can't use IRQ */ -- GitLab From d4da77a73cb9cc9a1a349daa1a2723505b086e2d Mon Sep 17 00:00:00 2001 From: Ian Abbott <abbotti@mev.co.uk> Date: Wed, 19 May 2010 16:34:07 +0100 Subject: [PATCH 640/842] Staging: comedi: adv_pci_dio: Support Advantech PCI-1735U Add support for the Advantech PCI-1735U card, including support for a counter subdevice (based on an 82C54 counter timer chip). The counter subdevice needs more testing, as the only person I know who tried it couldn't get it to work! Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/drivers/adv_pci_dio.c | 180 +++++++++++++++++-- 1 file changed, 169 insertions(+), 11 deletions(-) diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index 40eeecf5347f..e424a0c7d34f 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -7,17 +7,17 @@ */ /* Driver: adv_pci_dio -Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1736UP, - PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754, - PCI-1756, PCI-1762 +Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U, + PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, + PCI-1754, PCI-1756, PCI-1762 Author: Michal Dobes <dobes@tesnet.cz> Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733, - PCI-1734, PCI-1736UP, PCI-1750, + PCI-1734, PCI-1735U, PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753, PCI-1753+PCI-1753E, PCI-1754, PCI-1756, PCI-1760, PCI-1762 Status: untested -Updated: Mon, 14 Apr 2008 10:43:08 +0100 +Updated: Tue, 04 May 2010 13:00:00 +0000 This driver supports now only insn interface for DI/DO/DIO. @@ -35,6 +35,7 @@ Configuration options: #include "comedi_pci.h" #include "8255.h" +#include "8253.h" #undef PCI_DIO_EXTDEBUG /* if defined, enable extensive debug logging */ @@ -49,7 +50,7 @@ Configuration options: /* hardware types of the cards */ enum hw_cards_id { - TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1736, + TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736, TYPE_PCI1750, TYPE_PCI1751, TYPE_PCI1752, @@ -67,7 +68,10 @@ enum hw_io_access { #define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */ #define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */ #define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per card */ +#define MAX_8254_SUBDEVS 1 /* max number of 8254 counter subdevs per card */ + /* (could be more than one 8254 per subdevice) */ +#define SIZE_8254 4 /* 8254 IO space length */ #define SIZE_8255 4 /* 8255 IO space length */ #define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */ @@ -85,6 +89,12 @@ enum hw_io_access { #define PCI1734_IDO 0 /* W: Isolated digital output 0-31 */ #define PCI173x_BOARDID 4 /* R: Board I/D switch for 1730/3/4 */ +/* Advantech PCI-1735U */ +#define PCI1735_DI 0 /* R: Digital input 0-31 */ +#define PCI1735_DO 0 /* W: Digital output 0-31 */ +#define PCI1735_C8254 4 /* R/W: 8254 counter */ +#define PCI1735_BOARDID 8 /* R: Board I/D switch for 1735U */ + /* Advantech PCI-1736UP */ #define PCI1736_IDI 0 /* R: Isolated digital input 0-15 */ #define PCI1736_IDO 0 /* W: Isolated digital output 0-15 */ @@ -192,7 +202,8 @@ static int pci_dio_detach(struct comedi_device *dev); struct diosubd_data { int chans; /* num of chans */ int addr; /* PCI address ofset */ - int regs; /* number of registers to read or 8255 subdevices */ + int regs; /* number of registers to read or 8255 + subdevices or 8254 chips */ unsigned int specflags; /* addon subdevice flags */ }; @@ -206,6 +217,7 @@ struct dio_boardtype { struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */ struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */ struct diosubd_data boardid; /* card supports board ID switch */ + struct diosubd_data s8254[MAX_8254_SUBDEVS]; /* 8254 subdevices */ enum hw_io_access io_access; }; @@ -214,6 +226,7 @@ static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = { PCI_VENDOR_ID_ADVANTECH, 0x1730, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ADVANTECH, 0x1733, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ADVANTECH, 0x1734, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { + PCI_VENDOR_ID_ADVANTECH, 0x1735, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ADVANTECH, 0x1750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ADVANTECH, 0x1751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { @@ -235,14 +248,15 @@ static const struct dio_boardtype boardtypes[] = { {{16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, - IO_8b, - }, + {{0, 0, 0, 0}}, + IO_8b}, {"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG, TYPE_PCI1733, {{0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG, TYPE_PCI1734, @@ -250,6 +264,15 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, + IO_8b}, + {"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG, + TYPE_PCI1735, + {{32, PCI1735_DI, 4, 0}, {0, 0, 0, 0}}, + {{32, PCI1735_DO, 4, 0}, {0, 0, 0, 0}}, + {{0, 0, 0, 0}, {0, 0, 0, 0}}, + { 4, PCI1735_BOARDID, 1, SDF_INTERNAL}, + {{3, PCI1735_C8254, 1, 0}}, IO_8b}, {"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG, TYPE_PCI1736, @@ -257,14 +280,15 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI1736_BOARDID, 1, SDF_INTERNAL}, - IO_8b, - }, + {{0, 0, 0, 0}}, + IO_8b}, {"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG, TYPE_PCI1750, {{0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0}}, {{0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {0, 0, 0, 0}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG, TYPE_PCI1751, @@ -272,6 +296,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0}}, {0, 0, 0, 0}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG, TYPE_PCI1752, @@ -279,6 +304,7 @@ static const struct dio_boardtype boardtypes[] = { {{32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, IO_16b}, {"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG, TYPE_PCI1753, @@ -286,6 +312,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0}}, {0, 0, 0, 0}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG, TYPE_PCI1753E, @@ -293,6 +320,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0}}, {0, 0, 0, 0}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG, TYPE_PCI1754, @@ -300,6 +328,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, IO_16b}, {"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG, TYPE_PCI1756, @@ -307,6 +336,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, IO_16b}, {"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0, TYPE_PCI1760, @@ -314,6 +344,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {0, 0, 0, 0}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG, TYPE_PCI1762, @@ -321,6 +352,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {16, PCI1762_RO, 1, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI1762_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, IO_16b} }; @@ -437,6 +469,83 @@ static int pci_dio_insn_bits_do_w(struct comedi_device *dev, return 2; } +/* +============================================================================== +*/ +static int pci_8254_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + const struct diosubd_data *d = (const struct diosubd_data *)s->private; + unsigned int chan, chip, chipchan; + unsigned long flags; + + chan = CR_CHAN(insn->chanspec); /* channel on subdevice */ + chip = chan / 3; /* chip on subdevice */ + chipchan = chan - (3 * chip); /* channel on chip on subdevice */ + spin_lock_irqsave(&s->spin_lock, flags); + data[0] = i8254_read(dev->iobase + d->addr + (SIZE_8254 * chip), + 0, chipchan); + spin_unlock_irqrestore(&s->spin_lock, flags); + return 1; +} + +/* +============================================================================== +*/ +static int pci_8254_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + const struct diosubd_data *d = (const struct diosubd_data *)s->private; + unsigned int chan, chip, chipchan; + unsigned long flags; + + chan = CR_CHAN(insn->chanspec); /* channel on subdevice */ + chip = chan / 3; /* chip on subdevice */ + chipchan = chan - (3 * chip); /* channel on chip on subdevice */ + spin_lock_irqsave(&s->spin_lock, flags); + i8254_write(dev->iobase + d->addr + (SIZE_8254 * chip), + 0, chipchan, data[0]); + spin_unlock_irqrestore(&s->spin_lock, flags); + return 1; +} + +/* +============================================================================== +*/ +static int pci_8254_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + const struct diosubd_data *d = (const struct diosubd_data *)s->private; + unsigned int chan, chip, chipchan; + unsigned long iobase; + int ret = 0; + unsigned long flags; + + chan = CR_CHAN(insn->chanspec); /* channel on subdevice */ + chip = chan / 3; /* chip on subdevice */ + chipchan = chan - (3 * chip); /* channel on chip on subdevice */ + iobase = dev->iobase + d->addr + (SIZE_8254 * chip); + spin_lock_irqsave(&s->spin_lock, flags); + switch (data[0]) { + case INSN_CONFIG_SET_COUNTER_MODE: + ret = i8254_set_mode(iobase, 0, chipchan, data[1]); + if (ret < 0) + ret = -EINVAL; + break; + case INSN_CONFIG_8254_READ_STATUS: + data[1] = i8254_status(iobase, 0, chipchan); + break; + default: + ret = -EINVAL; + break; + } + spin_unlock_irqrestore(&s->spin_lock, flags); + return ret < 0 ? ret : insn->n; +} + /* ============================================================================== */ @@ -708,6 +817,15 @@ static int pci_dio_reset(struct comedi_device *dev) outb(0, dev->iobase + PCI1734_IDO + 2); outb(0, dev->iobase + PCI1734_IDO + 3); break; + case TYPE_PCI1735: + outb(0, dev->iobase + PCI1735_DO); /* clear outputs */ + outb(0, dev->iobase + PCI1735_DO + 1); + outb(0, dev->iobase + PCI1735_DO + 2); + outb(0, dev->iobase + PCI1735_DO + 3); + i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 0, I8254_MODE0); + i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 1, I8254_MODE0); + i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 2, I8254_MODE0); + break; case TYPE_PCI1736: outb(0, dev->iobase + PCI1736_IDO); @@ -874,6 +992,26 @@ static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } +/* +============================================================================== +*/ +static int pci_dio_add_8254(struct comedi_device *dev, + struct comedi_subdevice * s, + const struct diosubd_data *d, int subdev) +{ + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = d->chans; + s->maxdata = 65535; + s->len_chanlist = d->chans; + s->insn_read = pci_8254_insn_read; + s->insn_write = pci_8254_insn_write; + s->insn_config = pci_8254_insn_config; + s->private = (void *)d; + + return 0; +} + /* ============================================================================== */ @@ -979,6 +1117,9 @@ static int pci_dio_attach(struct comedi_device *dev, n_subdevices += this_board->sdio[i].regs; if (this_board->boardid.chans) n_subdevices++; + for (i = 0; i < MAX_8254_SUBDEVS; i++) + if (this_board->s8254[i].chans) + n_subdevices++; } ret = alloc_subdevices(dev, n_subdevices); @@ -1022,6 +1163,13 @@ static int pci_dio_attach(struct comedi_device *dev, subdev++; } + for (i = 0; i < MAX_8254_SUBDEVS; i++) + if (this_board->s8254[i].chans) { + s = dev->subdevices + subdev; + pci_dio_add_8254(dev, s, &this_board->s8254[i], subdev); + subdev++; + } + if (this_board->cardtype == TYPE_PCI1760) pci1760_attach(dev, it); @@ -1067,6 +1215,16 @@ static int pci_dio_detach(struct comedi_device *dev) } } + if (this_board->boardid.chans) { + subdev++; + } + + for (i = 0; i < MAX_8254_SUBDEVS; i++) { + if (this_board->s8254[i].chans) { + subdev++; + } + } + for (i = 0; i < dev->n_subdevices; i++) { s = dev->subdevices + i; s->private = NULL; -- GitLab From ee4063fa6bd801fa6ea045f23a2934db009b3dac Mon Sep 17 00:00:00 2001 From: Ian Abbott <abbotti@mev.co.uk> Date: Wed, 19 May 2010 16:59:40 +0100 Subject: [PATCH 641/842] Staging: comedi: amplc_dio200: Protect counter subdevice with spinlock The internal state of an 82C54 counter timer chip will get messed up if several threads read, write, configure, or check the status of the chip simultaneously. Protect the register access sequences with a spin lock. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/drivers/amplc_dio200.c | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index 8eb67651486a..bf27617aa62d 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -460,6 +460,7 @@ struct dio200_subdev_8254 { int has_clk_gat_sce; unsigned clock_src[3]; /* Current clock sources */ unsigned gate_src[3]; /* Current gate sources */ + spinlock_t spinlock; }; struct dio200_subdev_intr { @@ -1042,8 +1043,11 @@ dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s, { struct dio200_subdev_8254 *subpriv = s->private; int chan = CR_CHAN(insn->chanspec); + unsigned long flags; + spin_lock_irqsave(&subpriv->spinlock, flags); data[0] = i8254_read(subpriv->iobase, 0, chan); + spin_unlock_irqrestore(&subpriv->spinlock, flags); return 1; } @@ -1057,8 +1061,11 @@ dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s, { struct dio200_subdev_8254 *subpriv = s->private; int chan = CR_CHAN(insn->chanspec); + unsigned long flags; + spin_lock_irqsave(&subpriv->spinlock, flags); i8254_write(subpriv->iobase, 0, chan, data[0]); + spin_unlock_irqrestore(&subpriv->spinlock, flags); return 1; } @@ -1151,14 +1158,16 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct dio200_subdev_8254 *subpriv = s->private; - int ret; + int ret = 0; int chan = CR_CHAN(insn->chanspec); + unsigned long flags; + spin_lock_irqsave(&subpriv->spinlock, flags); switch (data[0]) { case INSN_CONFIG_SET_COUNTER_MODE: ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]); if (ret < 0) - return -EINVAL; + ret = -EINVAL; break; case INSN_CONFIG_8254_READ_STATUS: data[1] = i8254_status(subpriv->iobase, 0, chan); @@ -1166,30 +1175,35 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s, case INSN_CONFIG_SET_GATE_SRC: ret = dio200_set_gate_src(subpriv, chan, data[2]); if (ret < 0) - return -EINVAL; + ret = -EINVAL; break; case INSN_CONFIG_GET_GATE_SRC: ret = dio200_get_gate_src(subpriv, chan); - if (ret < 0) - return -EINVAL; + if (ret < 0) { + ret = -EINVAL; + break; + } data[2] = ret; break; case INSN_CONFIG_SET_CLOCK_SRC: ret = dio200_set_clock_src(subpriv, chan, data[1]); if (ret < 0) - return -EINVAL; + ret = -EINVAL; break; case INSN_CONFIG_GET_CLOCK_SRC: ret = dio200_get_clock_src(subpriv, chan, &data[2]); - if (ret < 0) - return -EINVAL; + if (ret < 0) { + ret = -EINVAL; + break; + } data[1] = ret; break; default: - return -EINVAL; + ret = -EINVAL; break; } - return insn->n; + spin_unlock_irqrestore(&subpriv->spinlock, flags); + return ret < 0 ? ret : insn->n; } /* @@ -1222,6 +1236,7 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s, s->insn_write = dio200_subdev_8254_write; s->insn_config = dio200_subdev_8254_config; + spin_lock_init(&subpriv->spinlock); subpriv->iobase = offset + iobase; subpriv->has_clk_gat_sce = has_clk_gat_sce; if (has_clk_gat_sce) { -- GitLab From d261154057c27f6c1d256b6198b0ad08733f1758 Mon Sep 17 00:00:00 2001 From: Ian Abbott <abbotti@mev.co.uk> Date: Wed, 19 May 2010 17:22:41 +0100 Subject: [PATCH 642/842] Staging: comedi: don't write to buffer if command finished For write(), any data copied to the data buffer after the previously set up streaming acquisition command has finished won't be used, but a non-empty write() does not currently return 0 (or -EPIPE on error) after the command has finished until the data buffer has been filled up. Change this behavior to return 0 (or -EPIPE) any time after the command has finished, without bothering to fill up the buffer with more useless data. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/comedi_fops.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index aced00e5cd10..39ed22b80229 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1576,6 +1576,19 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, while (nbytes > 0 && !retval) { set_current_state(TASK_INTERRUPTIBLE); + if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { + if (count == 0) { + if (comedi_get_subdevice_runflags(s) & + SRF_ERROR) { + retval = -EPIPE; + } else { + retval = 0; + } + do_become_nonbusy(dev, s); + } + break; + } + n = nbytes; m = n; @@ -1588,16 +1601,6 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, n = m; if (n == 0) { - if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { - if (comedi_get_subdevice_runflags(s) & - SRF_ERROR) { - retval = -EPIPE; - } else { - retval = 0; - } - do_become_nonbusy(dev, s); - break; - } if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; break; -- GitLab From 4772c018e35b6a21e8a8bde54568b59998540a16 Mon Sep 17 00:00:00 2001 From: Ian Abbott <abbotti@mev.co.uk> Date: Wed, 19 May 2010 18:09:49 +0100 Subject: [PATCH 643/842] Staging: comedi: COMEDI_BUFINFO with no async - report no bytes read or written When the COMEDI_BUFINFO ioctl is used on a subdevice without asynchronous streaming command support, set 'bytes_read = 0' and 'bytes_written = 0' in the buffer info returned back to the user. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/comedi_fops.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 39ed22b80229..75256251250d 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -584,6 +584,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, bi.buf_read_ptr = 0; bi.buf_write_count = 0; bi.buf_read_count = 0; + bi.bytes_read = 0; + bi.bytes_written = 0; goto copyback; } -- GitLab From 53fa827e295d8b09a2446b3126577244644d256d Mon Sep 17 00:00:00 2001 From: Ian Abbott <abbotti@mev.co.uk> Date: Wed, 19 May 2010 18:09:50 +0100 Subject: [PATCH 644/842] Staging: comedi: For COMEDI_BUFINFO, check access to command Don't allow COMEDI_BUFINFO ioctl if some other file object has locked the subdevice or has an active command. If there is no active command, just report back the last buffer position. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/comedi_fops.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 75256251250d..aeb2c00875cd 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -83,7 +83,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, static int do_chaninfo_ioctl(struct comedi_device *dev, struct comedi_chaninfo __user *arg); static int do_bufinfo_ioctl(struct comedi_device *dev, - struct comedi_bufinfo __user *arg); + struct comedi_bufinfo __user *arg, void *file); static int do_cmd_ioctl(struct comedi_device *dev, struct comedi_cmd __user *arg, void *file); static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, @@ -169,7 +169,8 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, break; case COMEDI_BUFINFO: rc = do_bufinfo_ioctl(dev, - (struct comedi_bufinfo __user *)arg); + (struct comedi_bufinfo __user *)arg, + file); break; case COMEDI_LOCK: rc = do_lock_ioctl(dev, arg, file); @@ -563,7 +564,7 @@ static int do_chaninfo_ioctl(struct comedi_device *dev, */ static int do_bufinfo_ioctl(struct comedi_device *dev, - struct comedi_bufinfo __user *arg) + struct comedi_bufinfo __user *arg, void *file) { struct comedi_bufinfo bi; struct comedi_subdevice *s; @@ -576,6 +577,10 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, return -EINVAL; s = dev->subdevices + bi.subdevice; + + if (s->lock && s->lock != file) + return -EACCES; + async = s->async; if (!async) { @@ -588,6 +593,13 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, bi.bytes_written = 0; goto copyback; } + if (!s->busy) { + bi.bytes_read = 0; + bi.bytes_written = 0; + goto copyback_position; + } + if (s->busy != file) + return -EACCES; if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) { bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read); @@ -606,6 +618,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, comedi_buf_write_free(async, bi.bytes_written); } +copyback_position: bi.buf_write_count = async->buf_write_count; bi.buf_write_ptr = async->buf_write_ptr; bi.buf_read_count = async->buf_read_count; -- GitLab From 824196248c1f28aa7d151fd5b11d76182c751f19 Mon Sep 17 00:00:00 2001 From: Alexander Kurz <linux@kbdbabel.org> Date: Wed, 19 May 2010 23:13:19 +0400 Subject: [PATCH 645/842] Staging: comedi: fix 8255 and DAS08 Kconfig dependancies. Both drivers support directly or indirectly multiple bus types, hence both are listed independent of bus types. Signed-off-by: Alexander Kurz <linux@kbdbabel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/Kconfig | 78 ++++++++++++++++++------- drivers/staging/comedi/drivers/Makefile | 4 +- 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 8ce307e64b58..7ac097e2576c 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -100,15 +100,6 @@ menuconfig COMEDI_ISA_DRIVERS if COMEDI_ISA_DRIVERS && ISA -config COMEDI_8255 - tristate "Generic 8255 support" - default N - ---help--- - Enable generic 8255 support. - - To compile this driver as a module, choose M here: the module will be - called 8255. - config COMEDI_ACL7225B tristate "ADlink NuDAQ ACL-7225b and compatibles support" default N @@ -130,6 +121,7 @@ config COMEDI_PCL711 config COMEDI_PCL724 tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO" + select COMEDI_8255 default N ---help--- Enable support for Advantech PCL-724, PCL-722, PCL-731 and @@ -198,6 +190,7 @@ config COMEDI_PCL818 config COMEDI_PCM3724 tristate "Advantech PCM-3724 PC/104 card support" + select COMEDI_8255 default N ---help--- Enable support for Advantech PCM-3724 PC/104 cards. @@ -232,18 +225,9 @@ config COMEDI_RTI802 To compile this driver as a module, choose M here: the module will be called rti802. -config COMEDI_DAS08 - tristate "DAS-08 compatible ISA, PC/104 and PCMCIA card support" - default N - ---help--- - Enable support for Keithley Metrabyte/ComputerBoards DAS08 - and compatible ISA and PC/104 cards - - To compile this driver as a module, choose M here: the module will be - called das08. - config COMEDI_DAS16M1 tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support" + select COMEDI_8255 select COMEDI_FC default N ---help--- @@ -254,6 +238,7 @@ config COMEDI_DAS16M1 config COMEDI_DAS16 tristate "DAS-16 compatible ISA and PC/104 card support" + select COMEDI_8255 select COMEDI_FC default N ---help--- @@ -385,6 +370,7 @@ config COMEDI_FL512 config COMEDI_AIO_AIO12_8 tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support" + select COMEDI_8255 default N ---help--- Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board @@ -466,6 +452,7 @@ config COMEDI_NI_ATMIO config COMEDI_NI_ATMIO16D tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support" depends on ISAPNP && COMEDI_NI_COMMON + select COMEDI_8255 default N ---help--- Enable support for National Instruments AT-MIO16/AT-MIO16D cards. @@ -667,6 +654,7 @@ config COMEDI_ADDI_APCI_3XXX config COMEDI_ADL_PCI6208 tristate "ADLink PCI-6208A support" + select COMEDI_8255 default N ---help--- Enable support for ADLink PCI-6208A cards @@ -751,6 +739,7 @@ config COMEDI_ADV_PCI1723 config COMEDI_ADV_PCI_DIO tristate "Advantech PCI DIO card support" + select COMEDI_8255 default N ---help--- Enable support for Advantech PCI DIO cards @@ -762,6 +751,7 @@ config COMEDI_ADV_PCI_DIO config COMEDI_AMPLC_DIO200 tristate "Amplicon PC272E and PCI272 DIO board support" + select COMEDI_8255 default N ---help--- Enable support for Amplicon PC272E and PCI272 DIO boards @@ -771,6 +761,7 @@ config COMEDI_AMPLC_DIO200 config COMEDI_AMPLC_PC236 tristate "Amplicon PC36AT and PCI236 DIO board support" + select COMEDI_8255 default N ---help--- Enable support for Amplicon PC36AT and PCI236 DIO boards @@ -799,6 +790,7 @@ config COMEDI_AMPLC_PCI224 config COMEDI_AMPLC_PCI230 tristate "Amplicon PCI230 and PCI260 support" + select COMEDI_8255 default N ---help--- Enable support for Amplicon PCI230 and PCI260 Multifunction I/O @@ -869,6 +861,7 @@ config COMEDI_II_PCI20KC config COMEDI_DAQBOARD2000 tristate "IOtech DAQboard/2000 support" + select COMEDI_8255 default N ---help--- Enable support for the IOtech DAQboard/2000 @@ -896,6 +889,7 @@ config COMEDI_KE_COUNTER config COMEDI_CB_PCIDAS64 tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support" + select COMEDI_8255 select COMEDI_FC default N ---help--- @@ -907,6 +901,7 @@ config COMEDI_CB_PCIDAS64 config COMEDI_CB_PCIDAS tristate "MeasurementComputing PCI-DAS support" + select COMEDI_8255 select COMEDI_FC default N ---help--- @@ -920,6 +915,7 @@ config COMEDI_CB_PCIDAS config COMEDI_CB_PCIDDA tristate "MeasurementComputing PCI-DDA series support" + select COMEDI_8255 default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI-DDA @@ -931,6 +927,7 @@ config COMEDI_CB_PCIDDA config COMEDI_CB_PCIDIO tristate "MeasurementComputing PCI-DIO series support" + select COMEDI_8255 default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI-DIO series @@ -941,6 +938,7 @@ config COMEDI_CB_PCIDIO config COMEDI_CB_PCIMDAS tristate "MeasurementComputing PCIM-DAS1602/16 support" + select COMEDI_8255 default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI Migration @@ -951,6 +949,7 @@ config COMEDI_CB_PCIMDAS config COMEDI_CB_PCIMDDA tristate "MeasurementComputing PCIM-DDA06-16 support" + select COMEDI_8255 default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16 @@ -1026,6 +1025,7 @@ config COMEDI_NI_670X config COMEDI_NI_PCIDIO tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support" depends on COMEDI_MITE + select COMEDI_8255 default N ---help--- Enable support for National Instruments PCI-DIO-32HS, PXI-6533, @@ -1058,6 +1058,7 @@ config COMEDI_NI_PCIMIO config COMEDI_RTD520 tristate "Real Time Devices PCI4520/DM7520 support" + select COMEDI_8255 default N ---help--- Enable support for Real Time Devices PCI4520/DM7520 @@ -1097,7 +1098,7 @@ endif # COMEDI_PCI_DRIVERS menuconfig COMEDI_PCMCIA_DRIVERS tristate "Comedi PCMCIA drivers" - depends on COMEDI && PCMCIA && PCCARD + depends on COMEDI && (PCMCIA || PCCARD) default N ---help--- Enable comedi PCMCIA and PCCARD drivers to be built @@ -1142,6 +1143,7 @@ config COMEDI_NI_DAQ_700_CS config COMEDI_NI_DAQ_DIO24_CS tristate "NI DAQ-Card DIO-24 PCMCIA support" depends on COMEDI_NI_COMMON + select COMEDI_8255 default N ---help--- Enable support for the National Instruments PCMCIA DAQ-Card DIO-24 @@ -1162,8 +1164,8 @@ config COMEDI_NI_LABPC_CS config COMEDI_NI_MIO_CS tristate "NI DAQCard E series PCMCIA support" depends on COMEDI_NI_TIO && COMEDI_NI_COMMON - default N select COMEDI_FC + default N ---help--- Enable support for the National Instruments PCMCIA DAQCard E series DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E @@ -1265,6 +1267,7 @@ config COMEDI_MITE config COMEDI_NI_TIO tristate "NI general purpose counter support" + select COMEDI_8255 select COMEDI_MITE default N ---help--- @@ -1278,6 +1281,7 @@ config COMEDI_NI_TIO config COMEDI_NI_LABPC tristate "NI Lab-PC and compatibles ISA and PCI support" + select COMEDI_8255 select COMEDI_FC default N ---help--- @@ -1291,8 +1295,40 @@ config COMEDI_NI_LABPC endif # COMEDI_NI_COMMON +config COMEDI_8255 + tristate "Generic 8255 support" + depends on COMEDI + default N + ---help--- + Enable generic 8255 support. + + You should enable compilation this driver if you plan to use a board + that has an 8255 chip. For multifunction boards, the main driver will + configure the 8255 subdevice automatically. + + Note that most PCI 8255 boards do NOT work with this driver, and + need a separate driver as a wrapper. + + To compile this driver as a module, choose M here: the module will be + called 8255. + +config COMEDI_DAS08 + tristate "DAS-08 compatible support" + depends on COMEDI + select COMEDI_8255 + default N + ---help--- + Enable support for DAS08 and compatible ISA, PC/104 and PCI cards. + + Note that PCMCIA DAS08 cards are not directly supported by this + driver, and need a separate driver as a wrapper. + + To compile this driver as a module, choose M here: the module will be + called das08. + config COMEDI_FC tristate "Comedi shared functions for low-level driver support" + depends on COMEDI default N ---help--- Enable support for shared functions for low-level drivers. diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 5ccf246e2526..354fb7d29841 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_COMEDI_SERIAL2002) += serial2002.o obj-$(CONFIG_COMEDI_SKEL) += skel.o # Comedi ISA drivers -obj-$(CONFIG_COMEDI_8255) += 8255.o obj-$(CONFIG_COMEDI_ACL7225B) += acl7225b.o obj-$(CONFIG_COMEDI_PCL711) += pcl711.o obj-$(CONFIG_COMEDI_PCL724) += pcl724.o @@ -26,7 +25,6 @@ obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o obj-$(CONFIG_COMEDI_PCM3730) += pcm3730.o obj-$(CONFIG_COMEDI_RTI800) += rti800.o obj-$(CONFIG_COMEDI_RTI802) += rti802.o -obj-$(CONFIG_COMEDI_DAS08) += das08.o obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o obj-$(CONFIG_COMEDI_DAS16) += das16.o obj-$(CONFIG_COMEDI_DAS800) += das800.o @@ -135,4 +133,6 @@ obj-$(CONFIG_COMEDI_NI_TIO) += ni_tio.o obj-$(CONFIG_COMEDI_NI_TIO) += ni_tiocmd.o obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc.o +obj-$(CONFIG_COMEDI_8255) += 8255.o +obj-$(CONFIG_COMEDI_DAS08) += das08.o obj-$(CONFIG_COMEDI_FC) += comedi_fc.o -- GitLab From 34ef545aa8c68d91e2e503ac05c129094772afb4 Mon Sep 17 00:00:00 2001 From: Alexander Kurz <linux@blala.de> Date: Thu, 20 May 2010 00:32:42 +0400 Subject: [PATCH 646/842] Staging: comedi: fixing ni_tio to mite PCI dependancy On Wed, 19 May 2010, Randy Dunlap wrote: > linux-next of 2010-0519: > when CONFIG_PCI is not enabled: > > drivers/staging/comedi/drivers/mite.c: In function 'mite_init': > drivers/staging/comedi/drivers/mite.c:89: error: implicit declaration of function 'pci_dev_get' > drivers/staging/comedi/drivers/mite.c:89: warning: assignment makes pointer from integer without a cast > make[5]: *** [drivers/staging/comedi/drivers/mite.o] Error 1 This patch fixes the problem. Signed-off-by: Alexander Kurz <linux@kbdbabel.org> Acked-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 7ac097e2576c..2614c3f87244 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -1267,8 +1267,8 @@ config COMEDI_MITE config COMEDI_NI_TIO tristate "NI general purpose counter support" + depends on COMEDI_MITE select COMEDI_8255 - select COMEDI_MITE default N ---help--- Enable support for National Instruments general purpose counters. -- GitLab From 9d20015391dfc47f6371492925cc0333ac403414 Mon Sep 17 00:00:00 2001 From: Stepan Moskovchenko <stepanm@codeaurora.org> Date: Wed, 19 May 2010 11:03:30 -0700 Subject: [PATCH 647/842] Staging: add MSM framebuffer driver Qualcomm development of the MSM SOC framebuffer driver has diverged significantly from the driver used by Android. This is a snapshot of our current driver, in all it's agony. We are putting this in staging to help with the process of converging the two drivers. At this point, the driver has been tested only in dumb framebuffer mode. Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org> Signed-off-by: David Brown <davidb@codeaurora.org> Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org> [dwalker@codeaurora.org: added a small compile fix and TODO.] Signed-off-by: Daniel Walker <dwalker@codeaurora.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/msm/Kconfig | 134 ++ drivers/staging/msm/Makefile | 93 + drivers/staging/msm/TODO | 3 + drivers/staging/msm/ebi2_l2f.c | 569 +++++ drivers/staging/msm/ebi2_lcd.c | 250 ++ drivers/staging/msm/ebi2_tmd20.c | 1122 +++++++++ drivers/staging/msm/hdmi_sii9022.c | 248 ++ drivers/staging/msm/lcdc.c | 239 ++ drivers/staging/msm/lcdc_external.c | 54 + drivers/staging/msm/lcdc_gordon.c | 446 ++++ drivers/staging/msm/lcdc_grapefruit.c | 60 + drivers/staging/msm/lcdc_panel.c | 88 + drivers/staging/msm/lcdc_prism.c | 64 + drivers/staging/msm/lcdc_sharp_wvga_pt.c | 290 +++ drivers/staging/msm/lcdc_st15.c | 237 ++ drivers/staging/msm/lcdc_st1_wxga.c | 54 + drivers/staging/msm/lcdc_toshiba_wvga_pt.c | 374 +++ drivers/staging/msm/lcdc_wxga.c | 56 + drivers/staging/msm/logo.c | 98 + drivers/staging/msm/mddi.c | 375 +++ drivers/staging/msm/mddi_ext.c | 320 +++ drivers/staging/msm/mddi_ext_lcd.c | 91 + drivers/staging/msm/mddi_prism.c | 114 + drivers/staging/msm/mddi_sharp.c | 892 +++++++ drivers/staging/msm/mddi_toshiba.c | 1741 ++++++++++++++ drivers/staging/msm/mddi_toshiba.h | 52 + drivers/staging/msm/mddi_toshiba_vga.c | 136 ++ drivers/staging/msm/mddi_toshiba_wvga.c | 63 + drivers/staging/msm/mddi_toshiba_wvga_pt.c | 64 + drivers/staging/msm/mddihost.c | 377 +++ drivers/staging/msm/mddihost.h | 225 ++ drivers/staging/msm/mddihost_e.c | 63 + drivers/staging/msm/mddihosti.c | 2239 ++++++++++++++++++ drivers/staging/msm/mddihosti.h | 547 +++++ drivers/staging/msm/mdp.c | 1113 +++++++++ drivers/staging/msm/mdp.h | 695 ++++++ drivers/staging/msm/mdp4.h | 352 +++ drivers/staging/msm/mdp4_debugfs.c | 181 ++ drivers/staging/msm/mdp4_overlay.c | 1259 ++++++++++ drivers/staging/msm/mdp4_overlay_lcdc.c | 313 +++ drivers/staging/msm/mdp4_overlay_mddi.c | 254 ++ drivers/staging/msm/mdp4_util.c | 1686 +++++++++++++ drivers/staging/msm/mdp_cursor.c | 104 + drivers/staging/msm/mdp_dma.c | 561 +++++ drivers/staging/msm/mdp_dma_lcdc.c | 379 +++ drivers/staging/msm/mdp_dma_s.c | 139 ++ drivers/staging/msm/mdp_dma_tv.c | 142 ++ drivers/staging/msm/mdp_hw_init.c | 720 ++++++ drivers/staging/msm/mdp_ppp.c | 1502 ++++++++++++ drivers/staging/msm/mdp_ppp_dq.c | 347 +++ drivers/staging/msm/mdp_ppp_dq.h | 86 + drivers/staging/msm/mdp_ppp_v20.c | 2486 ++++++++++++++++++++ drivers/staging/msm/mdp_ppp_v31.c | 828 +++++++ drivers/staging/msm/mdp_vsync.c | 389 +++ drivers/staging/msm/memory.c | 214 ++ drivers/staging/msm/memory_ll.h | 61 + drivers/staging/msm/msm_fb.c | 2354 ++++++++++++++++++ drivers/staging/msm/msm_fb.h | 174 ++ drivers/staging/msm/msm_fb_bl.c | 79 + drivers/staging/msm/msm_fb_def.h | 201 ++ drivers/staging/msm/msm_fb_panel.c | 136 ++ drivers/staging/msm/msm_fb_panel.h | 145 ++ drivers/staging/msm/msm_mdp.h | 245 ++ drivers/staging/msm/staging-devices.c | 323 +++ drivers/staging/msm/tv_ntsc.c | 163 ++ drivers/staging/msm/tv_pal.c | 213 ++ drivers/staging/msm/tvenc.c | 295 +++ drivers/staging/msm/tvenc.h | 117 + 70 files changed, 30037 insertions(+) create mode 100644 drivers/staging/msm/Kconfig create mode 100644 drivers/staging/msm/Makefile create mode 100644 drivers/staging/msm/TODO create mode 100644 drivers/staging/msm/ebi2_l2f.c create mode 100644 drivers/staging/msm/ebi2_lcd.c create mode 100644 drivers/staging/msm/ebi2_tmd20.c create mode 100644 drivers/staging/msm/hdmi_sii9022.c create mode 100644 drivers/staging/msm/lcdc.c create mode 100644 drivers/staging/msm/lcdc_external.c create mode 100644 drivers/staging/msm/lcdc_gordon.c create mode 100644 drivers/staging/msm/lcdc_grapefruit.c create mode 100644 drivers/staging/msm/lcdc_panel.c create mode 100644 drivers/staging/msm/lcdc_prism.c create mode 100644 drivers/staging/msm/lcdc_sharp_wvga_pt.c create mode 100644 drivers/staging/msm/lcdc_st15.c create mode 100644 drivers/staging/msm/lcdc_st1_wxga.c create mode 100644 drivers/staging/msm/lcdc_toshiba_wvga_pt.c create mode 100644 drivers/staging/msm/lcdc_wxga.c create mode 100644 drivers/staging/msm/logo.c create mode 100644 drivers/staging/msm/mddi.c create mode 100644 drivers/staging/msm/mddi_ext.c create mode 100644 drivers/staging/msm/mddi_ext_lcd.c create mode 100644 drivers/staging/msm/mddi_prism.c create mode 100644 drivers/staging/msm/mddi_sharp.c create mode 100644 drivers/staging/msm/mddi_toshiba.c create mode 100644 drivers/staging/msm/mddi_toshiba.h create mode 100644 drivers/staging/msm/mddi_toshiba_vga.c create mode 100644 drivers/staging/msm/mddi_toshiba_wvga.c create mode 100644 drivers/staging/msm/mddi_toshiba_wvga_pt.c create mode 100644 drivers/staging/msm/mddihost.c create mode 100644 drivers/staging/msm/mddihost.h create mode 100644 drivers/staging/msm/mddihost_e.c create mode 100644 drivers/staging/msm/mddihosti.c create mode 100644 drivers/staging/msm/mddihosti.h create mode 100644 drivers/staging/msm/mdp.c create mode 100644 drivers/staging/msm/mdp.h create mode 100644 drivers/staging/msm/mdp4.h create mode 100644 drivers/staging/msm/mdp4_debugfs.c create mode 100644 drivers/staging/msm/mdp4_overlay.c create mode 100644 drivers/staging/msm/mdp4_overlay_lcdc.c create mode 100644 drivers/staging/msm/mdp4_overlay_mddi.c create mode 100644 drivers/staging/msm/mdp4_util.c create mode 100644 drivers/staging/msm/mdp_cursor.c create mode 100644 drivers/staging/msm/mdp_dma.c create mode 100644 drivers/staging/msm/mdp_dma_lcdc.c create mode 100644 drivers/staging/msm/mdp_dma_s.c create mode 100644 drivers/staging/msm/mdp_dma_tv.c create mode 100644 drivers/staging/msm/mdp_hw_init.c create mode 100644 drivers/staging/msm/mdp_ppp.c create mode 100644 drivers/staging/msm/mdp_ppp_dq.c create mode 100644 drivers/staging/msm/mdp_ppp_dq.h create mode 100644 drivers/staging/msm/mdp_ppp_v20.c create mode 100644 drivers/staging/msm/mdp_ppp_v31.c create mode 100644 drivers/staging/msm/mdp_vsync.c create mode 100644 drivers/staging/msm/memory.c create mode 100644 drivers/staging/msm/memory_ll.h create mode 100644 drivers/staging/msm/msm_fb.c create mode 100644 drivers/staging/msm/msm_fb.h create mode 100644 drivers/staging/msm/msm_fb_bl.c create mode 100644 drivers/staging/msm/msm_fb_def.h create mode 100644 drivers/staging/msm/msm_fb_panel.c create mode 100644 drivers/staging/msm/msm_fb_panel.h create mode 100644 drivers/staging/msm/msm_mdp.h create mode 100644 drivers/staging/msm/staging-devices.c create mode 100644 drivers/staging/msm/tv_ntsc.c create mode 100644 drivers/staging/msm/tv_pal.c create mode 100644 drivers/staging/msm/tvenc.c create mode 100644 drivers/staging/msm/tvenc.h diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 883c88f3de7a..984a75440710 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -145,5 +145,7 @@ source "drivers/staging/xgifb/Kconfig" source "drivers/staging/mrst-touchscreen/Kconfig" +source "drivers/staging/msm/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 352ca2a973c2..9fa25133874a 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -53,3 +53,4 @@ obj-$(CONFIG_TI_ST) += ti-st/ obj-$(CONFIG_ADIS16255) += adis16255/ obj-$(CONFIG_FB_XGI) += xgifb/ obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/ +obj-$(CONFIG_MSM_STAGING) += msm/ diff --git a/drivers/staging/msm/Kconfig b/drivers/staging/msm/Kconfig new file mode 100644 index 000000000000..c57039f2060b --- /dev/null +++ b/drivers/staging/msm/Kconfig @@ -0,0 +1,134 @@ +config MSM_STAGING + tristate "MSM Frame Buffer Support" + depends on FB && ARCH_MSM && !FB_MSM + select FB_BACKLIGHT if FB_MSM_BACKLIGHT + select NEW_LEDS + select LEDS_CLASS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Support for MSM Framebuffer. + +if MSM_STAGING + +config FB_MSM_LCDC_HW + bool + default n + +choice + prompt "MDP HW version" + default FB_MSM_MDP31 + +config FB_MSM_MDP31 + select FB_MSM_LCDC_HW + bool "MDP HW ver3.1" + ---help--- + Support for MSM MDP HW revision 3.1 + Say Y here if this is msm8x50 variant platform. +endchoice + +config FB_MSM_LCDC + bool + default n + +config FB_MSM_TVOUT + bool + default n + +config FB_MSM_LCDC_PANEL + bool + select FB_MSM_LCDC + default n + +config FB_MSM_LCDC_PRISM_WVGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_ST1_WXGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_ST15_WXGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_WXGA + bool + select FB_MSM_LCDC_PANEL + default n + +choice + prompt "LCD Panel" + default FB_MSM_LCDC_ST15_PANEL + +config FB_MSM_LCDC_PRISM_WVGA_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC Prism WVGA Panel" + select FB_MSM_LCDC_PRISM_WVGA + ---help--- + Support for LCDC Prism WVGA (800x480) panel + + +config FB_MSM_LCDC_ST15_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC ST1.5 Panel" + select FB_MSM_LCDC_ST15_WXGA + ---help--- + Support for ST1.5 WXGA (1366x768) panel + +config FB_MSM_PANEL_NONE + bool "NONE" + ---help--- + This will disable LCD panel +endchoice + +choice + prompt "Secondary LCD Panel" + depends on FB_MSM_MDP31 + default FB_MSM_SECONDARY_PANEL_NONE + +config FB_MSM_SECONDARY_PANEL_NONE + bool "NONE" + ---help--- + No secondary panel +endchoice + +config FB_MSM_TVOUT_NTSC + bool + select FB_MSM_TVOUT + default n + +config FB_MSM_TVOUT_PAL + bool + select FB_MSM_TVOUT + default n + +choice + depends on (FB_MSM_MDP22 || FB_MSM_MDP31) + prompt "TVOut Region" + default FB_MSM_TVOUT_NTSC_M + +config FB_MSM_TVOUT_NTSC_M + bool "NTSC M" + select FB_MSM_TVOUT_NTSC + ---help--- + Support for NTSC M region (North American and Korea) + +config FB_MSM_TVOUT_NONE + bool "NONE" + ---help--- + This will disable TV Out functionality. +endchoice + +config PMEM_KERNEL_SIZE + int "PMEM for kernel components (in MB)" + default 2 + depends on ARCH_QSD8X50 + help + Configures the amount of PMEM for use by kernel components + (in MB; minimum 2MB) +endif diff --git a/drivers/staging/msm/Makefile b/drivers/staging/msm/Makefile new file mode 100644 index 000000000000..98a0ce177cb2 --- /dev/null +++ b/drivers/staging/msm/Makefile @@ -0,0 +1,93 @@ +obj-y := msm_fb.o staging-devices.o memory.o + +obj-$(CONFIG_FB_MSM_LOGO) += logo.o +obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o + +# MDP +obj-y += mdp.o + +ifeq ($(CONFIG_FB_MSM_MDP40),y) +obj-y += mdp4_util.o +obj-$(CONFIG_DEBUG_FS) += mdp4_debugfs.o +else +obj-y += mdp_hw_init.o +obj-y += mdp_ppp.o +ifeq ($(CONFIG_FB_MSM_MDP31),y) +obj-y += mdp_ppp_v31.o +obj-$(CONFIG_MDP_PPP_ASYNC_OP) += mdp_ppp_dq.o +else +obj-y += mdp_ppp_v20.o +endif +endif + +ifeq ($(CONFIG_FB_MSM_OVERLAY),y) +obj-y += mdp4_overlay.o +obj-y += mdp4_overlay_lcdc.o +obj-y += mdp4_overlay_mddi.o +else +obj-y += mdp_dma_lcdc.o +endif + +obj-y += mdp_dma.o +obj-y += mdp_dma_s.o +obj-y += mdp_vsync.o +obj-y += mdp_cursor.o +obj-y += mdp_dma_tv.o + +# EBI2 +obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o + +# LCDC +obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o + +# MDDI +msm_mddi-objs := mddi.o mddihost.o mddihosti.o +obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o + +# External MDDI +msm_mddi_ext-objs := mddihost_e.o mddi_ext.o +obj-$(CONFIG_FB_MSM_EXTMDDI) += msm_mddi_ext.o + +# TVEnc +obj-$(CONFIG_FB_MSM_TVOUT) += tvenc.o + +# MSM FB Panel +obj-y += msm_fb_panel.o +obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_tmd20.o +obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_l2f.o + +ifeq ($(CONFIG_FB_MSM_MDDI_AUTO_DETECT),y) +obj-y += mddi_prism.o +obj-y += mddi_toshiba.o +obj-y += mddi_toshiba_vga.o +obj-y += mddi_toshiba_wvga_pt.o +obj-y += mddi_toshiba_wvga.o +obj-y += mddi_sharp.o +else +obj-$(CONFIG_FB_MSM_MDDI_PRISM_WVGA) += mddi_prism.o +obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON) += mddi_toshiba.o +obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA) += mddi_toshiba_vga.o +obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT) += mddi_toshiba_wvga_pt.o +obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA) += mddi_toshiba_wvga.o +obj-$(CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128) += mddi_sharp.o +endif + +obj-$(CONFIG_FB_MSM_LCDC_PANEL) += lcdc_panel.o +obj-$(CONFIG_FB_MSM_LCDC_PRISM_WVGA) += lcdc_prism.o +obj-$(CONFIG_FB_MSM_LCDC_EXTERNAL_WXGA) += lcdc_external.o +obj-$(CONFIG_FB_MSM_LCDC_GORDON_VGA) += lcdc_gordon.o +obj-$(CONFIG_FB_MSM_LCDC_WXGA) += lcdc_wxga.o +obj-$(CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT) += lcdc_toshiba_wvga_pt.o +obj-$(CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT) += lcdc_sharp_wvga_pt.o +obj-$(CONFIG_FB_MSM_LCDC_GRAPEFRUIT_VGA) += lcdc_grapefruit.o +obj-$(CONFIG_FB_MSM_LCDC_ST1_WXGA) += lcdc_st1_wxga.o +obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o +obj-$(CONFIG_FB_MSM_HDMI_SII_EXTERNAL_720P) += hdmi_sii9022.o + +obj-$(CONFIG_FB_MSM_TVOUT_NTSC) += tv_ntsc.o +obj-$(CONFIG_FB_MSM_TVOUT_PAL) += tv_pal.o + +obj-$(CONFIG_FB_MSM_EXTMDDI_SVGA) += mddi_ext_lcd.o + +clean: + rm *.o .*cmd diff --git a/drivers/staging/msm/TODO b/drivers/staging/msm/TODO new file mode 100644 index 000000000000..05107a7d516a --- /dev/null +++ b/drivers/staging/msm/TODO @@ -0,0 +1,3 @@ +- Merge this code with the existing MSM framebuffer +- General style clean ups. + diff --git a/drivers/staging/msm/ebi2_l2f.c b/drivers/staging/msm/ebi2_l2f.c new file mode 100644 index 000000000000..eea891d8f0f8 --- /dev/null +++ b/drivers/staging/msm/ebi2_l2f.c @@ -0,0 +1,569 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" + +#include <linux/memory.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include "linux/proc_fs.h" + +#include <linux/delay.h> + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> + +/* The following are for MSM5100 on Gator +*/ +#ifdef FEATURE_PM1000 +#include "pm1000.h" +#endif /* FEATURE_PM1000 */ +/* The following are for MSM6050 on Bambi +*/ +#ifdef FEATURE_PMIC_LCDKBD_LED_DRIVER +#include "pm.h" +#endif /* FEATURE_PMIC_LCDKBD_LED_DRIVER */ + +#ifdef DISP_DEVICE_18BPP +#undef DISP_DEVICE_18BPP +#define DISP_DEVICE_16BPP +#endif + +#define QCIF_WIDTH 176 +#define QCIF_HEIGHT 220 + +static void *DISP_CMD_PORT; +static void *DISP_DATA_PORT; + +#define DISP_CMD_DISON 0xaf +#define DISP_CMD_DISOFF 0xae +#define DISP_CMD_DISNOR 0xa6 +#define DISP_CMD_DISINV 0xa7 +#define DISP_CMD_DISCTL 0xca +#define DISP_CMD_GCP64 0xcb +#define DISP_CMD_GCP16 0xcc +#define DISP_CMD_GSSET 0xcd +#define DISP_GS_2 0x02 +#define DISP_GS_16 0x01 +#define DISP_GS_64 0x00 +#define DISP_CMD_SLPIN 0x95 +#define DISP_CMD_SLPOUT 0x94 +#define DISP_CMD_SD_PSET 0x75 +#define DISP_CMD_MD_PSET 0x76 +#define DISP_CMD_SD_CSET 0x15 +#define DISP_CMD_MD_CSET 0x16 +#define DISP_CMD_DATCTL 0xbc +#define DISP_DATCTL_666 0x08 +#define DISP_DATCTL_565 0x28 +#define DISP_DATCTL_444 0x38 +#define DISP_CMD_RAMWR 0x5c +#define DISP_CMD_RAMRD 0x5d +#define DISP_CMD_PTLIN 0xa8 +#define DISP_CMD_PTLOUT 0xa9 +#define DISP_CMD_ASCSET 0xaa +#define DISP_CMD_SCSTART 0xab +#define DISP_CMD_VOLCTL 0xc6 +#define DISP_VOLCTL_TONE 0x80 +#define DISP_CMD_NOp 0x25 +#define DISP_CMD_OSSEL 0xd0 +#define DISP_CMD_3500KSET 0xd1 +#define DISP_CMD_3500KEND 0xd2 +#define DISP_CMD_14MSET 0xd3 +#define DISP_CMD_14MEND 0xd4 + +#define DISP_CMD_OUT(cmd) outpw(DISP_CMD_PORT, cmd); + +#define DISP_DATA_OUT(data) outpw(DISP_DATA_PORT, data); + +#define DISP_DATA_IN() inpw(DISP_DATA_PORT); + +/* Epson device column number starts at 2 +*/ +#define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \ + DISP_CMD_OUT(DISP_CMD_SD_PSET) \ + DISP_DATA_OUT((ulhc_row) & 0xFF) \ + DISP_DATA_OUT((ulhc_row) >> 8) \ + DISP_DATA_OUT((lrhc_row) & 0xFF) \ + DISP_DATA_OUT((lrhc_row) >> 8) \ + DISP_CMD_OUT(DISP_CMD_SD_CSET) \ + DISP_DATA_OUT(((ulhc_col)+2) & 0xFF) \ + DISP_DATA_OUT(((ulhc_col)+2) >> 8) \ + DISP_DATA_OUT(((lrhc_col)+2) & 0xFF) \ + DISP_DATA_OUT(((lrhc_col)+2) >> 8) + +#define DISP_MIN_CONTRAST 0 +#define DISP_MAX_CONTRAST 127 +#define DISP_DEFAULT_CONTRAST 80 + +#define DISP_MIN_BACKLIGHT 0 +#define DISP_MAX_BACKLIGHT 15 +#define DISP_DEFAULT_BACKLIGHT 2 + +#define WAIT_SEC(sec) mdelay((sec)/1000) + +static word disp_area_start_row; +static word disp_area_end_row; +static byte disp_contrast = DISP_DEFAULT_CONTRAST; +static boolean disp_powered_up; +static boolean disp_initialized = FALSE; +/* For some reason the contrast set at init time is not good. Need to do + * it again + */ +static boolean display_on = FALSE; +static void epsonQcif_disp_init(struct platform_device *pdev); +static void epsonQcif_disp_set_contrast(word contrast); +static void epsonQcif_disp_set_display_area(word start_row, word end_row); +static int epsonQcif_disp_off(struct platform_device *pdev); +static int epsonQcif_disp_on(struct platform_device *pdev); +static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres); + +volatile word databack; +static void epsonQcif_disp_init(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + int i; + + if (disp_initialized) + return; + + mfd = platform_get_drvdata(pdev); + + DISP_CMD_PORT = mfd->cmd_port; + DISP_DATA_PORT = mfd->data_port; + + /* Sleep in */ + DISP_CMD_OUT(DISP_CMD_SLPIN); + + /* Display off */ + DISP_CMD_OUT(DISP_CMD_DISOFF); + + /* Display normal */ + DISP_CMD_OUT(DISP_CMD_DISNOR); + + /* Set data mode */ + DISP_CMD_OUT(DISP_CMD_DATCTL); + DISP_DATA_OUT(DISP_DATCTL_565); + + /* Set display timing */ + DISP_CMD_OUT(DISP_CMD_DISCTL); + DISP_DATA_OUT(0x1c); /* p1 */ + DISP_DATA_OUT(0x02); /* p1 */ + DISP_DATA_OUT(0x82); /* p2 */ + DISP_DATA_OUT(0x00); /* p3 */ + DISP_DATA_OUT(0x00); /* p4 */ + DISP_DATA_OUT(0xe0); /* p5 */ + DISP_DATA_OUT(0x00); /* p5 */ + DISP_DATA_OUT(0xdc); /* p6 */ + DISP_DATA_OUT(0x00); /* p6 */ + DISP_DATA_OUT(0x02); /* p7 */ + DISP_DATA_OUT(0x00); /* p8 */ + + /* Set 64 gray scale level */ + DISP_CMD_OUT(DISP_CMD_GCP64); + DISP_DATA_OUT(0x08); /* p01 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x2a); /* p02 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x4e); /* p03 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x6b); /* p04 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x88); /* p05 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0xa3); /* p06 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0xba); /* p07 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0xd1); /* p08 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0xe5); /* p09 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0xf3); /* p10 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x03); /* p11 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x13); /* p12 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x22); /* p13 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x2f); /* p14 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x3b); /* p15 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x46); /* p16 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x51); /* p17 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x5b); /* p18 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x64); /* p19 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x6c); /* p20 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x74); /* p21 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x7c); /* p22 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x83); /* p23 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x8a); /* p24 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x91); /* p25 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x98); /* p26 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x9f); /* p27 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xa6); /* p28 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xac); /* p29 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xb2); /* p30 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xb7); /* p31 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xbc); /* p32 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xc1); /* p33 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xc6); /* p34 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xcb); /* p35 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xd0); /* p36 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xd4); /* p37 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xd8); /* p38 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xdc); /* p39 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xe0); /* p40 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xe4); /* p41 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xe8); /* p42 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xec); /* p43 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xf0); /* p44 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xf4); /* p45 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xf8); /* p46 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xfb); /* p47 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xfe); /* p48 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x01); /* p49 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x03); /* p50 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x05); /* p51 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x07); /* p52 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x09); /* p53 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x0b); /* p54 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x0d); /* p55 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x0f); /* p56 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x11); /* p57 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x13); /* p58 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x15); /* p59 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x17); /* p60 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x19); /* p61 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x1b); /* p62 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x1c); /* p63 */ + DISP_DATA_OUT(0x02); + + /* Set 16 gray scale level */ + DISP_CMD_OUT(DISP_CMD_GCP16); + DISP_DATA_OUT(0x1a); /* p01 */ + DISP_DATA_OUT(0x32); /* p02 */ + DISP_DATA_OUT(0x42); /* p03 */ + DISP_DATA_OUT(0x4c); /* p04 */ + DISP_DATA_OUT(0x58); /* p05 */ + DISP_DATA_OUT(0x5f); /* p06 */ + DISP_DATA_OUT(0x66); /* p07 */ + DISP_DATA_OUT(0x6b); /* p08 */ + DISP_DATA_OUT(0x70); /* p09 */ + DISP_DATA_OUT(0x74); /* p10 */ + DISP_DATA_OUT(0x78); /* p11 */ + DISP_DATA_OUT(0x7b); /* p12 */ + DISP_DATA_OUT(0x7e); /* p13 */ + DISP_DATA_OUT(0x80); /* p14 */ + DISP_DATA_OUT(0x82); /* p15 */ + + /* Set DSP column */ + DISP_CMD_OUT(DISP_CMD_MD_CSET); + DISP_DATA_OUT(0xff); + DISP_DATA_OUT(0x03); + DISP_DATA_OUT(0xff); + DISP_DATA_OUT(0x03); + + /* Set DSP page */ + DISP_CMD_OUT(DISP_CMD_MD_PSET); + DISP_DATA_OUT(0xff); + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xff); + DISP_DATA_OUT(0x01); + + /* Set ARM column */ + DISP_CMD_OUT(DISP_CMD_SD_CSET); + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT((QCIF_WIDTH + 1) & 0xFF); + DISP_DATA_OUT((QCIF_WIDTH + 1) >> 8); + + /* Set ARM page */ + DISP_CMD_OUT(DISP_CMD_SD_PSET); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT((QCIF_HEIGHT - 1) & 0xFF); + DISP_DATA_OUT((QCIF_HEIGHT - 1) >> 8); + + /* Set 64 gray scales */ + DISP_CMD_OUT(DISP_CMD_GSSET); + DISP_DATA_OUT(DISP_GS_64); + + DISP_CMD_OUT(DISP_CMD_OSSEL); + DISP_DATA_OUT(0); + + /* Sleep out */ + DISP_CMD_OUT(DISP_CMD_SLPOUT); + + WAIT_SEC(40000); + + /* Initialize power IC */ + DISP_CMD_OUT(DISP_CMD_VOLCTL); + DISP_DATA_OUT(DISP_VOLCTL_TONE); + + WAIT_SEC(40000); + + /* Set electronic volume, d'xx */ + DISP_CMD_OUT(DISP_CMD_VOLCTL); + DISP_DATA_OUT(DISP_DEFAULT_CONTRAST); /* value from 0 to 127 */ + + /* Initialize display data */ + DISP_SET_RECT(0, (QCIF_HEIGHT - 1), 0, (QCIF_WIDTH - 1)); + DISP_CMD_OUT(DISP_CMD_RAMWR); + for (i = 0; i < QCIF_HEIGHT * QCIF_WIDTH; i++) + DISP_DATA_OUT(0xffff); + + DISP_CMD_OUT(DISP_CMD_RAMRD); + databack = DISP_DATA_IN(); + databack = DISP_DATA_IN(); + databack = DISP_DATA_IN(); + databack = DISP_DATA_IN(); + + WAIT_SEC(80000); + + DISP_CMD_OUT(DISP_CMD_DISON); + + disp_area_start_row = 0; + disp_area_end_row = QCIF_HEIGHT - 1; + disp_powered_up = TRUE; + disp_initialized = TRUE; + epsonQcif_disp_set_display_area(0, QCIF_HEIGHT - 1); + display_on = TRUE; +} + +static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres) +{ + if (!disp_initialized) + return; + + DISP_SET_RECT(y, y + yres - 1, x, x + xres - 1); + DISP_CMD_OUT(DISP_CMD_RAMWR); +} + +static void epsonQcif_disp_set_display_area(word start_row, word end_row) +{ + if (!disp_initialized) + return; + + if ((start_row == disp_area_start_row) + && (end_row == disp_area_end_row)) + return; + disp_area_start_row = start_row; + disp_area_end_row = end_row; + + /* Range checking + */ + if (end_row >= QCIF_HEIGHT) + end_row = QCIF_HEIGHT - 1; + if (start_row > end_row) + start_row = end_row; + + /* When display is not the full screen, gray scale is set to + ** 2; otherwise it is set to 64. + */ + if ((start_row == 0) && (end_row == (QCIF_HEIGHT - 1))) { + /* The whole screen */ + DISP_CMD_OUT(DISP_CMD_PTLOUT); + WAIT_SEC(10000); + DISP_CMD_OUT(DISP_CMD_DISOFF); + WAIT_SEC(100000); + DISP_CMD_OUT(DISP_CMD_GSSET); + DISP_DATA_OUT(DISP_GS_64); + WAIT_SEC(100000); + DISP_CMD_OUT(DISP_CMD_DISON); + } else { + /* partial screen */ + DISP_CMD_OUT(DISP_CMD_PTLIN); + DISP_DATA_OUT(start_row); + DISP_DATA_OUT(start_row >> 8); + DISP_DATA_OUT(end_row); + DISP_DATA_OUT(end_row >> 8); + DISP_CMD_OUT(DISP_CMD_GSSET); + DISP_DATA_OUT(DISP_GS_2); + } +} + +static int epsonQcif_disp_off(struct platform_device *pdev) +{ + if (!disp_initialized) + epsonQcif_disp_init(pdev); + + if (display_on) { + DISP_CMD_OUT(DISP_CMD_DISOFF); + DISP_CMD_OUT(DISP_CMD_SLPIN); + display_on = FALSE; + } + + return 0; +} + +static int epsonQcif_disp_on(struct platform_device *pdev) +{ + if (!disp_initialized) + epsonQcif_disp_init(pdev); + + if (!display_on) { + DISP_CMD_OUT(DISP_CMD_SLPOUT); + WAIT_SEC(40000); + DISP_CMD_OUT(DISP_CMD_DISON); + epsonQcif_disp_set_contrast(disp_contrast); + display_on = TRUE; + } + + return 0; +} + +static void epsonQcif_disp_set_contrast(word contrast) +{ + if (!disp_initialized) + return; + + /* Initialize power IC, d'24 */ + DISP_CMD_OUT(DISP_CMD_VOLCTL); + DISP_DATA_OUT(DISP_VOLCTL_TONE); + + WAIT_SEC(40000); + + /* Set electronic volume, d'xx */ + DISP_CMD_OUT(DISP_CMD_VOLCTL); + if (contrast > 127) + contrast = 127; + DISP_DATA_OUT(contrast); /* value from 0 to 127 */ + disp_contrast = (byte) contrast; +} /* End disp_set_contrast */ + +static void epsonQcif_disp_clear_screen_area( + word start_row, word end_row, word start_column, word end_column) { + int32 i; + + /* Clear the display screen */ + DISP_SET_RECT(start_row, end_row, start_column, end_column); + DISP_CMD_OUT(DISP_CMD_RAMWR); + i = (end_row - start_row + 1) * (end_column - start_column + 1); + for (; i > 0; i--) + DISP_DATA_OUT(0xffff); +} + +static int __init epsonQcif_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = epsonQcif_probe, + .driver = { + .name = "ebi2_epson_qcif", + }, +}; + +static struct msm_fb_panel_data epsonQcif_panel_data = { + .on = epsonQcif_disp_on, + .off = epsonQcif_disp_off, + .set_rect = epsonQcif_disp_set_rect, +}; + +static struct platform_device this_device = { + .name = "ebi2_epson_qcif", + .id = 0, + .dev = { + .platform_data = &epsonQcif_panel_data, + } +}; + +static int __init epsonQcif_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &epsonQcif_panel_data.panel_info; + pinfo->xres = QCIF_WIDTH; + pinfo->yres = QCIF_HEIGHT; + pinfo->type = EBI2_PANEL; + pinfo->pdest = DISPLAY_2; + pinfo->wait_cycle = 0x808000; + pinfo->bpp = 16; + pinfo->fb_num = 2; + pinfo->lcd.vsync_enable = FALSE; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(epsonQcif_init); diff --git a/drivers/staging/msm/ebi2_lcd.c b/drivers/staging/msm/ebi2_lcd.c new file mode 100644 index 000000000000..b41e1230ceca --- /dev/null +++ b/drivers/staging/msm/ebi2_lcd.c @@ -0,0 +1,250 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/uaccess.h> +#include <linux/workqueue.h> +#include <linux/string.h> +#include <linux/version.h> +#include <linux/proc_fs.h> +#include <linux/vmalloc.h> +#include <linux/debugfs.h> + +#include "msm_fb.h" + +static int ebi2_lcd_probe(struct platform_device *pdev); +static int ebi2_lcd_remove(struct platform_device *pdev); + +static struct platform_driver ebi2_lcd_driver = { + .probe = ebi2_lcd_probe, + .remove = ebi2_lcd_remove, + .suspend = NULL, + .suspend_late = NULL, + .resume_early = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "ebi2_lcd", + }, +}; + +static void *ebi2_base; +static void *ebi2_lcd_cfg0; +static void *ebi2_lcd_cfg1; +static void __iomem *lcd01_base; +static void __iomem *lcd02_base; +static int ebi2_lcd_resource_initialized; + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +static int ebi2_lcd_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc, i; + + if (pdev->id == 0) { + for (i = 0; i < pdev->num_resources; i++) { + if (!strncmp(pdev->resource[i].name, "base", 4)) { + ebi2_base = ioremap(pdev->resource[i].start, + pdev->resource[i].end - + pdev->resource[i].start + 1); + if (!ebi2_base) { + printk(KERN_ERR + "ebi2_base ioremap failed!\n"); + return -ENOMEM; + } + ebi2_lcd_cfg0 = (void *)(ebi2_base + 0x20); + ebi2_lcd_cfg1 = (void *)(ebi2_base + 0x24); + } else if (!strncmp(pdev->resource[i].name, + "lcd01", 5)) { + lcd01_base = ioremap(pdev->resource[i].start, + pdev->resource[i].end - + pdev->resource[i].start + 1); + if (!lcd01_base) { + printk(KERN_ERR + "lcd01_base ioremap failed!\n"); + return -ENOMEM; + } + } else if (!strncmp(pdev->resource[i].name, + "lcd02", 5)) { + lcd02_base = ioremap(pdev->resource[i].start, + pdev->resource[i].end - + pdev->resource[i].start + 1); + if (!lcd02_base) { + printk(KERN_ERR + "lcd02_base ioremap failed!\n"); + return -ENOMEM; + } + } + } + ebi2_lcd_resource_initialized = 1; + return 0; + } + + if (!ebi2_lcd_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + if (ebi2_base == NULL) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* link to the latest pdev */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_LCD; + + /* add panel data */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "ebi2_lcd_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + + /* data chain */ + pdata = mdp_dev->dev.platform_data; + pdata->on = panel_next_on; + pdata->off = panel_next_off; + pdata->next = pdev; + + /* get/set panel specific fb info */ + mfd->panel_info = pdata->panel_info; + + if (mfd->panel_info.bpp == 24) + mfd->fb_imgType = MDP_RGB_888; + else + mfd->fb_imgType = MDP_RGB_565; + + /* config msm ebi2 lcd register */ + if (mfd->panel_info.pdest == DISPLAY_1) { + outp32(ebi2_base, + (inp32(ebi2_base) & (~(EBI2_PRIM_LCD_CLR))) | + EBI2_PRIM_LCD_SEL); + /* + * current design has one set of cfg0/1 register to control + * both EBI2 channels. so, we're using the PRIM channel to + * configure both. + */ + outp32(ebi2_lcd_cfg0, mfd->panel_info.wait_cycle); + if (mfd->panel_info.bpp == 18) + outp32(ebi2_lcd_cfg1, 0x01000000); + else + outp32(ebi2_lcd_cfg1, 0x0); + } else { +#ifdef DEBUG_EBI2_LCD + /* + * confliting with QCOM SURF FPGA CS. + * OEM should enable below for their CS mapping + */ + outp32(ebi2_base, (inp32(ebi2_base)&(~(EBI2_SECD_LCD_CLR))) + |EBI2_SECD_LCD_SEL); +#endif + } + + /* + * map cs (chip select) address + */ + if (mfd->panel_info.pdest == DISPLAY_1) { + mfd->cmd_port = lcd01_base; + mfd->data_port = + (void *)((uint32) mfd->cmd_port + EBI2_PRIM_LCD_RS_PIN); + mfd->data_port_phys = + (void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN); + } else { + mfd->cmd_port = lcd01_base; + mfd->data_port = + (void *)((uint32) mfd->cmd_port + EBI2_SECD_LCD_RS_PIN); + mfd->data_port_phys = + (void *)(LCD_SECD_BASE_PHYS + EBI2_SECD_LCD_RS_PIN); + } + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) { + goto ebi2_lcd_probe_err; + } + + pdev_list[pdev_list_cnt++] = pdev; + return 0; + + ebi2_lcd_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int ebi2_lcd_remove(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return 0; + + if (mfd->key != MFD_KEY) + return 0; + + iounmap(mfd->cmd_port); + + return 0; +} + +static int ebi2_lcd_register_driver(void) +{ + return platform_driver_register(&ebi2_lcd_driver); +} + +static int __init ebi2_lcd_driver_init(void) +{ + return ebi2_lcd_register_driver(); +} + +module_init(ebi2_lcd_driver_init); \ No newline at end of file diff --git a/drivers/staging/msm/ebi2_tmd20.c b/drivers/staging/msm/ebi2_tmd20.c new file mode 100644 index 000000000000..d66d03978253 --- /dev/null +++ b/drivers/staging/msm/ebi2_tmd20.c @@ -0,0 +1,1122 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" + +#include <linux/memory.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include "linux/proc_fs.h" + +#include <linux/delay.h> + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> + +/* #define TMD20QVGA_LCD_18BPP */ +#define QVGA_WIDTH 240 +#define QVGA_HEIGHT 320 + +#ifdef TMD20QVGA_LCD_18BPP +#define DISP_QVGA_18BPP(x) ((((x)<<2) & 0x3FC00)|(( (x)<<1)& 0x1FE)) +#define DISP_REG(name) uint32 register_##name; +#define OUTPORT(x, y) outpdw(x, y) +#define INPORT(x) inpdw(x) +#else +#define DISP_QVGA_18BPP(x) (x) +#define DISP_REG(name) uint16 register_##name; +#define OUTPORT(x, y) outpw(x, y) +#define INPORT(x) intpw(x) +#endif + +static void *DISP_CMD_PORT; +static void *DISP_DATA_PORT; + +#define DISP_RNTI 0x10 + +#define DISP_CMD_OUT(cmd) OUTPORT(DISP_CMD_PORT, DISP_QVGA_18BPP(cmd)) +#define DISP_DATA_OUT(data) OUTPORT(DISP_DATA_PORT, data) +#define DISP_DATA_IN() INPORT(DISP_DATA_PORT) + +#if (defined(TMD20QVGA_LCD_18BPP)) +#define DISP_DATA_OUT_16TO18BPP(x) \ + DISP_DATA_OUT((((x)&0xf800)<<2|((x)&0x80000)>>3) \ + | (((x)&0x7e0)<<1) \ + | (((x)&0x1F)<<1|((x)&0x10)>>4)) +#else +#define DISP_DATA_OUT_16TO18BPP(x) \ + DISP_DATA_OUT(x) +#endif + +#define DISP_WRITE_OUT(addr, data) \ + register_##addr = DISP_QVGA_18BPP(data); \ + DISP_CMD_OUT(addr); \ + DISP_DATA_OUT(register_##addr); + +#define DISP_UPDATE_VALUE(addr, bitmask, data) \ + DISP_WRITE_OUT(##addr, (register_##addr & ~(bitmask)) | (data)); + +#define DISP_VAL_IF(bitvalue, bitmask) \ + ((bitvalue) ? (bitmask) : 0) + +/* QVGA = 256 x 320 */ +/* actual display is 240 x 320...offset by 0x10 */ +#define DISP_ROW_COL_TO_ADDR(row, col) ((row) * 0x100 + col) +#define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \ + { \ + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_1_ADDR, (ulhc_col) + tmd20qvga_panel_offset); \ + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_2_ADDR, (lrhc_col) + tmd20qvga_panel_offset); \ + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_1_ADDR, (ulhc_row)); \ + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_2_ADDR, (lrhc_row)); \ + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_1_ADDR, (ulhc_col) + tmd20qvga_panel_offset); \ + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_2_ADDR, (ulhc_row)); \ + } + +#define WAIT_MSEC(msec) mdelay(msec) + +/* + * TMD QVGA Address + */ +/* Display Control */ +#define DISP_START_OSCILLATION_ADDR 0x000 +DISP_REG(DISP_START_OSCILLATION_ADDR) +#define DISP_DRIVER_OUTPUT_CTL_ADDR 0x001 + DISP_REG(DISP_DRIVER_OUTPUT_CTL_ADDR) +#define DISP_LCD_DRIVING_SIG_ADDR 0x002 + DISP_REG(DISP_LCD_DRIVING_SIG_ADDR) +#define DISP_ENTRY_MODE_ADDR 0x003 + DISP_REG(DISP_ENTRY_MODE_ADDR) +#define DISP_DISPLAY_CTL_1_ADDR 0x007 + DISP_REG(DISP_DISPLAY_CTL_1_ADDR) +#define DISP_DISPLAY_CTL_2_ADDR 0x008 + DISP_REG(DISP_DISPLAY_CTL_2_ADDR) + +/* DISPLAY MODE 0x009 partial display not supported */ +#define DISP_POWER_SUPPLY_INTF_ADDR 0x00A + DISP_REG(DISP_POWER_SUPPLY_INTF_ADDR) + +/* DISPLAY MODE 0x00B xZoom feature is not supported */ +#define DISP_EXT_DISPLAY_CTL_1_ADDR 0x00C + DISP_REG(DISP_EXT_DISPLAY_CTL_1_ADDR) + +#define DISP_FRAME_CYCLE_CTL_ADDR 0x00D + DISP_REG(DISP_FRAME_CYCLE_CTL_ADDR) + +#define DISP_EXT_DISPLAY_CTL_2_ADDR 0x00E + DISP_REG(DISP_EXT_DISPLAY_CTL_2_ADDR) + +#define DISP_EXT_DISPLAY_CTL_3_ADDR 0x00F + DISP_REG(DISP_EXT_DISPLAY_CTL_3_ADDR) + +#define DISP_LTPS_CTL_1_ADDR 0x012 + DISP_REG(DISP_LTPS_CTL_1_ADDR) +#define DISP_LTPS_CTL_2_ADDR 0x013 + DISP_REG(DISP_LTPS_CTL_2_ADDR) +#define DISP_LTPS_CTL_3_ADDR 0x014 + DISP_REG(DISP_LTPS_CTL_3_ADDR) +#define DISP_LTPS_CTL_4_ADDR 0x018 + DISP_REG(DISP_LTPS_CTL_4_ADDR) +#define DISP_LTPS_CTL_5_ADDR 0x019 + DISP_REG(DISP_LTPS_CTL_5_ADDR) +#define DISP_LTPS_CTL_6_ADDR 0x01A + DISP_REG(DISP_LTPS_CTL_6_ADDR) +#define DISP_AMP_SETTING_ADDR 0x01C + DISP_REG(DISP_AMP_SETTING_ADDR) +#define DISP_MODE_SETTING_ADDR 0x01D + DISP_REG(DISP_MODE_SETTING_ADDR) +#define DISP_POFF_LN_SETTING_ADDR 0x01E + DISP_REG(DISP_POFF_LN_SETTING_ADDR) +/* Power Contol */ +#define DISP_POWER_CTL_1_ADDR 0x100 + DISP_REG(DISP_POWER_CTL_1_ADDR) +#define DISP_POWER_CTL_2_ADDR 0x101 + DISP_REG(DISP_POWER_CTL_2_ADDR) +#define DISP_POWER_CTL_3_ADDR 0x102 + DISP_REG(DISP_POWER_CTL_3_ADDR) +#define DISP_POWER_CTL_4_ADDR 0x103 + DISP_REG(DISP_POWER_CTL_4_ADDR) +#define DISP_POWER_CTL_5_ADDR 0x104 + DISP_REG(DISP_POWER_CTL_5_ADDR) +#define DISP_POWER_CTL_6_ADDR 0x105 + DISP_REG(DISP_POWER_CTL_6_ADDR) +#define DISP_POWER_CTL_7_ADDR 0x106 + DISP_REG(DISP_POWER_CTL_7_ADDR) +/* RAM Access */ +#define DISP_RAM_ADDR_SET_1_ADDR 0x200 + DISP_REG(DISP_RAM_ADDR_SET_1_ADDR) +#define DISP_RAM_ADDR_SET_2_ADDR 0x201 + DISP_REG(DISP_RAM_ADDR_SET_2_ADDR) +#define DISP_CMD_RAMRD DISP_CMD_RAMWR +#define DISP_CMD_RAMWR 0x202 + DISP_REG(DISP_CMD_RAMWR) +#define DISP_RAM_DATA_MASK_1_ADDR 0x203 + DISP_REG(DISP_RAM_DATA_MASK_1_ADDR) +#define DISP_RAM_DATA_MASK_2_ADDR 0x204 + DISP_REG(DISP_RAM_DATA_MASK_2_ADDR) +/* Gamma Control, Contrast, Gray Scale Setting */ +#define DISP_GAMMA_CONTROL_1_ADDR 0x300 + DISP_REG(DISP_GAMMA_CONTROL_1_ADDR) +#define DISP_GAMMA_CONTROL_2_ADDR 0x301 + DISP_REG(DISP_GAMMA_CONTROL_2_ADDR) +#define DISP_GAMMA_CONTROL_3_ADDR 0x302 + DISP_REG(DISP_GAMMA_CONTROL_3_ADDR) +#define DISP_GAMMA_CONTROL_4_ADDR 0x303 + DISP_REG(DISP_GAMMA_CONTROL_4_ADDR) +#define DISP_GAMMA_CONTROL_5_ADDR 0x304 + DISP_REG(DISP_GAMMA_CONTROL_5_ADDR) +/* Coordinate Control */ +#define DISP_VERT_SCROLL_CTL_1_ADDR 0x400 + DISP_REG(DISP_VERT_SCROLL_CTL_1_ADDR) +#define DISP_VERT_SCROLL_CTL_2_ADDR 0x401 + DISP_REG(DISP_VERT_SCROLL_CTL_2_ADDR) +#define DISP_SCREEN_1_DRV_POS_1_ADDR 0x402 + DISP_REG(DISP_SCREEN_1_DRV_POS_1_ADDR) +#define DISP_SCREEN_1_DRV_POS_2_ADDR 0x403 + DISP_REG(DISP_SCREEN_1_DRV_POS_2_ADDR) +#define DISP_SCREEN_2_DRV_POS_1_ADDR 0x404 + DISP_REG(DISP_SCREEN_2_DRV_POS_1_ADDR) +#define DISP_SCREEN_2_DRV_POS_2_ADDR 0x405 + DISP_REG(DISP_SCREEN_2_DRV_POS_2_ADDR) +#define DISP_HORZ_RAM_ADDR_POS_1_ADDR 0x406 + DISP_REG(DISP_HORZ_RAM_ADDR_POS_1_ADDR) +#define DISP_HORZ_RAM_ADDR_POS_2_ADDR 0x407 + DISP_REG(DISP_HORZ_RAM_ADDR_POS_2_ADDR) +#define DISP_VERT_RAM_ADDR_POS_1_ADDR 0x408 + DISP_REG(DISP_VERT_RAM_ADDR_POS_1_ADDR) +#define DISP_VERT_RAM_ADDR_POS_2_ADDR 0x409 + DISP_REG(DISP_VERT_RAM_ADDR_POS_2_ADDR) +#define DISP_TMD_700_ADDR 0x700 /* 0x700 */ + DISP_REG(DISP_TMD_700_ADDR) +#define DISP_TMD_015_ADDR 0x015 /* 0x700 */ + DISP_REG(DISP_TMD_015_ADDR) +#define DISP_TMD_305_ADDR 0x305 /* 0x700 */ + DISP_REG(DISP_TMD_305_ADDR) + +/* + * TMD QVGA Bit Definations + */ + +#define DISP_BIT_IB15 0x8000 +#define DISP_BIT_IB14 0x4000 +#define DISP_BIT_IB13 0x2000 +#define DISP_BIT_IB12 0x1000 +#define DISP_BIT_IB11 0x0800 +#define DISP_BIT_IB10 0x0400 +#define DISP_BIT_IB09 0x0200 +#define DISP_BIT_IB08 0x0100 +#define DISP_BIT_IB07 0x0080 +#define DISP_BIT_IB06 0x0040 +#define DISP_BIT_IB05 0x0020 +#define DISP_BIT_IB04 0x0010 +#define DISP_BIT_IB03 0x0008 +#define DISP_BIT_IB02 0x0004 +#define DISP_BIT_IB01 0x0002 +#define DISP_BIT_IB00 0x0001 +/* + * Display Control + * DISP_START_OSCILLATION_ADDR Start Oscillation + * DISP_DRIVER_OUTPUT_CTL_ADDR Driver Output Control + */ +#define DISP_BITMASK_SS DISP_BIT_IB08 +#define DISP_BITMASK_NL5 DISP_BIT_IB05 +#define DISP_BITMASK_NL4 DISP_BIT_IB04 +#define DISP_BITMASK_NL3 DISP_BIT_IB03 +#define DISP_BITMASK_NL2 DISP_BIT_IB02 +#define DISP_BITMASK_NL1 DISP_BIT_IB01 +#define DISP_BITMASK_NL0 DISP_BIT_IB00 +/* DISP_LCD_DRIVING_SIG_ADDR LCD Driving Signal Setting */ +#define DISP_BITMASK_BC DISP_BIT_IB09 +/* DISP_ENTRY_MODE_ADDR Entry Mode */ +#define DISP_BITMASK_TRI DISP_BIT_IB15 +#define DISP_BITMASK_DFM1 DISP_BIT_IB14 +#define DISP_BITMASK_DFM0 DISP_BIT_IB13 +#define DISP_BITMASK_BGR DISP_BIT_IB12 +#define DISP_BITMASK_HWM0 DISP_BIT_IB08 +#define DISP_BITMASK_ID1 DISP_BIT_IB05 +#define DISP_BITMASK_ID0 DISP_BIT_IB04 +#define DISP_BITMASK_AM DISP_BIT_IB03 +/* DISP_DISPLAY_CTL_1_ADDR Display Control (1) */ +#define DISP_BITMASK_COL1 DISP_BIT_IB15 +#define DISP_BITMASK_COL0 DISP_BIT_IB14 +#define DISP_BITMASK_VLE2 DISP_BIT_IB10 +#define DISP_BITMASK_VLE1 DISP_BIT_IB09 +#define DISP_BITMASK_SPT DISP_BIT_IB08 +#define DISP_BITMASK_PT1 DISP_BIT_IB07 +#define DISP_BITMASK_PT0 DISP_BIT_IB06 +#define DISP_BITMASK_REV DISP_BIT_IB02 +/* DISP_DISPLAY_CTL_2_ADDR Display Control (2) */ +#define DISP_BITMASK_FP3 DISP_BIT_IB11 +#define DISP_BITMASK_FP2 DISP_BIT_IB10 +#define DISP_BITMASK_FP1 DISP_BIT_IB09 +#define DISP_BITMASK_FP0 DISP_BIT_IB08 +#define DISP_BITMASK_BP3 DISP_BIT_IB03 +#define DISP_BITMASK_BP2 DISP_BIT_IB02 +#define DISP_BITMASK_BP1 DISP_BIT_IB01 +#define DISP_BITMASK_BP0 DISP_BIT_IB00 +/* DISP_POWER_SUPPLY_INTF_ADDR Power Supply IC Interface Control */ +#define DISP_BITMASK_CSE DISP_BIT_IB12 +#define DISP_BITMASK_TE DISP_BIT_IB08 +#define DISP_BITMASK_IX3 DISP_BIT_IB03 +#define DISP_BITMASK_IX2 DISP_BIT_IB02 +#define DISP_BITMASK_IX1 DISP_BIT_IB01 +#define DISP_BITMASK_IX0 DISP_BIT_IB00 +/* DISP_EXT_DISPLAY_CTL_1_ADDR External Display Interface Control (1) */ +#define DISP_BITMASK_RM DISP_BIT_IB08 +#define DISP_BITMASK_DM1 DISP_BIT_IB05 +#define DISP_BITMASK_DM0 DISP_BIT_IB04 +#define DISP_BITMASK_RIM1 DISP_BIT_IB01 +#define DISP_BITMASK_RIM0 DISP_BIT_IB00 +/* DISP_FRAME_CYCLE_CTL_ADDR Frame Frequency Adjustment Control */ +#define DISP_BITMASK_DIVI1 DISP_BIT_IB09 +#define DISP_BITMASK_DIVI0 DISP_BIT_IB08 +#define DISP_BITMASK_RTNI4 DISP_BIT_IB04 +#define DISP_BITMASK_RTNI3 DISP_BIT_IB03 +#define DISP_BITMASK_RTNI2 DISP_BIT_IB02 +#define DISP_BITMASK_RTNI1 DISP_BIT_IB01 +#define DISP_BITMASK_RTNI0 DISP_BIT_IB00 +/* DISP_EXT_DISPLAY_CTL_2_ADDR External Display Interface Control (2) */ +#define DISP_BITMASK_DIVE1 DISP_BIT_IB09 +#define DISP_BITMASK_DIVE0 DISP_BIT_IB08 +#define DISP_BITMASK_RTNE7 DISP_BIT_IB07 +#define DISP_BITMASK_RTNE6 DISP_BIT_IB06 +#define DISP_BITMASK_RTNE5 DISP_BIT_IB05 +#define DISP_BITMASK_RTNE4 DISP_BIT_IB04 +#define DISP_BITMASK_RTNE3 DISP_BIT_IB03 +#define DISP_BITMASK_RTNE2 DISP_BIT_IB02 +#define DISP_BITMASK_RTNE1 DISP_BIT_IB01 +#define DISP_BITMASK_RTNE0 DISP_BIT_IB00 +/* DISP_EXT_DISPLAY_CTL_3_ADDR External Display Interface Control (3) */ +#define DISP_BITMASK_VSPL DISP_BIT_IB04 +#define DISP_BITMASK_HSPL DISP_BIT_IB03 +#define DISP_BITMASK_VPL DISP_BIT_IB02 +#define DISP_BITMASK_EPL DISP_BIT_IB01 +#define DISP_BITMASK_DPL DISP_BIT_IB00 +/* DISP_LTPS_CTL_1_ADDR LTPS Interface Control (1) */ +#define DISP_BITMASK_CLWI3 DISP_BIT_IB11 +#define DISP_BITMASK_CLWI2 DISP_BIT_IB10 +#define DISP_BITMASK_CLWI1 DISP_BIT_IB09 +#define DISP_BITMASK_CLWI0 DISP_BIT_IB08 +#define DISP_BITMASK_CLTI1 DISP_BIT_IB01 +#define DISP_BITMASK_CLTI0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_2_ADDR LTPS Interface Control (2) */ +#define DISP_BITMASK_OEVBI1 DISP_BIT_IB09 +#define DISP_BITMASK_OEVBI0 DISP_BIT_IB08 +#define DISP_BITMASK_OEVFI1 DISP_BIT_IB01 +#define DISP_BITMASK_OEVFI0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_3_ADDR LTPS Interface Control (3) */ +#define DISP_BITMASK_SHI1 DISP_BIT_IB01 +#define DISP_BITMASK_SHI0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_4_ADDR LTPS Interface Control (4) */ +#define DISP_BITMASK_CLWE5 DISP_BIT_IB13 +#define DISP_BITMASK_CLWE4 DISP_BIT_IB12 +#define DISP_BITMASK_CLWE3 DISP_BIT_IB11 +#define DISP_BITMASK_CLWE2 DISP_BIT_IB10 +#define DISP_BITMASK_CLWE1 DISP_BIT_IB09 +#define DISP_BITMASK_CLWE0 DISP_BIT_IB08 +#define DISP_BITMASK_CLTE3 DISP_BIT_IB03 +#define DISP_BITMASK_CLTE2 DISP_BIT_IB02 +#define DISP_BITMASK_CLTE1 DISP_BIT_IB01 +#define DISP_BITMASK_CLTE0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_5_ADDR LTPS Interface Control (5) */ +#define DISP_BITMASK_OEVBE3 DISP_BIT_IB11 +#define DISP_BITMASK_OEVBE2 DISP_BIT_IB10 +#define DISP_BITMASK_OEVBE1 DISP_BIT_IB09 +#define DISP_BITMASK_OEVBE0 DISP_BIT_IB08 +#define DISP_BITMASK_OEVFE3 DISP_BIT_IB03 +#define DISP_BITMASK_OEVFE2 DISP_BIT_IB02 +#define DISP_BITMASK_OEVFE1 DISP_BIT_IB01 +#define DISP_BITMASK_OEVFE0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_6_ADDR LTPS Interface Control (6) */ +#define DISP_BITMASK_SHE3 DISP_BIT_IB03 +#define DISP_BITMASK_SHE2 DISP_BIT_IB02 +#define DISP_BITMASK_SHE1 DISP_BIT_IB01 +#define DISP_BITMASK_SHE0 DISP_BIT_IB00 +/* DISP_AMP_SETTING_ADDR Amplify Setting */ +#define DISP_BITMASK_ABSW1 DISP_BIT_IB01 +#define DISP_BITMASK_ABSW0 DISP_BIT_IB00 +/* DISP_MODE_SETTING_ADDR Mode Setting */ +#define DISP_BITMASK_DSTB DISP_BIT_IB02 +#define DISP_BITMASK_STB DISP_BIT_IB00 +/* DISP_POFF_LN_SETTING_ADDR Power Off Line Setting */ +#define DISP_BITMASK_POFH3 DISP_BIT_IB03 +#define DISP_BITMASK_POFH2 DISP_BIT_IB02 +#define DISP_BITMASK_POFH1 DISP_BIT_IB01 +#define DISP_BITMASK_POFH0 DISP_BIT_IB00 + +/* Power Contol */ +/* DISP_POWER_CTL_1_ADDR Power Control (1) */ +#define DISP_BITMASK_PO DISP_BIT_IB11 +#define DISP_BITMASK_VCD DISP_BIT_IB09 +#define DISP_BITMASK_VSC DISP_BIT_IB08 +#define DISP_BITMASK_CON DISP_BIT_IB07 +#define DISP_BITMASK_ASW1 DISP_BIT_IB06 +#define DISP_BITMASK_ASW0 DISP_BIT_IB05 +#define DISP_BITMASK_OEV DISP_BIT_IB04 +#define DISP_BITMASK_OEVE DISP_BIT_IB03 +#define DISP_BITMASK_FR DISP_BIT_IB02 +#define DISP_BITMASK_D1 DISP_BIT_IB01 +#define DISP_BITMASK_D0 DISP_BIT_IB00 +/* DISP_POWER_CTL_2_ADDR Power Control (2) */ +#define DISP_BITMASK_DC4 DISP_BIT_IB15 +#define DISP_BITMASK_DC3 DISP_BIT_IB14 +#define DISP_BITMASK_SAP2 DISP_BIT_IB13 +#define DISP_BITMASK_SAP1 DISP_BIT_IB12 +#define DISP_BITMASK_SAP0 DISP_BIT_IB11 +#define DISP_BITMASK_BT2 DISP_BIT_IB10 +#define DISP_BITMASK_BT1 DISP_BIT_IB09 +#define DISP_BITMASK_BT0 DISP_BIT_IB08 +#define DISP_BITMASK_DC2 DISP_BIT_IB07 +#define DISP_BITMASK_DC1 DISP_BIT_IB06 +#define DISP_BITMASK_DC0 DISP_BIT_IB05 +#define DISP_BITMASK_AP2 DISP_BIT_IB04 +#define DISP_BITMASK_AP1 DISP_BIT_IB03 +#define DISP_BITMASK_AP0 DISP_BIT_IB02 +/* DISP_POWER_CTL_3_ADDR Power Control (3) */ +#define DISP_BITMASK_VGL4 DISP_BIT_IB10 +#define DISP_BITMASK_VGL3 DISP_BIT_IB09 +#define DISP_BITMASK_VGL2 DISP_BIT_IB08 +#define DISP_BITMASK_VGL1 DISP_BIT_IB07 +#define DISP_BITMASK_VGL0 DISP_BIT_IB06 +#define DISP_BITMASK_VGH4 DISP_BIT_IB04 +#define DISP_BITMASK_VGH3 DISP_BIT_IB03 +#define DISP_BITMASK_VGH2 DISP_BIT_IB02 +#define DISP_BITMASK_VGH1 DISP_BIT_IB01 +#define DISP_BITMASK_VGH0 DISP_BIT_IB00 +/* DISP_POWER_CTL_4_ADDR Power Control (4) */ +#define DISP_BITMASK_VC2 DISP_BIT_IB02 +#define DISP_BITMASK_VC1 DISP_BIT_IB01 +#define DISP_BITMASK_VC0 DISP_BIT_IB00 +/* DISP_POWER_CTL_5_ADDR Power Control (5) */ +#define DISP_BITMASK_VRL3 DISP_BIT_IB11 +#define DISP_BITMASK_VRL2 DISP_BIT_IB10 +#define DISP_BITMASK_VRL1 DISP_BIT_IB09 +#define DISP_BITMASK_VRL0 DISP_BIT_IB08 +#define DISP_BITMASK_PON DISP_BIT_IB04 +#define DISP_BITMASK_VRH3 DISP_BIT_IB03 +#define DISP_BITMASK_VRH2 DISP_BIT_IB02 +#define DISP_BITMASK_VRH1 DISP_BIT_IB01 +#define DISP_BITMASK_VRH0 DISP_BIT_IB00 +/* DISP_POWER_CTL_6_ADDR Power Control (6) */ +#define DISP_BITMASK_VCOMG DISP_BIT_IB13 +#define DISP_BITMASK_VDV4 DISP_BIT_IB12 +#define DISP_BITMASK_VDV3 DISP_BIT_IB11 +#define DISP_BITMASK_VDV2 DISP_BIT_IB10 +#define DISP_BITMASK_VDV1 DISP_BIT_IB09 +#define DISP_BITMASK_VDV0 DISP_BIT_IB08 +#define DISP_BITMASK_VCM4 DISP_BIT_IB04 +#define DISP_BITMASK_VCM3 DISP_BIT_IB03 +#define DISP_BITMASK_VCM2 DISP_BIT_IB02 +#define DISP_BITMASK_VCM1 DISP_BIT_IB01 +#define DISP_BITMASK_VCM0 DISP_BIT_IB00 +/* RAM Access */ +/* DISP_RAM_ADDR_SET_1_ADDR RAM Address Set (1) */ +#define DISP_BITMASK_AD7 DISP_BIT_IB07 +#define DISP_BITMASK_AD6 DISP_BIT_IB06 +#define DISP_BITMASK_AD5 DISP_BIT_IB05 +#define DISP_BITMASK_AD4 DISP_BIT_IB04 +#define DISP_BITMASK_AD3 DISP_BIT_IB03 +#define DISP_BITMASK_AD2 DISP_BIT_IB02 +#define DISP_BITMASK_AD1 DISP_BIT_IB01 +#define DISP_BITMASK_AD0 DISP_BIT_IB00 +/* DISP_RAM_ADDR_SET_2_ADDR RAM Address Set (2) */ +#define DISP_BITMASK_AD16 DISP_BIT_IB08 +#define DISP_BITMASK_AD15 DISP_BIT_IB07 +#define DISP_BITMASK_AD14 DISP_BIT_IB06 +#define DISP_BITMASK_AD13 DISP_BIT_IB05 +#define DISP_BITMASK_AD12 DISP_BIT_IB04 +#define DISP_BITMASK_AD11 DISP_BIT_IB03 +#define DISP_BITMASK_AD10 DISP_BIT_IB02 +#define DISP_BITMASK_AD9 DISP_BIT_IB01 +#define DISP_BITMASK_AD8 DISP_BIT_IB00 +/* + * DISP_CMD_RAMWR RAM Data Read/Write + * Use Data Bit Configuration + */ +/* DISP_RAM_DATA_MASK_1_ADDR RAM Write Data Mask (1) */ +#define DISP_BITMASK_WM11 DISP_BIT_IB13 +#define DISP_BITMASK_WM10 DISP_BIT_IB12 +#define DISP_BITMASK_WM9 DISP_BIT_IB11 +#define DISP_BITMASK_WM8 DISP_BIT_IB10 +#define DISP_BITMASK_WM7 DISP_BIT_IB09 +#define DISP_BITMASK_WM6 DISP_BIT_IB08 +#define DISP_BITMASK_WM5 DISP_BIT_IB05 +#define DISP_BITMASK_WM4 DISP_BIT_IB04 +#define DISP_BITMASK_WM3 DISP_BIT_IB03 +#define DISP_BITMASK_WM2 DISP_BIT_IB02 +#define DISP_BITMASK_WM1 DISP_BIT_IB01 +#define DISP_BITMASK_WM0 DISP_BIT_IB00 +/* DISP_RAM_DATA_MASK_2_ADDR RAM Write Data Mask (2) */ +#define DISP_BITMASK_WM17 DISP_BIT_IB05 +#define DISP_BITMASK_WM16 DISP_BIT_IB04 +#define DISP_BITMASK_WM15 DISP_BIT_IB03 +#define DISP_BITMASK_WM14 DISP_BIT_IB02 +#define DISP_BITMASK_WM13 DISP_BIT_IB01 +#define DISP_BITMASK_WM12 DISP_BIT_IB00 +/*Gamma Control */ +/* DISP_GAMMA_CONTROL_1_ADDR Gamma Control (1) */ +#define DISP_BITMASK_PKP12 DISP_BIT_IB10 +#define DISP_BITMASK_PKP11 DISP_BIT_IB08 +#define DISP_BITMASK_PKP10 DISP_BIT_IB09 +#define DISP_BITMASK_PKP02 DISP_BIT_IB02 +#define DISP_BITMASK_PKP01 DISP_BIT_IB01 +#define DISP_BITMASK_PKP00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_2_ADDR Gamma Control (2) */ +#define DISP_BITMASK_PKP32 DISP_BIT_IB10 +#define DISP_BITMASK_PKP31 DISP_BIT_IB09 +#define DISP_BITMASK_PKP30 DISP_BIT_IB08 +#define DISP_BITMASK_PKP22 DISP_BIT_IB02 +#define DISP_BITMASK_PKP21 DISP_BIT_IB01 +#define DISP_BITMASK_PKP20 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_3_ADDR Gamma Control (3) */ +#define DISP_BITMASK_PKP52 DISP_BIT_IB10 +#define DISP_BITMASK_PKP51 DISP_BIT_IB09 +#define DISP_BITMASK_PKP50 DISP_BIT_IB08 +#define DISP_BITMASK_PKP42 DISP_BIT_IB02 +#define DISP_BITMASK_PKP41 DISP_BIT_IB01 +#define DISP_BITMASK_PKP40 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_4_ADDR Gamma Control (4) */ +#define DISP_BITMASK_PRP12 DISP_BIT_IB10 +#define DISP_BITMASK_PRP11 DISP_BIT_IB08 +#define DISP_BITMASK_PRP10 DISP_BIT_IB09 +#define DISP_BITMASK_PRP02 DISP_BIT_IB02 +#define DISP_BITMASK_PRP01 DISP_BIT_IB01 +#define DISP_BITMASK_PRP00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_5_ADDR Gamma Control (5) */ +#define DISP_BITMASK_VRP14 DISP_BIT_IB12 +#define DISP_BITMASK_VRP13 DISP_BIT_IB11 +#define DISP_BITMASK_VRP12 DISP_BIT_IB10 +#define DISP_BITMASK_VRP11 DISP_BIT_IB08 +#define DISP_BITMASK_VRP10 DISP_BIT_IB09 +#define DISP_BITMASK_VRP03 DISP_BIT_IB03 +#define DISP_BITMASK_VRP02 DISP_BIT_IB02 +#define DISP_BITMASK_VRP01 DISP_BIT_IB01 +#define DISP_BITMASK_VRP00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_6_ADDR Gamma Control (6) */ +#define DISP_BITMASK_PKN12 DISP_BIT_IB10 +#define DISP_BITMASK_PKN11 DISP_BIT_IB08 +#define DISP_BITMASK_PKN10 DISP_BIT_IB09 +#define DISP_BITMASK_PKN02 DISP_BIT_IB02 +#define DISP_BITMASK_PKN01 DISP_BIT_IB01 +#define DISP_BITMASK_PKN00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_7_ADDR Gamma Control (7) */ +#define DISP_BITMASK_PKN32 DISP_BIT_IB10 +#define DISP_BITMASK_PKN31 DISP_BIT_IB08 +#define DISP_BITMASK_PKN30 DISP_BIT_IB09 +#define DISP_BITMASK_PKN22 DISP_BIT_IB02 +#define DISP_BITMASK_PKN21 DISP_BIT_IB01 +#define DISP_BITMASK_PKN20 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_8_ADDR Gamma Control (8) */ +#define DISP_BITMASK_PKN52 DISP_BIT_IB10 +#define DISP_BITMASK_PKN51 DISP_BIT_IB08 +#define DISP_BITMASK_PKN50 DISP_BIT_IB09 +#define DISP_BITMASK_PKN42 DISP_BIT_IB02 +#define DISP_BITMASK_PKN41 DISP_BIT_IB01 +#define DISP_BITMASK_PKN40 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_9_ADDR Gamma Control (9) */ +#define DISP_BITMASK_PRN12 DISP_BIT_IB10 +#define DISP_BITMASK_PRN11 DISP_BIT_IB08 +#define DISP_BITMASK_PRN10 DISP_BIT_IB09 +#define DISP_BITMASK_PRN02 DISP_BIT_IB02 +#define DISP_BITMASK_PRN01 DISP_BIT_IB01 +#define DISP_BITMASK_PRN00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_10_ADDR Gamma Control (10) */ +#define DISP_BITMASK_VRN14 DISP_BIT_IB12 +#define DISP_BITMASK_VRN13 DISP_BIT_IB11 +#define DISP_BITMASK_VRN12 DISP_BIT_IB10 +#define DISP_BITMASK_VRN11 DISP_BIT_IB08 +#define DISP_BITMASK_VRN10 DISP_BIT_IB09 +#define DISP_BITMASK_VRN03 DISP_BIT_IB03 +#define DISP_BITMASK_VRN02 DISP_BIT_IB02 +#define DISP_BITMASK_VRN01 DISP_BIT_IB01 +#define DISP_BITMASK_VRN00 DISP_BIT_IB00 +/* Coordinate Control */ +/* DISP_VERT_SCROLL_CTL_1_ADDR Vertical Scroll Control (1) */ +#define DISP_BITMASK_VL18 DISP_BIT_IB08 +#define DISP_BITMASK_VL17 DISP_BIT_IB07 +#define DISP_BITMASK_VL16 DISP_BIT_IB06 +#define DISP_BITMASK_VL15 DISP_BIT_IB05 +#define DISP_BITMASK_VL14 DISP_BIT_IB04 +#define DISP_BITMASK_VL13 DISP_BIT_IB03 +#define DISP_BITMASK_VL12 DISP_BIT_IB02 +#define DISP_BITMASK_VL11 DISP_BIT_IB01 +#define DISP_BITMASK_VL10 DISP_BIT_IB00 +/* DISP_VERT_SCROLL_CTL_2_ADDR Vertical Scroll Control (2) */ +#define DISP_BITMASK_VL28 DISP_BIT_IB08 +#define DISP_BITMASK_VL27 DISP_BIT_IB07 +#define DISP_BITMASK_VL26 DISP_BIT_IB06 +#define DISP_BITMASK_VL25 DISP_BIT_IB05 +#define DISP_BITMASK_VL24 DISP_BIT_IB04 +#define DISP_BITMASK_VL23 DISP_BIT_IB03 +#define DISP_BITMASK_VL22 DISP_BIT_IB02 +#define DISP_BITMASK_VL21 DISP_BIT_IB01 +#define DISP_BITMASK_VL20 DISP_BIT_IB00 +/* DISP_SCREEN_1_DRV_POS_1_ADDR First Screen Driving Position (1) */ +#define DISP_BITMASK_SS18 DISP_BIT_IB08 +#define DISP_BITMASK_SS17 DISP_BIT_IB07 +#define DISP_BITMASK_SS16 DISP_BIT_IB06 +#define DISP_BITMASK_SS15 DISP_BIT_IB05 +#define DISP_BITMASK_SS14 DISP_BIT_IB04 +#define DISP_BITMASK_SS13 DISP_BIT_IB03 +#define DISP_BITMASK_SS12 DISP_BIT_IB02 +#define DISP_BITMASK_SS11 DISP_BIT_IB01 +#define DISP_BITMASK_SS10 DISP_BIT_IB00 +/* DISP_SCREEN_1_DRV_POS_2_ADDR First Screen Driving Position (2) */ +#define DISP_BITMASK_SE18 DISP_BIT_IB08 +#define DISP_BITMASK_SE17 DISP_BIT_IB07 +#define DISP_BITMASK_SE16 DISP_BIT_IB06 +#define DISP_BITMASK_SE15 DISP_BIT_IB05 +#define DISP_BITMASK_SE14 DISP_BIT_IB04 +#define DISP_BITMASK_SE13 DISP_BIT_IB03 +#define DISP_BITMASK_SE12 DISP_BIT_IB02 +#define DISP_BITMASK_SE11 DISP_BIT_IB01 +#define DISP_BITMASK_SE10 DISP_BIT_IB00 +/* DISP_SCREEN_2_DRV_POS_1_ADDR Second Screen Driving Position (1) */ +#define DISP_BITMASK_SS28 DISP_BIT_IB08 +#define DISP_BITMASK_SS27 DISP_BIT_IB07 +#define DISP_BITMASK_SS26 DISP_BIT_IB06 +#define DISP_BITMASK_SS25 DISP_BIT_IB05 +#define DISP_BITMASK_SS24 DISP_BIT_IB04 +#define DISP_BITMASK_SS23 DISP_BIT_IB03 +#define DISP_BITMASK_SS22 DISP_BIT_IB02 +#define DISP_BITMASK_SS21 DISP_BIT_IB01 +#define DISP_BITMASK_SS20 DISP_BIT_IB00 +/* DISP_SCREEN_3_DRV_POS_2_ADDR Second Screen Driving Position (2) */ +#define DISP_BITMASK_SE28 DISP_BIT_IB08 +#define DISP_BITMASK_SE27 DISP_BIT_IB07 +#define DISP_BITMASK_SE26 DISP_BIT_IB06 +#define DISP_BITMASK_SE25 DISP_BIT_IB05 +#define DISP_BITMASK_SE24 DISP_BIT_IB04 +#define DISP_BITMASK_SE23 DISP_BIT_IB03 +#define DISP_BITMASK_SE22 DISP_BIT_IB02 +#define DISP_BITMASK_SE21 DISP_BIT_IB01 +#define DISP_BITMASK_SE20 DISP_BIT_IB00 +/* DISP_HORZ_RAM_ADDR_POS_1_ADDR Horizontal RAM Address Position (1) */ +#define DISP_BITMASK_HSA7 DISP_BIT_IB07 +#define DISP_BITMASK_HSA6 DISP_BIT_IB06 +#define DISP_BITMASK_HSA5 DISP_BIT_IB05 +#define DISP_BITMASK_HSA4 DISP_BIT_IB04 +#define DISP_BITMASK_HSA3 DISP_BIT_IB03 +#define DISP_BITMASK_HSA2 DISP_BIT_IB02 +#define DISP_BITMASK_HSA1 DISP_BIT_IB01 +#define DISP_BITMASK_HSA0 DISP_BIT_IB00 +/* DISP_HORZ_RAM_ADDR_POS_2_ADDR Horizontal RAM Address Position (2) */ +#define DISP_BITMASK_HEA7 DISP_BIT_IB07 +#define DISP_BITMASK_HEA6 DISP_BIT_IB06 +#define DISP_BITMASK_HEA5 DISP_BIT_IB05 +#define DISP_BITMASK_HEA4 DISP_BIT_IB04 +#define DISP_BITMASK_HEA3 DISP_BIT_IB03 +#define DISP_BITMASK_HEA2 DISP_BIT_IB02 +#define DISP_BITMASK_HEA1 DISP_BIT_IB01 +#define DISP_BITMASK_HEA0 DISP_BIT_IB00 +/* DISP_VERT_RAM_ADDR_POS_1_ADDR Vertical RAM Address Position (1) */ +#define DISP_BITMASK_VSA8 DISP_BIT_IB08 +#define DISP_BITMASK_VSA7 DISP_BIT_IB07 +#define DISP_BITMASK_VSA6 DISP_BIT_IB06 +#define DISP_BITMASK_VSA5 DISP_BIT_IB05 +#define DISP_BITMASK_VSA4 DISP_BIT_IB04 +#define DISP_BITMASK_VSA3 DISP_BIT_IB03 +#define DISP_BITMASK_VSA2 DISP_BIT_IB02 +#define DISP_BITMASK_VSA1 DISP_BIT_IB01 +#define DISP_BITMASK_VSA0 DISP_BIT_IB00 +/* DISP_VERT_RAM_ADDR_POS_2_ADDR Vertical RAM Address Position (2) */ +#define DISP_BITMASK_VEA8 DISP_BIT_IB08 +#define DISP_BITMASK_VEA7 DISP_BIT_IB07 +#define DISP_BITMASK_VEA6 DISP_BIT_IB06 +#define DISP_BITMASK_VEA5 DISP_BIT_IB05 +#define DISP_BITMASK_VEA4 DISP_BIT_IB04 +#define DISP_BITMASK_VEA3 DISP_BIT_IB03 +#define DISP_BITMASK_VEA2 DISP_BIT_IB02 +#define DISP_BITMASK_VEA1 DISP_BIT_IB01 +#define DISP_BITMASK_VEA0 DISP_BIT_IB00 +static word disp_area_start_row; +static word disp_area_end_row; +static boolean disp_initialized = FALSE; +/* For some reason the contrast set at init time is not good. Need to do +* it again +*/ +static boolean display_on = FALSE; + +static uint32 tmd20qvga_lcd_rev; +uint16 tmd20qvga_panel_offset; + +#ifdef DISP_DEVICE_8BPP +static word convert_8_to_16_tbl[256] = { + 0x0000, 0x2000, 0x4000, 0x6000, 0x8000, 0xA000, 0xC000, 0xE000, + 0x0100, 0x2100, 0x4100, 0x6100, 0x8100, 0xA100, 0xC100, 0xE100, + 0x0200, 0x2200, 0x4200, 0x6200, 0x8200, 0xA200, 0xC200, 0xE200, + 0x0300, 0x2300, 0x4300, 0x6300, 0x8300, 0xA300, 0xC300, 0xE300, + 0x0400, 0x2400, 0x4400, 0x6400, 0x8400, 0xA400, 0xC400, 0xE400, + 0x0500, 0x2500, 0x4500, 0x6500, 0x8500, 0xA500, 0xC500, 0xE500, + 0x0600, 0x2600, 0x4600, 0x6600, 0x8600, 0xA600, 0xC600, 0xE600, + 0x0700, 0x2700, 0x4700, 0x6700, 0x8700, 0xA700, 0xC700, 0xE700, + 0x0008, 0x2008, 0x4008, 0x6008, 0x8008, 0xA008, 0xC008, 0xE008, + 0x0108, 0x2108, 0x4108, 0x6108, 0x8108, 0xA108, 0xC108, 0xE108, + 0x0208, 0x2208, 0x4208, 0x6208, 0x8208, 0xA208, 0xC208, 0xE208, + 0x0308, 0x2308, 0x4308, 0x6308, 0x8308, 0xA308, 0xC308, 0xE308, + 0x0408, 0x2408, 0x4408, 0x6408, 0x8408, 0xA408, 0xC408, 0xE408, + 0x0508, 0x2508, 0x4508, 0x6508, 0x8508, 0xA508, 0xC508, 0xE508, + 0x0608, 0x2608, 0x4608, 0x6608, 0x8608, 0xA608, 0xC608, 0xE608, + 0x0708, 0x2708, 0x4708, 0x6708, 0x8708, 0xA708, 0xC708, 0xE708, + 0x0010, 0x2010, 0x4010, 0x6010, 0x8010, 0xA010, 0xC010, 0xE010, + 0x0110, 0x2110, 0x4110, 0x6110, 0x8110, 0xA110, 0xC110, 0xE110, + 0x0210, 0x2210, 0x4210, 0x6210, 0x8210, 0xA210, 0xC210, 0xE210, + 0x0310, 0x2310, 0x4310, 0x6310, 0x8310, 0xA310, 0xC310, 0xE310, + 0x0410, 0x2410, 0x4410, 0x6410, 0x8410, 0xA410, 0xC410, 0xE410, + 0x0510, 0x2510, 0x4510, 0x6510, 0x8510, 0xA510, 0xC510, 0xE510, + 0x0610, 0x2610, 0x4610, 0x6610, 0x8610, 0xA610, 0xC610, 0xE610, + 0x0710, 0x2710, 0x4710, 0x6710, 0x8710, 0xA710, 0xC710, 0xE710, + 0x0018, 0x2018, 0x4018, 0x6018, 0x8018, 0xA018, 0xC018, 0xE018, + 0x0118, 0x2118, 0x4118, 0x6118, 0x8118, 0xA118, 0xC118, 0xE118, + 0x0218, 0x2218, 0x4218, 0x6218, 0x8218, 0xA218, 0xC218, 0xE218, + 0x0318, 0x2318, 0x4318, 0x6318, 0x8318, 0xA318, 0xC318, 0xE318, + 0x0418, 0x2418, 0x4418, 0x6418, 0x8418, 0xA418, 0xC418, 0xE418, + 0x0518, 0x2518, 0x4518, 0x6518, 0x8518, 0xA518, 0xC518, 0xE518, + 0x0618, 0x2618, 0x4618, 0x6618, 0x8618, 0xA618, 0xC618, 0xE618, + 0x0718, 0x2718, 0x4718, 0x6718, 0x8718, 0xA718, 0xC718, 0xE718 +}; +#endif /* DISP_DEVICE_8BPP */ + +static void tmd20qvga_disp_set_rect(int x, int y, int xres, int yres); +static void tmd20qvga_disp_init(struct platform_device *pdev); +static void tmd20qvga_disp_set_contrast(void); +static void tmd20qvga_disp_set_display_area(word start_row, word end_row); +static int tmd20qvga_disp_off(struct platform_device *pdev); +static int tmd20qvga_disp_on(struct platform_device *pdev); +static void tmd20qvga_set_revId(int); + +/* future use */ +void tmd20qvga_disp_clear_screen_area(word start_row, word end_row, + word start_column, word end_column); + +static void tmd20qvga_set_revId(int id) +{ + + tmd20qvga_lcd_rev = id; + + if (tmd20qvga_lcd_rev == 1) + tmd20qvga_panel_offset = 0x10; + else + tmd20qvga_panel_offset = 0; +} + +static void tmd20qvga_disp_init(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + if (disp_initialized) + return; + + mfd = platform_get_drvdata(pdev); + + DISP_CMD_PORT = mfd->cmd_port; + DISP_DATA_PORT = mfd->data_port; + +#ifdef TMD20QVGA_LCD_18BPP + tmd20qvga_set_revId(2); +#else + tmd20qvga_set_revId(1); +#endif + + disp_initialized = TRUE; + tmd20qvga_disp_set_contrast(); + tmd20qvga_disp_set_display_area(0, QVGA_HEIGHT - 1); +} + +static void tmd20qvga_disp_set_rect(int x, int y, int xres, int yres) +{ + if (!disp_initialized) + return; + + DISP_SET_RECT(y, y + yres - 1, x, x + xres - 1); + + DISP_CMD_OUT(DISP_CMD_RAMWR); +} + +static void tmd20qvga_disp_set_display_area(word start_row, word end_row) +{ + word start_driving = start_row; + word end_driving = end_row; + + if (!disp_initialized) + return; + + /* Range checking + */ + if (end_driving >= QVGA_HEIGHT) + end_driving = QVGA_HEIGHT - 1; + if (start_driving > end_driving) { + /* Probably Backwards Switch */ + start_driving = end_driving; + end_driving = start_row; /* Has not changed */ + if (end_driving >= QVGA_HEIGHT) + end_driving = QVGA_HEIGHT - 1; + } + + if ((start_driving == disp_area_start_row) + && (end_driving == disp_area_end_row)) + return; + + disp_area_start_row = start_driving; + disp_area_end_row = end_driving; + + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, + DISP_VAL_IF(start_driving & 0x100, + DISP_BITMASK_SS18) | + DISP_VAL_IF(start_driving & 0x080, + DISP_BITMASK_SS17) | + DISP_VAL_IF(start_driving & 0x040, + DISP_BITMASK_SS16) | + DISP_VAL_IF(start_driving & 0x020, + DISP_BITMASK_SS15) | + DISP_VAL_IF(start_driving & 0x010, + DISP_BITMASK_SS14) | + DISP_VAL_IF(start_driving & 0x008, + DISP_BITMASK_SS13) | + DISP_VAL_IF(start_driving & 0x004, + DISP_BITMASK_SS12) | + DISP_VAL_IF(start_driving & 0x002, + DISP_BITMASK_SS11) | + DISP_VAL_IF(start_driving & 0x001, DISP_BITMASK_SS10)); + + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, + DISP_VAL_IF(end_driving & 0x100, DISP_BITMASK_SE18) | + DISP_VAL_IF(end_driving & 0x080, DISP_BITMASK_SE17) | + DISP_VAL_IF(end_driving & 0x040, DISP_BITMASK_SE16) | + DISP_VAL_IF(end_driving & 0x020, DISP_BITMASK_SE15) | + DISP_VAL_IF(end_driving & 0x010, DISP_BITMASK_SE14) | + DISP_VAL_IF(end_driving & 0x008, DISP_BITMASK_SE13) | + DISP_VAL_IF(end_driving & 0x004, DISP_BITMASK_SE12) | + DISP_VAL_IF(end_driving & 0x002, DISP_BITMASK_SE11) | + DISP_VAL_IF(end_driving & 0x001, DISP_BITMASK_SE10)); +} + +static int tmd20qvga_disp_off(struct platform_device *pdev) +{ + if (!disp_initialized) + tmd20qvga_disp_init(pdev); + + if (display_on) { + if (tmd20qvga_lcd_rev == 2) { + DISP_WRITE_OUT(DISP_POFF_LN_SETTING_ADDR, 0x000A); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xFFEE); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xF812); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xE811); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xC011); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x4011); + WAIT_MSEC(20); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0010); + + } else { + DISP_WRITE_OUT(DISP_POFF_LN_SETTING_ADDR, 0x000F); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BFE); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BED); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x00CD); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(20); + DISP_WRITE_OUT(DISP_START_OSCILLATION_ADDR, 0x0); + } + + DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0004); + DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0000); + + display_on = FALSE; + } + + return 0; +} + +static int tmd20qvga_disp_on(struct platform_device *pdev) +{ + if (!disp_initialized) + tmd20qvga_disp_init(pdev); + + if (!display_on) { + /* Deep Stand-by -> Stand-by */ + DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR); + WAIT_MSEC(1); + DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR); + WAIT_MSEC(1); + DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR); + WAIT_MSEC(1); + + /* OFF -> Deep Stan-By -> Stand-by */ + /* let's change the state from "Stand-by" to "Sleep" */ + DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0005); + WAIT_MSEC(1); + + /* Sleep -> Displaying */ + DISP_WRITE_OUT(DISP_START_OSCILLATION_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_DRIVER_OUTPUT_CTL_ADDR, 0x0127); + DISP_WRITE_OUT(DISP_LCD_DRIVING_SIG_ADDR, 0x200); + /* fast write mode */ + DISP_WRITE_OUT(DISP_ENTRY_MODE_ADDR, 0x0130); + if (tmd20qvga_lcd_rev == 2) + DISP_WRITE_OUT(DISP_TMD_700_ADDR, 0x0003); + /* back porch = 14 + front porch = 2 --> 16 lines */ + if (tmd20qvga_lcd_rev == 2) { +#ifdef TMD20QVGA_LCD_18BPP + /* 256k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x0000); +#else + /* 65k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x4000); +#endif + DISP_WRITE_OUT(DISP_DISPLAY_CTL_2_ADDR, 0x0302); + } else { +#ifdef TMD20QVGA_LCD_18BPP + /* 256k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x0004); +#else + /* 65k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x4004); +#endif + DISP_WRITE_OUT(DISP_DISPLAY_CTL_2_ADDR, 0x020E); + } + /* 16 bit one transfer */ + if (tmd20qvga_lcd_rev == 2) { + DISP_WRITE_OUT(DISP_EXT_DISPLAY_CTL_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_FRAME_CYCLE_CTL_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_LTPS_CTL_1_ADDR, 0x0302); + DISP_WRITE_OUT(DISP_LTPS_CTL_2_ADDR, 0x0102); + DISP_WRITE_OUT(DISP_LTPS_CTL_3_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_TMD_015_ADDR, 0x2000); + + DISP_WRITE_OUT(DISP_AMP_SETTING_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0304); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0101); + DISP_WRITE_OUT(DISP_TMD_305_ADDR, 0); + + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, 0x013F); + + DISP_WRITE_OUT(DISP_POWER_CTL_3_ADDR, 0x077D); + + DISP_WRITE_OUT(DISP_POWER_CTL_4_ADDR, 0x0005); + DISP_WRITE_OUT(DISP_POWER_CTL_5_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_POWER_CTL_6_ADDR, 0x0015); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xC010); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xFFFE); + WAIT_MSEC(60); + } else { + DISP_WRITE_OUT(DISP_EXT_DISPLAY_CTL_1_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_FRAME_CYCLE_CTL_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_LTPS_CTL_1_ADDR, 0x0301); + DISP_WRITE_OUT(DISP_LTPS_CTL_2_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_LTPS_CTL_3_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_AMP_SETTING_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0507); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0405); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0607); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0502); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0301); + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, 0x013F); + DISP_WRITE_OUT(DISP_POWER_CTL_3_ADDR, 0x0795); + + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0102); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_4_ADDR, 0x0450); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0103); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_5_ADDR, 0x0008); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0104); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_6_ADDR, 0x0C00); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0105); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_7_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0106); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0801); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x001F); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0101); + WAIT_MSEC(60); + + DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x009F); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0101); + WAIT_MSEC(10); + + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_1_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_2_ADDR, 0x00FF); + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_2_ADDR, 0x013F); + /* RAM starts at address 0x10 */ + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_1_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_2_ADDR, 0x0000); + + /* lcd controller uses internal clock, not ext. vsync */ + DISP_CMD_OUT(DISP_CMD_RAMWR); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0881); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BE1); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BFF); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + } + display_on = TRUE; + } + + return 0; +} + +static void tmd20qvga_disp_set_contrast(void) +{ +#if (defined(TMD20QVGA_LCD_18BPP)) + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0302); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0F07); + +#else + int newcontrast = 0x46; + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403); + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, + DISP_VAL_IF(newcontrast & 0x0001, DISP_BITMASK_PKP20) | + DISP_VAL_IF(newcontrast & 0x0002, DISP_BITMASK_PKP21) | + DISP_VAL_IF(newcontrast & 0x0004, DISP_BITMASK_PKP22) | + DISP_VAL_IF(newcontrast & 0x0010, DISP_BITMASK_PKP30) | + DISP_VAL_IF(newcontrast & 0x0020, DISP_BITMASK_PKP31) | + DISP_VAL_IF(newcontrast & 0x0040, DISP_BITMASK_PKP32)); + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, + DISP_VAL_IF(newcontrast & 0x0010, DISP_BITMASK_PKP40) | + DISP_VAL_IF(newcontrast & 0x0020, DISP_BITMASK_PKP41) | + DISP_VAL_IF(newcontrast & 0x0040, DISP_BITMASK_PKP42) | + DISP_VAL_IF(newcontrast & 0x0001, DISP_BITMASK_PKP50) | + DISP_VAL_IF(newcontrast & 0x0002, DISP_BITMASK_PKP51) | + DISP_VAL_IF(newcontrast & 0x0004, DISP_BITMASK_PKP52)); + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0F07); + +#endif /* defined(TMD20QVGA_LCD_18BPP) */ + +} /* End disp_set_contrast */ + +void tmd20qvga_disp_clear_screen_area + (word start_row, word end_row, word start_column, word end_column) { + int32 i; + + /* Clear the display screen */ + DISP_SET_RECT(start_row, end_row, start_column, end_column); + DISP_CMD_OUT(DISP_CMD_RAMWR); + i = (end_row - start_row + 1) * (end_column - start_column + 1); + for (; i > 0; i--) + DISP_DATA_OUT_16TO18BPP(0x0); +} + +static int __init tmd20qvga_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = tmd20qvga_probe, + .driver = { + .name = "ebi2_tmd_qvga", + }, +}; + +static struct msm_fb_panel_data tmd20qvga_panel_data = { + .on = tmd20qvga_disp_on, + .off = tmd20qvga_disp_off, + .set_rect = tmd20qvga_disp_set_rect, +}; + +static struct platform_device this_device = { + .name = "ebi2_tmd_qvga", + .id = 0, + .dev = { + .platform_data = &tmd20qvga_panel_data, + } +}; + +static int __init tmd20qvga_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &tmd20qvga_panel_data.panel_info; + pinfo->xres = 240; + pinfo->yres = 320; + pinfo->type = EBI2_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0x808000; +#ifdef TMD20QVGA_LCD_18BPP + pinfo->bpp = 18; +#else + pinfo->bpp = 16; +#endif + pinfo->fb_num = 2; + pinfo->lcd.vsync_enable = TRUE; + pinfo->lcd.refx100 = 6000; + pinfo->lcd.v_back_porch = 16; + pinfo->lcd.v_front_porch = 4; + pinfo->lcd.v_pulse_width = 0; + pinfo->lcd.hw_vsync_mode = FALSE; + pinfo->lcd.vsync_notifier_period = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(tmd20qvga_init); diff --git a/drivers/staging/msm/hdmi_sii9022.c b/drivers/staging/msm/hdmi_sii9022.c new file mode 100644 index 000000000000..6b82b56a77b6 --- /dev/null +++ b/drivers/staging/msm/hdmi_sii9022.c @@ -0,0 +1,248 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/i2c.h> +#include <linux/delay.h> +#include "msm_fb.h" + +#define DEVICE_NAME "sii9022" +#define SII9022_DEVICE_ID 0xB0 + +struct sii9022_i2c_addr_data{ + u8 addr; + u8 data; +}; + +/* video mode data */ +static u8 video_mode_data[] = { + 0x00, + 0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02, +}; + +static u8 avi_io_format[] = { + 0x09, + 0x00, 0x00, +}; + +/* power state */ +static struct sii9022_i2c_addr_data regset0[] = { + { 0x60, 0x04 }, + { 0x63, 0x00 }, + { 0x1E, 0x00 }, +}; + +static u8 video_infoframe[] = { + 0x0C, + 0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00, + 0xE9, 0x02, 0x04, 0x01, 0x04, 0x06, +}; + +/* configure audio */ +static struct sii9022_i2c_addr_data regset1[] = { + { 0x26, 0x90 }, + { 0x20, 0x90 }, + { 0x1F, 0x80 }, + { 0x26, 0x80 }, + { 0x24, 0x02 }, + { 0x25, 0x0B }, + { 0xBC, 0x02 }, + { 0xBD, 0x24 }, + { 0xBE, 0x02 }, +}; + +/* enable audio */ +static u8 misc_infoframe[] = { + 0xBF, + 0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +/* set HDMI, active */ +static struct sii9022_i2c_addr_data regset2[] = { + { 0x1A, 0x01 }, + { 0x3D, 0x00 }, +}; + +static int send_i2c_data(struct i2c_client *client, + struct sii9022_i2c_addr_data *regset, + int size) +{ + int i; + int rc = 0; + + for (i = 0; i < size; i++) { + rc = i2c_smbus_write_byte_data( + client, + regset[i].addr, regset[i].data); + if (rc) + break; + } + return rc; +} + +static int hdmi_sii_enable(struct i2c_client *client) +{ + int rc; + int retries = 10; + int count; + + rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00); + if (rc) + goto enable_exit; + + do { + msleep(1); + rc = i2c_smbus_read_byte_data(client, 0x1B); + } while ((rc != SII9022_DEVICE_ID) && retries--); + + if (rc != SII9022_DEVICE_ID) + return -ENODEV; + + rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(video_mode_data); + rc = i2c_master_send(client, video_mode_data, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = i2c_smbus_write_byte_data(client, 0x08, 0x20); + if (rc) + goto enable_exit; + count = ARRAY_SIZE(avi_io_format); + rc = i2c_master_send(client, avi_io_format, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0)); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(video_infoframe); + rc = i2c_master_send(client, video_infoframe, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1)); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(misc_infoframe); + rc = i2c_master_send(client, misc_infoframe, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2)); + if (rc) + goto enable_exit; + + return 0; +enable_exit: + printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc); + return rc; +} + +static const struct i2c_device_id hmdi_sii_id[] = { + { DEVICE_NAME, 0 }, + { } +}; + +static int hdmi_sii_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C)) + return -ENODEV; + rc = hdmi_sii_enable(client); + return rc; +} + + +static struct i2c_driver hdmi_sii_i2c_driver = { + .driver = { + .name = DEVICE_NAME, + .owner = THIS_MODULE, + }, + .probe = hdmi_sii_probe, + .remove = __exit_p(hdmi_sii_remove), + .id_table = hmdi_sii_id, +}; + +static int __init hdmi_sii_init(void) +{ + int ret; + struct msm_panel_info pinfo; + + if (msm_fb_detect_client("hdmi_sii9022")) + return 0; + + pinfo.xres = 1280; + pinfo.yres = 720; + pinfo.type = HDMI_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.fb_num = 2; + pinfo.clk_rate = 74250000; + + pinfo.lcdc.h_back_porch = 124; + pinfo.lcdc.h_front_porch = 110; + pinfo.lcdc.h_pulse_width = 136; + pinfo.lcdc.v_back_porch = 19; + pinfo.lcdc.v_front_porch = 5; + pinfo.lcdc.v_pulse_width = 6; + pinfo.lcdc.border_clr = 0; + pinfo.lcdc.underflow_clr = 0xff; + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) { + printk(KERN_ERR "%s: failed to register device\n", __func__); + goto init_exit; + } + + ret = i2c_add_driver(&hdmi_sii_i2c_driver); + if (ret) + printk(KERN_ERR "%s: failed to add i2c driver\n", __func__); + +init_exit: + return ret; +} + +static void __exit hdmi_sii_exit(void) +{ + i2c_del_driver(&hdmi_sii_i2c_driver); +} + +module_init(hdmi_sii_init); +module_exit(hdmi_sii_exit); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); +MODULE_AUTHOR("Qualcomm Innovation Center, Inc."); +MODULE_DESCRIPTION("SiI9022 HDMI driver"); +MODULE_ALIAS("platform:hdmi-sii9022"); diff --git a/drivers/staging/msm/lcdc.c b/drivers/staging/msm/lcdc.c new file mode 100644 index 000000000000..735280ab72cb --- /dev/null +++ b/drivers/staging/msm/lcdc.c @@ -0,0 +1,239 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/pm_qos_params.h> + +#include "msm_fb.h" + +static int lcdc_probe(struct platform_device *pdev); +static int lcdc_remove(struct platform_device *pdev); + +static int lcdc_off(struct platform_device *pdev); +static int lcdc_on(struct platform_device *pdev); + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +static struct clk *mdp_lcdc_pclk_clk; +static struct clk *mdp_lcdc_pad_pclk_clk; + +int mdp_lcdc_pclk_clk_rate; +int mdp_lcdc_pad_pclk_clk_rate; + +static struct platform_driver lcdc_driver = { + .probe = lcdc_probe, + .remove = lcdc_remove, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "lcdc", + }, +}; + +static struct lcdc_platform_data *lcdc_pdata; + +static int lcdc_off(struct platform_device *pdev) +{ + int ret = 0; + + ret = panel_next_off(pdev); + + clk_disable(mdp_lcdc_pclk_clk); + clk_disable(mdp_lcdc_pad_pclk_clk); + + if (lcdc_pdata && lcdc_pdata->lcdc_power_save) + lcdc_pdata->lcdc_power_save(0); + + if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config) + ret = lcdc_pdata->lcdc_gpio_config(0); + +// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc", +// PM_QOS_DEFAULT_VALUE); + + return ret; +} + +static int lcdc_on(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + unsigned long panel_pixclock_freq , pm_qos_freq; + + mfd = platform_get_drvdata(pdev); + panel_pixclock_freq = mfd->fbi->var.pixclock; + + if (panel_pixclock_freq > 58000000) + /* pm_qos_freq should be in Khz */ + pm_qos_freq = panel_pixclock_freq / 1000 ; + else + pm_qos_freq = 58000; + +// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc", +// pm_qos_freq); + mfd = platform_get_drvdata(pdev); + + clk_enable(mdp_lcdc_pclk_clk); + clk_enable(mdp_lcdc_pad_pclk_clk); + + if (lcdc_pdata && lcdc_pdata->lcdc_power_save) + lcdc_pdata->lcdc_power_save(1); + if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config) + ret = lcdc_pdata->lcdc_gpio_config(1); + + clk_set_rate(mdp_lcdc_pclk_clk, mfd->fbi->var.pixclock); + clk_set_rate(mdp_lcdc_pad_pclk_clk, mfd->fbi->var.pixclock); + mdp_lcdc_pclk_clk_rate = clk_get_rate(mdp_lcdc_pclk_clk); + mdp_lcdc_pad_pclk_clk_rate = clk_get_rate(mdp_lcdc_pad_pclk_clk); + + ret = panel_next_on(pdev); + return ret; +} + +static int lcdc_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct fb_info *fbi; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc; + + if (pdev->id == 0) { + lcdc_pdata = pdev->dev.platform_data; + return 0; + } + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_LCDC; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "lcdc_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data; + pdata->on = lcdc_on; + pdata->off = lcdc_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + mfd->fb_imgType = MDP_RGB_565; + + fbi = mfd->fbi; + fbi->var.pixclock = mfd->panel_info.clk_rate; + fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch; + fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch; + fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch; + fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch; + fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width; + fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width; + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto lcdc_probe_err; + + pdev_list[pdev_list_cnt++] = pdev; + return 0; + +lcdc_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int lcdc_remove(struct platform_device *pdev) +{ +// pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc"); + return 0; +} + +static int lcdc_register_driver(void) +{ + return platform_driver_register(&lcdc_driver); +} + +static int __init lcdc_driver_init(void) +{ + mdp_lcdc_pclk_clk = clk_get(NULL, "mdp_lcdc_pclk_clk"); + if (IS_ERR(mdp_lcdc_pclk_clk)) { + printk(KERN_ERR "error: can't get mdp_lcdc_pclk_clk!\n"); + return IS_ERR(mdp_lcdc_pclk_clk); + } + mdp_lcdc_pad_pclk_clk = clk_get(NULL, "mdp_lcdc_pad_pclk_clk"); + if (IS_ERR(mdp_lcdc_pad_pclk_clk)) { + printk(KERN_ERR "error: can't get mdp_lcdc_pad_pclk_clk!\n"); + return IS_ERR(mdp_lcdc_pad_pclk_clk); + } +// pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc", +// PM_QOS_DEFAULT_VALUE); + return lcdc_register_driver(); +} + +module_init(lcdc_driver_init); diff --git a/drivers/staging/msm/lcdc_external.c b/drivers/staging/msm/lcdc_external.c new file mode 100644 index 000000000000..45ff78527111 --- /dev/null +++ b/drivers/staging/msm/lcdc_external.c @@ -0,0 +1,54 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" + +static int __init lcdc_external_init(void) +{ + int ret; + struct msm_panel_info pinfo; + + if (msm_fb_detect_client("lcdc_external")) + return 0; + + pinfo.xres = 1280; + pinfo.yres = 720; + pinfo.type = LCDC_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.fb_num = 2; + pinfo.clk_rate = 74250000; + + pinfo.lcdc.h_back_porch = 124; + pinfo.lcdc.h_front_porch = 110; + pinfo.lcdc.h_pulse_width = 136; + pinfo.lcdc.v_back_porch = 19; + pinfo.lcdc.v_front_porch = 5; + pinfo.lcdc.v_pulse_width = 6; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(lcdc_external_init); diff --git a/drivers/staging/msm/lcdc_gordon.c b/drivers/staging/msm/lcdc_gordon.c new file mode 100644 index 000000000000..399ec8c791ec --- /dev/null +++ b/drivers/staging/msm/lcdc_gordon.c @@ -0,0 +1,446 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/delay.h> +#include <mach/gpio.h> +#include "msm_fb.h" + +/* registers */ +#define GORDON_REG_NOP 0x00 +#define GORDON_REG_IMGCTL1 0x10 +#define GORDON_REG_IMGCTL2 0x11 +#define GORDON_REG_IMGSET1 0x12 +#define GORDON_REG_IMGSET2 0x13 +#define GORDON_REG_IVBP1 0x14 +#define GORDON_REG_IHBP1 0x15 +#define GORDON_REG_IVNUM1 0x16 +#define GORDON_REG_IHNUM1 0x17 +#define GORDON_REG_IVBP2 0x18 +#define GORDON_REG_IHBP2 0x19 +#define GORDON_REG_IVNUM2 0x1A +#define GORDON_REG_IHNUM2 0x1B +#define GORDON_REG_LCDIFCTL1 0x30 +#define GORDON_REG_VALTRAN 0x31 +#define GORDON_REG_AVCTL 0x33 +#define GORDON_REG_LCDIFCTL2 0x34 +#define GORDON_REG_LCDIFCTL3 0x35 +#define GORDON_REG_LCDIFSET1 0x36 +#define GORDON_REG_PCCTL 0x3C +#define GORDON_REG_TPARAM1 0x40 +#define GORDON_REG_TLCDIF1 0x41 +#define GORDON_REG_TSSPB_ST1 0x42 +#define GORDON_REG_TSSPB_ED1 0x43 +#define GORDON_REG_TSCK_ST1 0x44 +#define GORDON_REG_TSCK_WD1 0x45 +#define GORDON_REG_TGSPB_VST1 0x46 +#define GORDON_REG_TGSPB_VED1 0x47 +#define GORDON_REG_TGSPB_CH1 0x48 +#define GORDON_REG_TGCK_ST1 0x49 +#define GORDON_REG_TGCK_ED1 0x4A +#define GORDON_REG_TPCTL_ST1 0x4B +#define GORDON_REG_TPCTL_ED1 0x4C +#define GORDON_REG_TPCHG_ED1 0x4D +#define GORDON_REG_TCOM_CH1 0x4E +#define GORDON_REG_THBP1 0x4F +#define GORDON_REG_TPHCTL1 0x50 +#define GORDON_REG_EVPH1 0x51 +#define GORDON_REG_EVPL1 0x52 +#define GORDON_REG_EVNH1 0x53 +#define GORDON_REG_EVNL1 0x54 +#define GORDON_REG_TBIAS1 0x55 +#define GORDON_REG_TPARAM2 0x56 +#define GORDON_REG_TLCDIF2 0x57 +#define GORDON_REG_TSSPB_ST2 0x58 +#define GORDON_REG_TSSPB_ED2 0x59 +#define GORDON_REG_TSCK_ST2 0x5A +#define GORDON_REG_TSCK_WD2 0x5B +#define GORDON_REG_TGSPB_VST2 0x5C +#define GORDON_REG_TGSPB_VED2 0x5D +#define GORDON_REG_TGSPB_CH2 0x5E +#define GORDON_REG_TGCK_ST2 0x5F +#define GORDON_REG_TGCK_ED2 0x60 +#define GORDON_REG_TPCTL_ST2 0x61 +#define GORDON_REG_TPCTL_ED2 0x62 +#define GORDON_REG_TPCHG_ED2 0x63 +#define GORDON_REG_TCOM_CH2 0x64 +#define GORDON_REG_THBP2 0x65 +#define GORDON_REG_TPHCTL2 0x66 +#define GORDON_REG_POWCTL 0x80 + +static int lcdc_gordon_panel_off(struct platform_device *pdev); + +static int spi_cs; +static int spi_sclk; +static int spi_sdo; +static int spi_sdi; +static int spi_dac; +static unsigned char bit_shift[8] = { (1 << 7), /* MSB */ + (1 << 6), + (1 << 5), + (1 << 4), + (1 << 3), + (1 << 2), + (1 << 1), + (1 << 0) /* LSB */ +}; + +struct gordon_state_type{ + boolean disp_initialized; + boolean display_on; + boolean disp_powered_up; +}; + +static struct gordon_state_type gordon_state = { 0 }; +static struct msm_panel_common_pdata *lcdc_gordon_pdata; + +static void serigo(uint16 reg, uint8 data) +{ + unsigned int tx_val = ((0x00FF & reg) << 8) | data; + unsigned char i, val = 0; + + /* Enable the Chip Select */ + gpio_set_value(spi_cs, 1); + udelay(33); + + /* Transmit it in two parts, Higher Byte first, then Lower Byte */ + val = (unsigned char)((tx_val & 0xFF00) >> 8); + + /* Clock should be Low before entering ! */ + for (i = 0; i < 8; i++) { + /* #1: Drive the Data (High or Low) */ + if (val & bit_shift[i]) + gpio_set_value(spi_sdi, 1); + else + gpio_set_value(spi_sdi, 0); + + /* #2: Drive the Clk High and then Low */ + udelay(33); + gpio_set_value(spi_sclk, 1); + udelay(33); + gpio_set_value(spi_sclk, 0); + } + + /* Idle state of SDO (MOSI) is Low */ + gpio_set_value(spi_sdi, 0); + /* ..then Lower Byte */ + val = (uint8) (tx_val & 0x00FF); + /* Before we enter here the Clock should be Low ! */ + + for (i = 0; i < 8; i++) { + /* #1: Drive the Data (High or Low) */ + if (val & bit_shift[i]) + gpio_set_value(spi_sdi, 1); + else + gpio_set_value(spi_sdi, 0); + + /* #2: Drive the Clk High and then Low */ + udelay(33); + + gpio_set_value(spi_sclk, 1); + udelay(33); + gpio_set_value(spi_sclk, 0); + } + + /* Idle state of SDO (MOSI) is Low */ + gpio_set_value(spi_sdi, 0); + + /* Now Disable the Chip Select */ + udelay(33); + gpio_set_value(spi_cs, 0); +} + +static void spi_init(void) +{ + /* Setting the Default GPIO's */ + spi_sclk = *(lcdc_gordon_pdata->gpio_num); + spi_cs = *(lcdc_gordon_pdata->gpio_num + 1); + spi_sdi = *(lcdc_gordon_pdata->gpio_num + 2); + spi_sdo = *(lcdc_gordon_pdata->gpio_num + 3); + + /* Set the output so that we dont disturb the slave device */ + gpio_set_value(spi_sclk, 0); + gpio_set_value(spi_sdi, 0); + + /* Set the Chip Select De-asserted */ + gpio_set_value(spi_cs, 0); + +} + +static void gordon_disp_powerup(void) +{ + if (!gordon_state.disp_powered_up && !gordon_state.display_on) { + /* Reset the hardware first */ + /* Include DAC power up implementation here */ + gordon_state.disp_powered_up = TRUE; + } +} + +static void gordon_init(void) +{ + /* Image interface settings */ + serigo(GORDON_REG_IMGCTL2, 0x00); + serigo(GORDON_REG_IMGSET1, 0x00); + + /* Exchange the RGB signal for J510(Softbank mobile) */ + serigo(GORDON_REG_IMGSET2, 0x12); + serigo(GORDON_REG_LCDIFSET1, 0x00); + + /* Pre-charge settings */ + serigo(GORDON_REG_PCCTL, 0x09); + serigo(GORDON_REG_LCDIFCTL2, 0x7B); + + mdelay(1); +} + +static void gordon_disp_on(void) +{ + if (gordon_state.disp_powered_up && !gordon_state.display_on) { + gordon_init(); + mdelay(20); + /* gordon_dispmode setting */ + serigo(GORDON_REG_TPARAM1, 0x30); + serigo(GORDON_REG_TLCDIF1, 0x00); + serigo(GORDON_REG_TSSPB_ST1, 0x8B); + serigo(GORDON_REG_TSSPB_ED1, 0x93); + serigo(GORDON_REG_TSCK_ST1, 0x88); + serigo(GORDON_REG_TSCK_WD1, 0x00); + serigo(GORDON_REG_TGSPB_VST1, 0x01); + serigo(GORDON_REG_TGSPB_VED1, 0x02); + serigo(GORDON_REG_TGSPB_CH1, 0x5E); + serigo(GORDON_REG_TGCK_ST1, 0x80); + serigo(GORDON_REG_TGCK_ED1, 0x3C); + serigo(GORDON_REG_TPCTL_ST1, 0x50); + serigo(GORDON_REG_TPCTL_ED1, 0x74); + serigo(GORDON_REG_TPCHG_ED1, 0x78); + serigo(GORDON_REG_TCOM_CH1, 0x50); + serigo(GORDON_REG_THBP1, 0x84); + serigo(GORDON_REG_TPHCTL1, 0x00); + serigo(GORDON_REG_EVPH1, 0x70); + serigo(GORDON_REG_EVPL1, 0x64); + serigo(GORDON_REG_EVNH1, 0x56); + serigo(GORDON_REG_EVNL1, 0x48); + serigo(GORDON_REG_TBIAS1, 0x88); + + /* QVGA settings */ + serigo(GORDON_REG_TPARAM2, 0x28); + serigo(GORDON_REG_TLCDIF2, 0x14); + serigo(GORDON_REG_TSSPB_ST2, 0x49); + serigo(GORDON_REG_TSSPB_ED2, 0x4B); + serigo(GORDON_REG_TSCK_ST2, 0x4A); + serigo(GORDON_REG_TSCK_WD2, 0x02); + serigo(GORDON_REG_TGSPB_VST2, 0x02); + serigo(GORDON_REG_TGSPB_VED2, 0x03); + serigo(GORDON_REG_TGSPB_CH2, 0x2F); + serigo(GORDON_REG_TGCK_ST2, 0x40); + serigo(GORDON_REG_TGCK_ED2, 0x1E); + serigo(GORDON_REG_TPCTL_ST2, 0x2C); + serigo(GORDON_REG_TPCTL_ED2, 0x3A); + serigo(GORDON_REG_TPCHG_ED2, 0x3C); + serigo(GORDON_REG_TCOM_CH2, 0x28); + serigo(GORDON_REG_THBP2, 0x4D); + serigo(GORDON_REG_TPHCTL2, 0x1A); + + /* VGA settings */ + serigo(GORDON_REG_IVBP1, 0x02); + serigo(GORDON_REG_IHBP1, 0x90); + serigo(GORDON_REG_IVNUM1, 0xA0); + serigo(GORDON_REG_IHNUM1, 0x78); + + /* QVGA settings */ + serigo(GORDON_REG_IVBP2, 0x02); + serigo(GORDON_REG_IHBP2, 0x48); + serigo(GORDON_REG_IVNUM2, 0x50); + serigo(GORDON_REG_IHNUM2, 0x3C); + + /* Gordon Charge pump settings and ON */ + serigo(GORDON_REG_POWCTL, 0x03); + mdelay(15); + serigo(GORDON_REG_POWCTL, 0x07); + mdelay(15); + + serigo(GORDON_REG_POWCTL, 0x0F); + mdelay(15); + + serigo(GORDON_REG_AVCTL, 0x03); + mdelay(15); + + serigo(GORDON_REG_POWCTL, 0x1F); + mdelay(15); + + serigo(GORDON_REG_POWCTL, 0x5F); + mdelay(15); + + serigo(GORDON_REG_POWCTL, 0x7F); + mdelay(15); + + serigo(GORDON_REG_LCDIFCTL1, 0x02); + mdelay(15); + + serigo(GORDON_REG_IMGCTL1, 0x00); + mdelay(15); + + serigo(GORDON_REG_LCDIFCTL3, 0x00); + mdelay(15); + + serigo(GORDON_REG_VALTRAN, 0x01); + mdelay(15); + + serigo(GORDON_REG_LCDIFCTL1, 0x03); + mdelay(1); + gordon_state.display_on = TRUE; + } +} + +static int lcdc_gordon_panel_on(struct platform_device *pdev) +{ + if (!gordon_state.disp_initialized) { + /* Configure reset GPIO that drives DAC */ + lcdc_gordon_pdata->panel_config_gpio(1); + spi_dac = *(lcdc_gordon_pdata->gpio_num + 4); + gpio_set_value(spi_dac, 0); + udelay(15); + gpio_set_value(spi_dac, 1); + spi_init(); /* LCD needs SPI */ + gordon_disp_powerup(); + gordon_disp_on(); + gordon_state.disp_initialized = TRUE; + } + return 0; +} + +static int lcdc_gordon_panel_off(struct platform_device *pdev) +{ + if (gordon_state.disp_powered_up && gordon_state.display_on) { + serigo(GORDON_REG_LCDIFCTL2, 0x7B); + serigo(GORDON_REG_VALTRAN, 0x01); + serigo(GORDON_REG_LCDIFCTL1, 0x02); + serigo(GORDON_REG_LCDIFCTL3, 0x01); + mdelay(20); + serigo(GORDON_REG_VALTRAN, 0x01); + serigo(GORDON_REG_IMGCTL1, 0x01); + serigo(GORDON_REG_LCDIFCTL1, 0x00); + mdelay(20); + + serigo(GORDON_REG_POWCTL, 0x1F); + mdelay(40); + + serigo(GORDON_REG_POWCTL, 0x07); + mdelay(40); + + serigo(GORDON_REG_POWCTL, 0x03); + mdelay(40); + + serigo(GORDON_REG_POWCTL, 0x00); + mdelay(40); + lcdc_gordon_pdata->panel_config_gpio(0); + gordon_state.display_on = FALSE; + gordon_state.disp_initialized = FALSE; + } + return 0; +} + +static void lcdc_gordon_set_backlight(struct msm_fb_data_type *mfd) +{ + int bl_level = mfd->bl_level; + + if (bl_level <= 1) { + /* keep back light OFF */ + serigo(GORDON_REG_LCDIFCTL2, 0x0B); + udelay(15); + serigo(GORDON_REG_VALTRAN, 0x01); + } else { + /* keep back light ON */ + serigo(GORDON_REG_LCDIFCTL2, 0x7B); + udelay(15); + serigo(GORDON_REG_VALTRAN, 0x01); + } +} + +static int __init gordon_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + lcdc_gordon_pdata = pdev->dev.platform_data; + return 0; + } + msm_fb_add_device(pdev); + return 0; +} + +static struct platform_driver this_driver = { + .probe = gordon_probe, + .driver = { + .name = "lcdc_gordon_vga", + }, +}; + +static struct msm_fb_panel_data gordon_panel_data = { + .on = lcdc_gordon_panel_on, + .off = lcdc_gordon_panel_off, + .set_backlight = lcdc_gordon_set_backlight, +}; + +static struct platform_device this_device = { + .name = "lcdc_gordon_vga", + .id = 1, + .dev = { + .platform_data = &gordon_panel_data, + } +}; + +static int __init lcdc_gordon_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM + if (msm_fb_detect_client("lcdc_gordon_vga")) + return 0; +#endif + ret = platform_driver_register(&this_driver); + if (ret) + return ret; + + pinfo = &gordon_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 640; + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 24; + pinfo->fb_num = 2; + pinfo->clk_rate = 24500000; + pinfo->bl_max = 4; + pinfo->bl_min = 1; + + pinfo->lcdc.h_back_porch = 84; + pinfo->lcdc.h_front_porch = 33; + pinfo->lcdc.h_pulse_width = 60; + pinfo->lcdc.v_back_porch = 0; + pinfo->lcdc.v_front_porch = 2; + pinfo->lcdc.v_pulse_width = 2; + pinfo->lcdc.border_clr = 0; /* blk */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + + return ret; +} + +module_init(lcdc_gordon_panel_init); diff --git a/drivers/staging/msm/lcdc_grapefruit.c b/drivers/staging/msm/lcdc_grapefruit.c new file mode 100644 index 000000000000..7284649ea0ae --- /dev/null +++ b/drivers/staging/msm/lcdc_grapefruit.c @@ -0,0 +1,60 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" + +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM +#include "mddihosti.h" +#endif + +static int __init lcdc_grapefruit_init(void) +{ + int ret; + struct msm_panel_info pinfo; + +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM + if (msm_fb_detect_client("lcdc_grapefruit_vga")) + return 0; +#endif + + pinfo.xres = 1024; + pinfo.yres = 600; + pinfo.type = LCDC_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.fb_num = 2; + pinfo.clk_rate = 40000000; + + pinfo.lcdc.h_back_porch = 88; + pinfo.lcdc.h_front_porch = 40; + pinfo.lcdc.h_pulse_width = 128; + pinfo.lcdc.v_back_porch = 23; + pinfo.lcdc.v_front_porch = 1; + pinfo.lcdc.v_pulse_width = 4; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(lcdc_grapefruit_init); diff --git a/drivers/staging/msm/lcdc_panel.c b/drivers/staging/msm/lcdc_panel.c new file mode 100644 index 000000000000..b40974e1f27c --- /dev/null +++ b/drivers/staging/msm/lcdc_panel.c @@ -0,0 +1,88 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" + +static int lcdc_panel_on(struct platform_device *pdev) +{ + return 0; +} + +static int lcdc_panel_off(struct platform_device *pdev) +{ + return 0; +} + +static int __init lcdc_panel_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = lcdc_panel_probe, + .driver = { + .name = "lcdc_panel", + }, +}; + +static struct msm_fb_panel_data lcdc_panel_data = { + .on = lcdc_panel_on, + .off = lcdc_panel_off, +}; + +static int lcdc_dev_id; + +int lcdc_device_register(struct msm_panel_info *pinfo) +{ + struct platform_device *pdev = NULL; + int ret; + + pdev = platform_device_alloc("lcdc_panel", ++lcdc_dev_id); + if (!pdev) + return -ENOMEM; + + lcdc_panel_data.panel_info = *pinfo; + ret = platform_device_add_data(pdev, &lcdc_panel_data, + sizeof(lcdc_panel_data)); + if (ret) { + printk(KERN_ERR + "%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + printk(KERN_ERR + "%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static int __init lcdc_panel_init(void) +{ + return platform_driver_register(&this_driver); +} + +module_init(lcdc_panel_init); diff --git a/drivers/staging/msm/lcdc_prism.c b/drivers/staging/msm/lcdc_prism.c new file mode 100644 index 000000000000..d102c98447c1 --- /dev/null +++ b/drivers/staging/msm/lcdc_prism.c @@ -0,0 +1,64 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" + +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM +#include "mddihosti.h" +#endif + +static int __init lcdc_prism_init(void) +{ + int ret; + struct msm_panel_info pinfo; + +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM + ret = msm_fb_detect_client("lcdc_prism_wvga"); + if (ret == -ENODEV) + return 0; + + if (ret && (mddi_get_client_id() != 0)) + return 0; +#endif + + pinfo.xres = 800; + pinfo.yres = 480; + pinfo.type = LCDC_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.fb_num = 2; + pinfo.clk_rate = 38460000; + + pinfo.lcdc.h_back_porch = 21; + pinfo.lcdc.h_front_porch = 81; + pinfo.lcdc.h_pulse_width = 60; + pinfo.lcdc.v_back_porch = 18; + pinfo.lcdc.v_front_porch = 27; + pinfo.lcdc.v_pulse_width = 2; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(lcdc_prism_init); diff --git a/drivers/staging/msm/lcdc_sharp_wvga_pt.c b/drivers/staging/msm/lcdc_sharp_wvga_pt.c new file mode 100644 index 000000000000..1f08cf9bc217 --- /dev/null +++ b/drivers/staging/msm/lcdc_sharp_wvga_pt.c @@ -0,0 +1,290 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/delay.h> +#ifdef CONFIG_ARCH_MSM7X30 +#include <linux/mfd/pmic8058.h> +#endif +#include <mach/gpio.h> +#include "msm_fb.h" + +static int lcdc_sharp_panel_off(struct platform_device *pdev); + +static int spi_cs; +static int spi_sclk; +static int spi_mosi; +static int spi_miso; +static unsigned char bit_shift[8] = { (1 << 7), /* MSB */ + (1 << 6), + (1 << 5), + (1 << 4), + (1 << 3), + (1 << 2), + (1 << 1), + (1 << 0) /* LSB */ +}; + +struct sharp_state_type { + boolean disp_initialized; + boolean display_on; + boolean disp_powered_up; +}; + +struct sharp_spi_data { + u8 addr; + u8 data; +}; + +static struct sharp_spi_data init_sequence[] = { + { 15, 0x01 }, + { 5, 0x01 }, + { 7, 0x10 }, + { 9, 0x1E }, + { 10, 0x04 }, + { 17, 0xFF }, + { 21, 0x8A }, + { 22, 0x00 }, + { 23, 0x82 }, + { 24, 0x24 }, + { 25, 0x22 }, + { 26, 0x6D }, + { 27, 0xEB }, + { 28, 0xB9 }, + { 29, 0x3A }, + { 49, 0x1A }, + { 50, 0x16 }, + { 51, 0x05 }, + { 55, 0x7F }, + { 56, 0x15 }, + { 57, 0x7B }, + { 60, 0x05 }, + { 61, 0x0C }, + { 62, 0x80 }, + { 63, 0x00 }, + { 92, 0x90 }, + { 97, 0x01 }, + { 98, 0xFF }, + { 113, 0x11 }, + { 114, 0x02 }, + { 115, 0x08 }, + { 123, 0xAB }, + { 124, 0x04 }, + { 6, 0x02 }, + { 133, 0x00 }, + { 134, 0xFE }, + { 135, 0x22 }, + { 136, 0x0B }, + { 137, 0xFF }, + { 138, 0x0F }, + { 139, 0x00 }, + { 140, 0xFE }, + { 141, 0x22 }, + { 142, 0x0B }, + { 143, 0xFF }, + { 144, 0x0F }, + { 145, 0x00 }, + { 146, 0xFE }, + { 147, 0x22 }, + { 148, 0x0B }, + { 149, 0xFF }, + { 150, 0x0F }, + { 202, 0x30 }, + { 30, 0x01 }, + { 4, 0x01 }, + { 31, 0x41 }, +}; + +static struct sharp_state_type sharp_state = { 0 }; +static struct msm_panel_common_pdata *lcdc_sharp_pdata; + +static void sharp_spi_write_byte(u8 val) +{ + int i; + + /* Clock should be Low before entering */ + for (i = 0; i < 8; i++) { + /* #1: Drive the Data (High or Low) */ + if (val & bit_shift[i]) + gpio_set_value(spi_mosi, 1); + else + gpio_set_value(spi_mosi, 0); + + /* #2: Drive the Clk High and then Low */ + gpio_set_value(spi_sclk, 1); + gpio_set_value(spi_sclk, 0); + } +} + +static void serigo(u8 reg, u8 data) +{ + /* Enable the Chip Select - low */ + gpio_set_value(spi_cs, 0); + udelay(1); + + /* Transmit register address first, then data */ + sharp_spi_write_byte(reg); + + /* Idle state of MOSI is Low */ + gpio_set_value(spi_mosi, 0); + udelay(1); + sharp_spi_write_byte(data); + + gpio_set_value(spi_mosi, 0); + gpio_set_value(spi_cs, 1); +} + +static void sharp_spi_init(void) +{ + spi_sclk = *(lcdc_sharp_pdata->gpio_num); + spi_cs = *(lcdc_sharp_pdata->gpio_num + 1); + spi_mosi = *(lcdc_sharp_pdata->gpio_num + 2); + spi_miso = *(lcdc_sharp_pdata->gpio_num + 3); + + /* Set the output so that we don't disturb the slave device */ + gpio_set_value(spi_sclk, 0); + gpio_set_value(spi_mosi, 0); + + /* Set the Chip Select deasserted (active low) */ + gpio_set_value(spi_cs, 1); +} + +static void sharp_disp_powerup(void) +{ + if (!sharp_state.disp_powered_up && !sharp_state.display_on) + sharp_state.disp_powered_up = TRUE; +} + +static void sharp_disp_on(void) +{ + int i; + + if (sharp_state.disp_powered_up && !sharp_state.display_on) { + for (i = 0; i < ARRAY_SIZE(init_sequence); i++) { + serigo(init_sequence[i].addr, + init_sequence[i].data); + } + mdelay(10); + serigo(31, 0xC1); + mdelay(10); + serigo(31, 0xD9); + serigo(31, 0xDF); + + sharp_state.display_on = TRUE; + } +} + +static int lcdc_sharp_panel_on(struct platform_device *pdev) +{ + if (!sharp_state.disp_initialized) { + lcdc_sharp_pdata->panel_config_gpio(1); + sharp_spi_init(); + sharp_disp_powerup(); + sharp_disp_on(); + sharp_state.disp_initialized = TRUE; + } + return 0; +} + +static int lcdc_sharp_panel_off(struct platform_device *pdev) +{ + if (sharp_state.disp_powered_up && sharp_state.display_on) { + serigo(4, 0x00); + mdelay(40); + serigo(31, 0xC1); + mdelay(40); + serigo(31, 0x00); + mdelay(100); + sharp_state.display_on = FALSE; + sharp_state.disp_initialized = FALSE; + } + return 0; +} + +static int __init sharp_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + lcdc_sharp_pdata = pdev->dev.platform_data; + return 0; + } + msm_fb_add_device(pdev); + return 0; +} + +static struct platform_driver this_driver = { + .probe = sharp_probe, + .driver = { + .name = "lcdc_sharp_wvga", + }, +}; + +static struct msm_fb_panel_data sharp_panel_data = { + .on = lcdc_sharp_panel_on, + .off = lcdc_sharp_panel_off, +}; + +static struct platform_device this_device = { + .name = "lcdc_sharp_wvga", + .id = 1, + .dev = { + .platform_data = &sharp_panel_data, + } +}; + +static int __init lcdc_sharp_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + if (msm_fb_detect_client("lcdc_sharp_wvga_pt")) + return 0; +#endif + + ret = platform_driver_register(&this_driver); + if (ret) + return ret; + + pinfo = &sharp_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 800; + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->clk_rate = 24500000; + pinfo->bl_max = 4; + pinfo->bl_min = 1; + + pinfo->lcdc.h_back_porch = 20; + pinfo->lcdc.h_front_porch = 10; + pinfo->lcdc.h_pulse_width = 10; + pinfo->lcdc.v_back_porch = 2; + pinfo->lcdc.v_front_porch = 2; + pinfo->lcdc.v_pulse_width = 2; + pinfo->lcdc.border_clr = 0; + pinfo->lcdc.underflow_clr = 0xff; + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + + return ret; +} + +module_init(lcdc_sharp_panel_init); diff --git a/drivers/staging/msm/lcdc_st15.c b/drivers/staging/msm/lcdc_st15.c new file mode 100644 index 000000000000..fed8278eb153 --- /dev/null +++ b/drivers/staging/msm/lcdc_st15.c @@ -0,0 +1,237 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/i2c.h> +#include <linux/delay.h> +#include "msm_fb.h" + +#define DEVICE_NAME "sii9022" +#define SII9022_DEVICE_ID 0xB0 + +struct sii9022_i2c_addr_data{ + u8 addr; + u8 data; +}; + +/* video mode data */ +static u8 video_mode_data[] = { + 0x00, + 0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02, +}; + +static u8 avi_io_format[] = { + 0x09, + 0x00, 0x00, +}; + +/* power state */ +static struct sii9022_i2c_addr_data regset0[] = { + { 0x60, 0x04 }, + { 0x63, 0x00 }, + { 0x1E, 0x00 }, +}; + +static u8 video_infoframe[] = { + 0x0C, + 0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00, + 0xE9, 0x02, 0x04, 0x01, 0x04, 0x06, +}; + +/* configure audio */ +static struct sii9022_i2c_addr_data regset1[] = { + { 0x26, 0x90 }, + { 0x20, 0x90 }, + { 0x1F, 0x80 }, + { 0x26, 0x80 }, + { 0x24, 0x02 }, + { 0x25, 0x0B }, + { 0xBC, 0x02 }, + { 0xBD, 0x24 }, + { 0xBE, 0x02 }, +}; + +/* enable audio */ +static u8 misc_infoframe[] = { + 0xBF, + 0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +/* set HDMI, active */ +static struct sii9022_i2c_addr_data regset2[] = { + { 0x1A, 0x01 }, + { 0x3D, 0x00 }, +}; + +static int send_i2c_data(struct i2c_client *client, + struct sii9022_i2c_addr_data *regset, + int size) +{ + int i; + int rc = 0; + + for (i = 0; i < size; i++) { + rc = i2c_smbus_write_byte_data( + client, + regset[i].addr, regset[i].data); + if (rc) + break; + } + return rc; +} + +static int hdmi_sii_enable(struct i2c_client *client) +{ + int rc; + int retries = 10; + int count; + + rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00); + if (rc) + goto enable_exit; + + do { + msleep(1); + rc = i2c_smbus_read_byte_data(client, 0x1B); + } while ((rc != SII9022_DEVICE_ID) && retries--); + + if (rc != SII9022_DEVICE_ID) + return -ENODEV; + + rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(video_mode_data); + rc = i2c_master_send(client, video_mode_data, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = i2c_smbus_write_byte_data(client, 0x08, 0x20); + if (rc) + goto enable_exit; + count = ARRAY_SIZE(avi_io_format); + rc = i2c_master_send(client, avi_io_format, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0)); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(video_infoframe); + rc = i2c_master_send(client, video_infoframe, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1)); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(misc_infoframe); + rc = i2c_master_send(client, misc_infoframe, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2)); + if (rc) + goto enable_exit; + + return 0; +enable_exit: + printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc); + return rc; +} + +static const struct i2c_device_id hmdi_sii_id[] = { + { DEVICE_NAME, 0 }, + { } +}; + +static int hdmi_sii_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C)) + return -ENODEV; + rc = hdmi_sii_enable(client); + return rc; +} + + +static struct i2c_driver hdmi_sii_i2c_driver = { + .driver = { + .name = DEVICE_NAME, + .owner = THIS_MODULE, + }, + .probe = hdmi_sii_probe, + .remove = __exit_p(hdmi_sii_remove), + .id_table = hmdi_sii_id, +}; + +static int __init lcdc_st15_init(void) +{ + int ret; + struct msm_panel_info pinfo; + + if (msm_fb_detect_client("lcdc_st15")) + return 0; + + pinfo.xres = 1366; + pinfo.yres = 768; + pinfo.type = LCDC_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.fb_num = 2; + pinfo.clk_rate = 74250000; + + pinfo.lcdc.h_back_porch = 120; + pinfo.lcdc.h_front_porch = 20; + pinfo.lcdc.h_pulse_width = 40; + pinfo.lcdc.v_back_porch = 25; + pinfo.lcdc.v_front_porch = 1; + pinfo.lcdc.v_pulse_width = 7; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) { + printk(KERN_ERR "%s: failed to register device!\n", __func__); + goto init_exit; + } + + ret = i2c_add_driver(&hdmi_sii_i2c_driver); + if (ret) + printk(KERN_ERR "%s: failed to add i2c driver\n", __func__); + +init_exit: + return ret; +} + +module_init(lcdc_st15_init); diff --git a/drivers/staging/msm/lcdc_st1_wxga.c b/drivers/staging/msm/lcdc_st1_wxga.c new file mode 100644 index 000000000000..73760019cf2e --- /dev/null +++ b/drivers/staging/msm/lcdc_st1_wxga.c @@ -0,0 +1,54 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" + +static int __init lcdc_st1_wxga_init(void) +{ + int ret; + struct msm_panel_info pinfo; + + if (msm_fb_detect_client("lcdc_st1_wxga")) + return 0; + + pinfo.xres = 1280; + pinfo.yres = 720; + pinfo.type = LCDC_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.fb_num = 2; + pinfo.clk_rate = 74250000; + + pinfo.lcdc.h_back_porch = 124; + pinfo.lcdc.h_front_porch = 110; + pinfo.lcdc.h_pulse_width = 136; + pinfo.lcdc.v_back_porch = 19; + pinfo.lcdc.v_front_porch = 5; + pinfo.lcdc.v_pulse_width = 6; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(lcdc_st1_wxga_init); diff --git a/drivers/staging/msm/lcdc_toshiba_wvga_pt.c b/drivers/staging/msm/lcdc_toshiba_wvga_pt.c new file mode 100644 index 000000000000..864d7c18913d --- /dev/null +++ b/drivers/staging/msm/lcdc_toshiba_wvga_pt.c @@ -0,0 +1,374 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <mach/gpio.h> +#include <mach/pmic.h> +#include "msm_fb.h" + +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM +#include "mddihosti.h" +#endif + +static int spi_cs; +static int spi_sclk; +static int spi_mosi; +static int spi_miso; + +struct toshiba_state_type{ + boolean disp_initialized; + boolean display_on; + boolean disp_powered_up; +}; + +static struct toshiba_state_type toshiba_state = { 0 }; +static struct msm_panel_common_pdata *lcdc_toshiba_pdata; + +static void toshiba_spi_write_byte(char dc, uint8 data) +{ + uint32 bit; + int bnum; + + gpio_set_value(spi_sclk, 0); /* clk low */ + /* dc: 0 for command, 1 for parameter */ + gpio_set_value(spi_mosi, dc); + udelay(1); /* at least 20 ns */ + gpio_set_value(spi_sclk, 1); /* clk high */ + udelay(1); /* at least 20 ns */ + bnum = 8; /* 8 data bits */ + bit = 0x80; + while (bnum) { + gpio_set_value(spi_sclk, 0); /* clk low */ + if (data & bit) + gpio_set_value(spi_mosi, 1); + else + gpio_set_value(spi_mosi, 0); + udelay(1); + gpio_set_value(spi_sclk, 1); /* clk high */ + udelay(1); + bit >>= 1; + bnum--; + } +} + +static void toshiba_spi_write(char cmd, uint32 data, int num) +{ + char *bp; + + gpio_set_value(spi_cs, 1); /* cs high */ + + /* command byte first */ + toshiba_spi_write_byte(0, cmd); + + /* followed by parameter bytes */ + if (num) { + bp = (char *)&data;; + bp += (num - 1); + while (num) { + toshiba_spi_write_byte(1, *bp); + num--; + bp--; + } + } + + gpio_set_value(spi_cs, 0); /* cs low */ + udelay(1); +} + +void toshiba_spi_read_bytes(char cmd, uint32 *data, int num) +{ + uint32 dbit, bits; + int bnum; + + gpio_set_value(spi_cs, 1); /* cs high */ + + /* command byte first */ + toshiba_spi_write_byte(0, cmd); + + if (num > 1) { + /* extra dc bit */ + gpio_set_value(spi_sclk, 0); /* clk low */ + udelay(1); + dbit = gpio_get_value(spi_miso);/* dc bit */ + udelay(1); + gpio_set_value(spi_sclk, 1); /* clk high */ + } + + /* followed by data bytes */ + bnum = num * 8; /* number of bits */ + bits = 0; + while (bnum) { + bits <<= 1; + gpio_set_value(spi_sclk, 0); /* clk low */ + udelay(1); + dbit = gpio_get_value(spi_miso); + udelay(1); + gpio_set_value(spi_sclk, 1); /* clk high */ + bits |= dbit; + bnum--; + } + + *data = bits; + + udelay(1); + gpio_set_value(spi_cs, 0); /* cs low */ + udelay(1); +} + +static void spi_pin_assign(void) +{ + /* Setting the Default GPIO's */ + spi_sclk = *(lcdc_toshiba_pdata->gpio_num); + spi_cs = *(lcdc_toshiba_pdata->gpio_num + 1); + spi_mosi = *(lcdc_toshiba_pdata->gpio_num + 2); + spi_miso = *(lcdc_toshiba_pdata->gpio_num + 3); +} + +static void toshiba_disp_powerup(void) +{ + if (!toshiba_state.disp_powered_up && !toshiba_state.display_on) { + /* Reset the hardware first */ + /* Include DAC power up implementation here */ + toshiba_state.disp_powered_up = TRUE; + } +} + +static void toshiba_disp_on(void) +{ + uint32 data; + + gpio_set_value(spi_cs, 0); /* low */ + gpio_set_value(spi_sclk, 1); /* high */ + gpio_set_value(spi_mosi, 0); + gpio_set_value(spi_miso, 0); + + if (toshiba_state.disp_powered_up && !toshiba_state.display_on) { + toshiba_spi_write(0, 0, 0); + mdelay(7); + toshiba_spi_write(0, 0, 0); + mdelay(7); + toshiba_spi_write(0, 0, 0); + mdelay(7); + toshiba_spi_write(0xba, 0x11, 1); + toshiba_spi_write(0x36, 0x00, 1); + mdelay(1); + toshiba_spi_write(0x3a, 0x60, 1); + toshiba_spi_write(0xb1, 0x5d, 1); + mdelay(1); + toshiba_spi_write(0xb2, 0x33, 1); + toshiba_spi_write(0xb3, 0x22, 1); + mdelay(1); + toshiba_spi_write(0xb4, 0x02, 1); + toshiba_spi_write(0xb5, 0x1e, 1); /* vcs -- adjust brightness */ + mdelay(1); + toshiba_spi_write(0xb6, 0x27, 1); + toshiba_spi_write(0xb7, 0x03, 1); + mdelay(1); + toshiba_spi_write(0xb9, 0x24, 1); + toshiba_spi_write(0xbd, 0xa1, 1); + mdelay(1); + toshiba_spi_write(0xbb, 0x00, 1); + toshiba_spi_write(0xbf, 0x01, 1); + mdelay(1); + toshiba_spi_write(0xbe, 0x00, 1); + toshiba_spi_write(0xc0, 0x11, 1); + mdelay(1); + toshiba_spi_write(0xc1, 0x11, 1); + toshiba_spi_write(0xc2, 0x11, 1); + mdelay(1); + toshiba_spi_write(0xc3, 0x3232, 2); + mdelay(1); + toshiba_spi_write(0xc4, 0x3232, 2); + mdelay(1); + toshiba_spi_write(0xc5, 0x3232, 2); + mdelay(1); + toshiba_spi_write(0xc6, 0x3232, 2); + mdelay(1); + toshiba_spi_write(0xc7, 0x6445, 2); + mdelay(1); + toshiba_spi_write(0xc8, 0x44, 1); + toshiba_spi_write(0xc9, 0x52, 1); + mdelay(1); + toshiba_spi_write(0xca, 0x00, 1); + mdelay(1); + toshiba_spi_write(0xec, 0x02a4, 2); /* 0x02a4 */ + mdelay(1); + toshiba_spi_write(0xcf, 0x01, 1); + mdelay(1); + toshiba_spi_write(0xd0, 0xc003, 2); /* c003 */ + mdelay(1); + toshiba_spi_write(0xd1, 0x01, 1); + mdelay(1); + toshiba_spi_write(0xd2, 0x0028, 2); + mdelay(1); + toshiba_spi_write(0xd3, 0x0028, 2); + mdelay(1); + toshiba_spi_write(0xd4, 0x26a4, 2); + mdelay(1); + toshiba_spi_write(0xd5, 0x20, 1); + mdelay(1); + toshiba_spi_write(0xef, 0x3200, 2); + mdelay(32); + toshiba_spi_write(0xbc, 0x80, 1); /* wvga pass through */ + toshiba_spi_write(0x3b, 0x00, 1); + mdelay(1); + toshiba_spi_write(0xb0, 0x16, 1); + mdelay(1); + toshiba_spi_write(0xb8, 0xfff5, 2); + mdelay(1); + toshiba_spi_write(0x11, 0, 0); + mdelay(5); + toshiba_spi_write(0x29, 0, 0); + mdelay(5); + toshiba_state.display_on = TRUE; + } + + data = 0; + toshiba_spi_read_bytes(0x04, &data, 3); + printk(KERN_INFO "toshiba_disp_on: id=%x\n", data); + +} + +static int lcdc_toshiba_panel_on(struct platform_device *pdev) +{ + if (!toshiba_state.disp_initialized) { + /* Configure reset GPIO that drives DAC */ + if (lcdc_toshiba_pdata->panel_config_gpio) + lcdc_toshiba_pdata->panel_config_gpio(1); + toshiba_disp_powerup(); + toshiba_disp_on(); + toshiba_state.disp_initialized = TRUE; + } + return 0; +} + +static int lcdc_toshiba_panel_off(struct platform_device *pdev) +{ + if (toshiba_state.disp_powered_up && toshiba_state.display_on) { + /* Main panel power off (Deep standby in) */ + + toshiba_spi_write(0x28, 0, 0); /* display off */ + mdelay(1); + toshiba_spi_write(0xb8, 0x8002, 2); /* output control */ + mdelay(1); + toshiba_spi_write(0x10, 0x00, 1); /* sleep mode in */ + mdelay(85); /* wait 85 msec */ + toshiba_spi_write(0xb0, 0x00, 1); /* deep standby in */ + mdelay(1); + if (lcdc_toshiba_pdata->panel_config_gpio) + lcdc_toshiba_pdata->panel_config_gpio(0); + toshiba_state.display_on = FALSE; + toshiba_state.disp_initialized = FALSE; + } + return 0; +} + +static void lcdc_toshiba_set_backlight(struct msm_fb_data_type *mfd) +{ + int bl_level; + int ret = -EPERM; + + bl_level = mfd->bl_level; + ret = pmic_set_led_intensity(LED_LCD, bl_level); + + if (ret) + printk(KERN_WARNING "%s: can't set lcd backlight!\n", + __func__); +} + +static int __init toshiba_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + lcdc_toshiba_pdata = pdev->dev.platform_data; + spi_pin_assign(); + return 0; + } + msm_fb_add_device(pdev); + return 0; +} + +static struct platform_driver this_driver = { + .probe = toshiba_probe, + .driver = { + .name = "lcdc_toshiba_wvga", + }, +}; + +static struct msm_fb_panel_data toshiba_panel_data = { + .on = lcdc_toshiba_panel_on, + .off = lcdc_toshiba_panel_off, + .set_backlight = lcdc_toshiba_set_backlight, +}; + +static struct platform_device this_device = { + .name = "lcdc_toshiba_wvga", + .id = 1, + .dev = { + .platform_data = &toshiba_panel_data, + } +}; + +static int __init lcdc_toshiba_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM + if (mddi_get_client_id() != 0) + return 0; + + ret = msm_fb_detect_client("lcdc_toshiba_wvga_pt"); + if (ret) + return 0; + +#endif + + ret = platform_driver_register(&this_driver); + if (ret) + return ret; + + pinfo = &toshiba_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 800; + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + /* 30Mhz mdp_lcdc_pclk and mdp_lcdc_pad_pcl */ + pinfo->clk_rate = 27648000; + pinfo->bl_max = 15; + pinfo->bl_min = 1; + + pinfo->lcdc.h_back_porch = 184; /* hsw = 8 + hbp=184 */ + pinfo->lcdc.h_front_porch = 4; + pinfo->lcdc.h_pulse_width = 8; + pinfo->lcdc.v_back_porch = 2; /* vsw=1 + vbp = 2 */ + pinfo->lcdc.v_front_porch = 3; + pinfo->lcdc.v_pulse_width = 1; + pinfo->lcdc.border_clr = 0; /* blk */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + + return ret; +} + +device_initcall(lcdc_toshiba_panel_init); diff --git a/drivers/staging/msm/lcdc_wxga.c b/drivers/staging/msm/lcdc_wxga.c new file mode 100644 index 000000000000..202c92c0ef54 --- /dev/null +++ b/drivers/staging/msm/lcdc_wxga.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" + +static int __init lcdc_wxga_init(void) +{ + int ret; + struct msm_panel_info pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + if (msm_fb_detect_client("lcdc_wxga")) + return 0; +#endif + + pinfo.xres = 1280; + pinfo.yres = 720; + pinfo.type = LCDC_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.fb_num = 2; + pinfo.clk_rate = 74250000; + + pinfo.lcdc.h_back_porch = 124; + pinfo.lcdc.h_front_porch = 110; + pinfo.lcdc.h_pulse_width = 136; + pinfo.lcdc.v_back_porch = 19; + pinfo.lcdc.v_front_porch = 5; + pinfo.lcdc.v_pulse_width = 6; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(lcdc_wxga_init); diff --git a/drivers/staging/msm/logo.c b/drivers/staging/msm/logo.c new file mode 100644 index 000000000000..7272765f48cd --- /dev/null +++ b/drivers/staging/msm/logo.c @@ -0,0 +1,98 @@ +/* drivers/video/msm/logo.c + * + * Show Logo in RLE 565 format + * + * Copyright (C) 2008 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/module.h> +#include <linux/types.h> +#include <linux/fb.h> +#include <linux/vt_kern.h> +#include <linux/unistd.h> +#include <linux/syscalls.h> + +#include <linux/irq.h> +#include <asm/system.h> + +#define fb_width(fb) ((fb)->var.xres) +#define fb_height(fb) ((fb)->var.yres) +#define fb_size(fb) ((fb)->var.xres * (fb)->var.yres * 2) + +static void memset16(void *_ptr, unsigned short val, unsigned count) +{ + unsigned short *ptr = _ptr; + count >>= 1; + while (count--) + *ptr++ = val; +} + +/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */ +int load_565rle_image(char *filename) +{ + struct fb_info *info; + int fd, err = 0; + unsigned count, max; + unsigned short *data, *bits, *ptr; + + info = registered_fb[0]; + if (!info) { + printk(KERN_WARNING "%s: Can not access framebuffer\n", + __func__); + return -ENODEV; + } + + fd = sys_open(filename, O_RDONLY, 0); + if (fd < 0) { + printk(KERN_WARNING "%s: Can not open %s\n", + __func__, filename); + return -ENOENT; + } + count = (unsigned)sys_lseek(fd, (off_t)0, 2); + if (count == 0) { + sys_close(fd); + err = -EIO; + goto err_logo_close_file; + } + sys_lseek(fd, (off_t)0, 0); + data = kmalloc(count, GFP_KERNEL); + if (!data) { + printk(KERN_WARNING "%s: Can not alloc data\n", __func__); + err = -ENOMEM; + goto err_logo_close_file; + } + if ((unsigned)sys_read(fd, (char *)data, count) != count) { + err = -EIO; + goto err_logo_free_data; + } + + max = fb_width(info) * fb_height(info); + ptr = data; + bits = (unsigned short *)(info->screen_base); + while (count > 3) { + unsigned n = ptr[0]; + if (n > max) + break; + memset16(bits, ptr[1], n << 1); + bits += n; + max -= n; + ptr += 2; + count -= 4; + } + +err_logo_free_data: + kfree(data); +err_logo_close_file: + sys_close(fd); + return err; +} +EXPORT_SYMBOL(load_565rle_image); diff --git a/drivers/staging/msm/mddi.c b/drivers/staging/msm/mddi.c new file mode 100644 index 000000000000..132eb1adff16 --- /dev/null +++ b/drivers/staging/msm/mddi.c @@ -0,0 +1,375 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <asm/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <linux/clk.h> +#include <linux/platform_device.h> + +#include "msm_fb.h" +#include "mddihosti.h" +#include "mddihost.h" +#include <mach/gpio.h> +#include <mach/clk.h> + +static int mddi_probe(struct platform_device *pdev); +static int mddi_remove(struct platform_device *pdev); + +static int mddi_off(struct platform_device *pdev); +static int mddi_on(struct platform_device *pdev); + +static int mddi_suspend(struct platform_device *pdev, pm_message_t state); +static int mddi_resume(struct platform_device *pdev); + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mddi_early_suspend(struct early_suspend *h); +static void mddi_early_resume(struct early_suspend *h); +#endif + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; +static struct clk *mddi_clk; +static struct clk *mddi_pclk; +static struct mddi_platform_data *mddi_pdata; + +static struct platform_driver mddi_driver = { + .probe = mddi_probe, + .remove = mddi_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND +#ifdef CONFIG_PM + .suspend = mddi_suspend, + .resume = mddi_resume, +#endif +#endif + .suspend_late = NULL, + .resume_early = NULL, + .shutdown = NULL, + .driver = { + .name = "mddi", + }, +}; + +extern int int_mddi_pri_flag; + +static int mddi_off(struct platform_device *pdev) +{ + int ret = 0; + + ret = panel_next_off(pdev); + + if (mddi_pdata && mddi_pdata->mddi_power_save) + mddi_pdata->mddi_power_save(0); + + return ret; +} + +static int mddi_on(struct platform_device *pdev) +{ + int ret = 0; + u32 clk_rate; + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (mddi_pdata && mddi_pdata->mddi_power_save) + mddi_pdata->mddi_power_save(1); + + clk_rate = mfd->fbi->var.pixclock; + clk_rate = min(clk_rate, mfd->panel_info.clk_max); + + if (mddi_pdata && + mddi_pdata->mddi_sel_clk && + mddi_pdata->mddi_sel_clk(&clk_rate)) + printk(KERN_ERR + "%s: can't select mddi io clk targate rate = %d\n", + __func__, clk_rate); + + if (clk_set_min_rate(mddi_clk, clk_rate) < 0) + printk(KERN_ERR "%s: clk_set_min_rate failed\n", + __func__); + + ret = panel_next_on(pdev); + + return ret; +} + +static int mddi_resource_initialized; + +static int mddi_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc; + resource_size_t size ; + u32 clk_rate; + + if ((pdev->id == 0) && (pdev->num_resources >= 0)) { + mddi_pdata = pdev->dev.platform_data; + + size = resource_size(&pdev->resource[0]); + msm_pmdh_base = ioremap(pdev->resource[0].start, size); + + MSM_FB_INFO("primary mddi base phy_addr = 0x%x virt = 0x%x\n", + pdev->resource[0].start, (int) msm_pmdh_base); + + if (unlikely(!msm_pmdh_base)) + return -ENOMEM; + + if (mddi_pdata && mddi_pdata->mddi_power_save) + mddi_pdata->mddi_power_save(1); + + mddi_resource_initialized = 1; + return 0; + } + + if (!mddi_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_LCD; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "mddi_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = mdp_dev->dev.platform_data; + pdata->on = mddi_on; + pdata->off = mddi_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + mfd->fb_imgType = MDP_RGB_565; + + clk_rate = mfd->panel_info.clk_max; + if (mddi_pdata && + mddi_pdata->mddi_sel_clk && + mddi_pdata->mddi_sel_clk(&clk_rate)) + printk(KERN_ERR + "%s: can't select mddi io clk targate rate = %d\n", + __func__, clk_rate); + + if (clk_set_max_rate(mddi_clk, clk_rate) < 0) + printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__); + mfd->panel_info.clk_rate = mfd->panel_info.clk_min; + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto mddi_probe_err; + + pdev_list[pdev_list_cnt++] = pdev; + +#ifdef CONFIG_HAS_EARLYSUSPEND + mfd->mddi_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; + mfd->mddi_early_suspend.suspend = mddi_early_suspend; + mfd->mddi_early_suspend.resume = mddi_early_resume; + register_early_suspend(&mfd->mddi_early_suspend); +#endif + + return 0; + +mddi_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int mddi_pad_ctrl; +static int mddi_power_locked; +static int mddi_is_in_suspend; + +void mddi_disable(int lock) +{ + mddi_host_type host_idx = MDDI_HOST_PRIM; + + if (mddi_power_locked) + return; + + if (lock) + mddi_power_locked = 1; + + if (mddi_host_timer.function) + del_timer_sync(&mddi_host_timer); + + mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL); + mddi_host_reg_out(PAD_CTL, 0x0); + + if (clk_set_min_rate(mddi_clk, 0) < 0) + printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__); + + clk_disable(mddi_clk); + if (mddi_pclk) + clk_disable(mddi_pclk); + disable_irq(INT_MDDI_PRI); + + if (mddi_pdata && mddi_pdata->mddi_power_save) + mddi_pdata->mddi_power_save(0); +} + +static int mddi_suspend(struct platform_device *pdev, pm_message_t state) +{ + if (mddi_is_in_suspend) + return 0; + + mddi_is_in_suspend = 1; + mddi_disable(0); + return 0; +} + +static int mddi_resume(struct platform_device *pdev) +{ + mddi_host_type host_idx = MDDI_HOST_PRIM; + + if (!mddi_is_in_suspend) + return 0; + + mddi_is_in_suspend = 0; + + if (mddi_power_locked) + return 0; + + enable_irq(INT_MDDI_PRI); + clk_enable(mddi_clk); + if (mddi_pclk) + clk_enable(mddi_pclk); + mddi_host_reg_out(PAD_CTL, mddi_pad_ctrl); + + if (mddi_host_timer.function) + mddi_host_timer_service(0); + + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mddi_early_suspend(struct early_suspend *h) +{ + pm_message_t state; + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + mddi_early_suspend); + + state.event = PM_EVENT_SUSPEND; + mddi_suspend(mfd->pdev, state); +} + +static void mddi_early_resume(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + mddi_early_suspend); + mddi_resume(mfd->pdev); +} +#endif + +static int mddi_remove(struct platform_device *pdev) +{ + if (mddi_host_timer.function) + del_timer_sync(&mddi_host_timer); + + iounmap(msm_pmdh_base); + + return 0; +} + +static int mddi_register_driver(void) +{ + return platform_driver_register(&mddi_driver); +} + +static int __init mddi_driver_init(void) +{ + int ret; + + mddi_clk = clk_get(NULL, "mddi_clk"); + if (IS_ERR(mddi_clk)) { + printk(KERN_ERR "can't find mddi_clk \n"); + return PTR_ERR(mddi_clk); + } + clk_enable(mddi_clk); + + mddi_pclk = clk_get(NULL, "mddi_pclk"); + if (IS_ERR(mddi_pclk)) + mddi_pclk = NULL; + else + clk_enable(mddi_pclk); + + ret = mddi_register_driver(); + if (ret) { + clk_disable(mddi_clk); + clk_put(mddi_clk); + if (mddi_pclk) { + clk_disable(mddi_pclk); + clk_put(mddi_pclk); + } + printk(KERN_ERR "mddi_register_driver() failed!\n"); + return ret; + } + + mddi_init(); + + return ret; +} + +module_init(mddi_driver_init); diff --git a/drivers/staging/msm/mddi_ext.c b/drivers/staging/msm/mddi_ext.c new file mode 100644 index 000000000000..c0c168c7199d --- /dev/null +++ b/drivers/staging/msm/mddi_ext.c @@ -0,0 +1,320 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <asm/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <linux/clk.h> +#include <mach/clk.h> +#include <linux/platform_device.h> + +#include "msm_fb.h" +#include "mddihosti.h" + +static int mddi_ext_probe(struct platform_device *pdev); +static int mddi_ext_remove(struct platform_device *pdev); + +static int mddi_ext_off(struct platform_device *pdev); +static int mddi_ext_on(struct platform_device *pdev); + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state); +static int mddi_ext_resume(struct platform_device *pdev); + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mddi_ext_early_suspend(struct early_suspend *h); +static void mddi_ext_early_resume(struct early_suspend *h); +#endif + +static struct platform_driver mddi_ext_driver = { + .probe = mddi_ext_probe, + .remove = mddi_ext_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND +#ifdef CONFIG_PM + .suspend = mddi_ext_suspend, + .resume = mddi_ext_resume, +#endif +#endif + .resume_early = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "mddi_ext", + }, +}; + +static struct clk *mddi_ext_clk; +static struct mddi_platform_data *mddi_ext_pdata; + +extern int int_mddi_ext_flag; + +static int mddi_ext_off(struct platform_device *pdev) +{ + int ret = 0; + + ret = panel_next_off(pdev); + mddi_host_stop_ext_display(); + + return ret; +} + +static int mddi_ext_on(struct platform_device *pdev) +{ + int ret = 0; + u32 clk_rate; + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + clk_rate = mfd->fbi->var.pixclock; + clk_rate = min(clk_rate, mfd->panel_info.clk_max); + + if (mddi_ext_pdata && + mddi_ext_pdata->mddi_sel_clk && + mddi_ext_pdata->mddi_sel_clk(&clk_rate)) + printk(KERN_ERR + "%s: can't select mddi io clk targate rate = %d\n", + __func__, clk_rate); + + if (clk_set_min_rate(mddi_ext_clk, clk_rate) < 0) + printk(KERN_ERR "%s: clk_set_min_rate failed\n", + __func__); + + mddi_host_start_ext_display(); + ret = panel_next_on(pdev); + + return ret; +} + +static int mddi_ext_resource_initialized; + +static int mddi_ext_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc; + resource_size_t size ; + u32 clk_rate; + + if ((pdev->id == 0) && (pdev->num_resources >= 0)) { + mddi_ext_pdata = pdev->dev.platform_data; + + size = resource_size(&pdev->resource[0]); + msm_emdh_base = ioremap(pdev->resource[0].start, size); + + MSM_FB_INFO("external mddi base address = 0x%x\n", + pdev->resource[0].start); + + if (unlikely(!msm_emdh_base)) + return -ENOMEM; + + mddi_ext_resource_initialized = 1; + return 0; + } + + if (!mddi_ext_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_EXT_MDDI; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "mddi_ext_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = mdp_dev->dev.platform_data; + pdata->on = mddi_ext_on; + pdata->off = mddi_ext_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + mfd->fb_imgType = MDP_RGB_565; + + clk_rate = mfd->panel_info.clk_max; + if (mddi_ext_pdata && + mddi_ext_pdata->mddi_sel_clk && + mddi_ext_pdata->mddi_sel_clk(&clk_rate)) + printk(KERN_ERR + "%s: can't select mddi io clk targate rate = %d\n", + __func__, clk_rate); + + if (clk_set_max_rate(mddi_ext_clk, clk_rate) < 0) + printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__); + mfd->panel_info.clk_rate = mfd->panel_info.clk_min; + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto mddi_ext_probe_err; + + pdev_list[pdev_list_cnt++] = pdev; + +#ifdef CONFIG_HAS_EARLYSUSPEND + mfd->mddi_ext_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; + mfd->mddi_ext_early_suspend.suspend = mddi_ext_early_suspend; + mfd->mddi_ext_early_suspend.resume = mddi_ext_early_resume; + register_early_suspend(&mfd->mddi_ext_early_suspend); +#endif + + return 0; + +mddi_ext_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int mddi_ext_is_in_suspend; + +static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state) +{ + if (mddi_ext_is_in_suspend) + return 0; + + mddi_ext_is_in_suspend = 1; + + if (clk_set_min_rate(mddi_ext_clk, 0) < 0) + printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__); + + clk_disable(mddi_ext_clk); + disable_irq(INT_MDDI_EXT); + + return 0; +} + +static int mddi_ext_resume(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mddi_ext_is_in_suspend) + return 0; + + mddi_ext_is_in_suspend = 0; + enable_irq(INT_MDDI_EXT); + + clk_enable(mddi_ext_clk); + + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mddi_ext_early_suspend(struct early_suspend *h) +{ + pm_message_t state; + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + mddi_ext_early_suspend); + + state.event = PM_EVENT_SUSPEND; + mddi_ext_suspend(mfd->pdev, state); +} + +static void mddi_ext_early_resume(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + mddi_ext_early_suspend); + mddi_ext_resume(mfd->pdev); +} +#endif + +static int mddi_ext_remove(struct platform_device *pdev) +{ + iounmap(msm_emdh_base); + return 0; +} + +static int mddi_ext_register_driver(void) +{ + return platform_driver_register(&mddi_ext_driver); +} + +static int __init mddi_ext_driver_init(void) +{ + int ret; + + mddi_ext_clk = clk_get(NULL, "emdh_clk"); + if (IS_ERR(mddi_ext_clk)) { + printk(KERN_ERR "can't find emdh_clk\n"); + return PTR_ERR(mddi_ext_clk); + } + clk_enable(mddi_ext_clk); + + ret = mddi_ext_register_driver(); + if (ret) { + clk_disable(mddi_ext_clk); + clk_put(mddi_ext_clk); + printk(KERN_ERR "mddi_ext_register_driver() failed!\n"); + return ret; + } + mddi_init(); + + return ret; +} + +module_init(mddi_ext_driver_init); diff --git a/drivers/staging/msm/mddi_ext_lcd.c b/drivers/staging/msm/mddi_ext_lcd.c new file mode 100644 index 000000000000..502e80d17ec7 --- /dev/null +++ b/drivers/staging/msm/mddi_ext_lcd.c @@ -0,0 +1,91 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +static int mddi_ext_lcd_on(struct platform_device *pdev); +static int mddi_ext_lcd_off(struct platform_device *pdev); + +static int mddi_ext_lcd_on(struct platform_device *pdev) +{ + return 0; +} + +static int mddi_ext_lcd_off(struct platform_device *pdev) +{ + return 0; +} + +static int __init mddi_ext_lcd_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mddi_ext_lcd_probe, + .driver = { + .name = "extmddi_svga", + }, +}; + +static struct msm_fb_panel_data mddi_ext_lcd_panel_data = { + .panel_info.xres = 800, + .panel_info.yres = 600, + .panel_info.type = EXT_MDDI_PANEL, + .panel_info.pdest = DISPLAY_1, + .panel_info.wait_cycle = 0, + .panel_info.bpp = 18, + .panel_info.fb_num = 2, + .panel_info.clk_rate = 122880000, + .panel_info.clk_min = 120000000, + .panel_info.clk_max = 125000000, + .on = mddi_ext_lcd_on, + .off = mddi_ext_lcd_off, +}; + +static struct platform_device this_device = { + .name = "extmddi_svga", + .id = 0, + .dev = { + .platform_data = &mddi_ext_lcd_panel_data, + } +}; + +static int __init mddi_ext_lcd_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &mddi_ext_lcd_panel_data.panel_info; + pinfo->lcd.vsync_enable = FALSE; + pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(mddi_ext_lcd_init); diff --git a/drivers/staging/msm/mddi_prism.c b/drivers/staging/msm/mddi_prism.c new file mode 100644 index 000000000000..489d40405a5f --- /dev/null +++ b/drivers/staging/msm/mddi_prism.c @@ -0,0 +1,114 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +static int prism_lcd_on(struct platform_device *pdev); +static int prism_lcd_off(struct platform_device *pdev); + +static int prism_lcd_on(struct platform_device *pdev) +{ + /* Set the MDP pixel data attributes for Primary Display */ + mddi_host_write_pix_attr_reg(0x00C3); + + return 0; +} + +static int prism_lcd_off(struct platform_device *pdev) +{ + return 0; +} + +static int __init prism_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = prism_probe, + .driver = { + .name = "mddi_prism_wvga", + }, +}; + +static struct msm_fb_panel_data prism_panel_data = { + .on = prism_lcd_on, + .off = prism_lcd_off, +}; + +static struct platform_device this_device = { + .name = "mddi_prism_wvga", + .id = 0, + .dev = { + .platform_data = &prism_panel_data, + } +}; + +static int __init prism_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; + + ret = msm_fb_detect_client("mddi_prism_wvga"); + if (ret == -ENODEV) + return 0; + + if (ret) { + id = mddi_get_client_id(); + + if (((id >> 16) != 0x4474) || ((id & 0xffff) == 0x8960)) + return 0; + } +#endif + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &prism_panel_data.panel_info; + pinfo->xres = 800; + pinfo->yres = 480; + pinfo->type = MDDI_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->clk_rate = 153600000; + pinfo->clk_min = 150000000; + pinfo->clk_max = 160000000; + pinfo->lcd.vsync_enable = TRUE; + pinfo->lcd.refx100 = 6050; + pinfo->lcd.v_back_porch = 23; + pinfo->lcd.v_front_porch = 20; + pinfo->lcd.v_pulse_width = 105; + pinfo->lcd.hw_vsync_mode = TRUE; + pinfo->lcd.vsync_notifier_period = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(prism_init); diff --git a/drivers/staging/msm/mddi_sharp.c b/drivers/staging/msm/mddi_sharp.c new file mode 100644 index 000000000000..1da1be4052d0 --- /dev/null +++ b/drivers/staging/msm/mddi_sharp.c @@ -0,0 +1,892 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +#define SHARP_QVGA_PRIM 1 +#define SHARP_128X128_SECD 2 + +extern uint32 mddi_host_core_version; +static boolean mddi_debug_prim_wait = FALSE; +static boolean mddi_sharp_vsync_wake = TRUE; +static boolean mddi_sharp_monitor_refresh_value = TRUE; +static boolean mddi_sharp_report_refresh_measurements = FALSE; +static uint32 mddi_sharp_rows_per_second = 13830; /* 5200000/376 */ +static uint32 mddi_sharp_rows_per_refresh = 338; +static uint32 mddi_sharp_usecs_per_refresh = 24440; /* (376+338)/5200000 */ +static boolean mddi_sharp_debug_60hz_refresh = FALSE; + +extern mddi_gpio_info_type mddi_gpio; +extern boolean mddi_vsync_detect_enabled; +static msm_fb_vsync_handler_type mddi_sharp_vsync_handler; +static void *mddi_sharp_vsync_handler_arg; +static uint16 mddi_sharp_vsync_attempts; + +static void mddi_sharp_prim_lcd_init(void); +static void mddi_sharp_sub_lcd_init(void); +static void mddi_sharp_lcd_set_backlight(struct msm_fb_data_type *mfd); +static void mddi_sharp_vsync_set_handler(msm_fb_vsync_handler_type handler, + void *); +static void mddi_sharp_lcd_vsync_detected(boolean detected); +static struct msm_panel_common_pdata *mddi_sharp_pdata; + +#define REG_SYSCTL 0x0000 +#define REG_INTR 0x0006 +#define REG_CLKCNF 0x000C +#define REG_CLKDIV1 0x000E +#define REG_CLKDIV2 0x0010 + +#define REG_GIOD 0x0040 +#define REG_GIOA 0x0042 + +#define REG_AGM 0x010A +#define REG_FLFT 0x0110 +#define REG_FRGT 0x0112 +#define REG_FTOP 0x0114 +#define REG_FBTM 0x0116 +#define REG_FSTRX 0x0118 +#define REG_FSTRY 0x011A +#define REG_VRAM 0x0202 +#define REG_SSDCTL 0x0330 +#define REG_SSD0 0x0332 +#define REG_PSTCTL1 0x0400 +#define REG_PSTCTL2 0x0402 +#define REG_PTGCTL 0x042A +#define REG_PTHP 0x042C +#define REG_PTHB 0x042E +#define REG_PTHW 0x0430 +#define REG_PTHF 0x0432 +#define REG_PTVP 0x0434 +#define REG_PTVB 0x0436 +#define REG_PTVW 0x0438 +#define REG_PTVF 0x043A +#define REG_VBLKS 0x0458 +#define REG_VBLKE 0x045A +#define REG_SUBCTL 0x0700 +#define REG_SUBTCMD 0x0702 +#define REG_SUBTCMDD 0x0704 +#define REG_REVBYTE 0x0A02 +#define REG_REVCNT 0x0A04 +#define REG_REVATTR 0x0A06 +#define REG_REVFMT 0x0A08 + +#define SHARP_SUB_UNKNOWN 0xffffffff +#define SHARP_SUB_HYNIX 1 +#define SHARP_SUB_ROHM 2 + +static uint32 sharp_subpanel_type = SHARP_SUB_UNKNOWN; + +static void sub_through_write(int sub_rs, uint32 sub_data) +{ + mddi_queue_register_write(REG_SUBTCMDD, sub_data, FALSE, 0); + + /* CS=1,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, FALSE, 0); + + /* CS=0,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0); + + /* CS=0,RD=1,WE=0,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0004 | sub_rs, FALSE, 0); + + /* CS=0,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0); + + /* CS=1,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, TRUE, 0); +} + +static uint32 sub_through_read(int sub_rs) +{ + uint32 sub_data; + + /* CS=1,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, FALSE, 0); + + /* CS=0,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0); + + /* CS=0,RD=1,WE=0,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0002 | sub_rs, TRUE, 0); + + mddi_queue_register_read(REG_SUBTCMDD, &sub_data, TRUE, 0); + + /* CS=0,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0); + + /* CS=1,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, TRUE, 0); + + return sub_data; +} + +static void serigo(uint32 ssd) +{ + uint32 ssdctl; + + mddi_queue_register_read(REG_SSDCTL, &ssdctl, TRUE, 0); + ssdctl = ((ssdctl & 0xE7) | 0x02); + + mddi_queue_register_write(REG_SSD0, ssd, FALSE, 0); + mddi_queue_register_write(REG_SSDCTL, ssdctl, TRUE, 0); + + do { + mddi_queue_register_read(REG_SSDCTL, &ssdctl, TRUE, 0); + } while ((ssdctl & 0x0002) != 0); + + if (mddi_debug_prim_wait) + mddi_wait(2); +} + +static void mddi_sharp_lcd_powerdown(void) +{ + serigo(0x0131); + serigo(0x0300); + mddi_wait(40); + serigo(0x0135); + mddi_wait(20); + serigo(0x2122); + mddi_wait(20); + serigo(0x0201); + mddi_wait(20); + serigo(0x2100); + mddi_wait(20); + serigo(0x2000); + mddi_wait(20); + + mddi_queue_register_write(REG_PSTCTL1, 0x1, TRUE, 0); + mddi_wait(100); + mddi_queue_register_write(REG_PSTCTL1, 0x0, TRUE, 0); + mddi_wait(2); + mddi_queue_register_write(REG_SYSCTL, 0x1, TRUE, 0); + mddi_wait(2); + mddi_queue_register_write(REG_CLKDIV1, 0x3, TRUE, 0); + mddi_wait(2); + mddi_queue_register_write(REG_SSDCTL, 0x0000, TRUE, 0); /* SSDRESET */ + mddi_queue_register_write(REG_SYSCTL, 0x0, TRUE, 0); + mddi_wait(2); +} + +static void mddi_sharp_lcd_set_backlight(struct msm_fb_data_type *mfd) +{ + uint32 regdata; + int32 level; + int max = mfd->panel_info.bl_max; + int min = mfd->panel_info.bl_min; + + if (mddi_sharp_pdata && mddi_sharp_pdata->backlight_level) { + level = mddi_sharp_pdata->backlight_level(mfd->bl_level, + max, + min); + + if (level < 0) + return; + + /* use Rodem GPIO(2:0) to give 8 levels of backlight (7-0) */ + /* Set lower 3 GPIOs as Outputs (set to 0) */ + mddi_queue_register_read(REG_GIOA, ®data, TRUE, 0); + mddi_queue_register_write(REG_GIOA, regdata & 0xfff8, TRUE, 0); + + /* Set lower 3 GPIOs as level */ + mddi_queue_register_read(REG_GIOD, ®data, TRUE, 0); + mddi_queue_register_write(REG_GIOD, + (regdata & 0xfff8) | (0x07 & level), TRUE, 0); + } +} + +static void mddi_sharp_prim_lcd_init(void) +{ + mddi_queue_register_write(REG_SYSCTL, 0x4000, TRUE, 0); + mddi_wait(1); + mddi_queue_register_write(REG_SYSCTL, 0x0000, TRUE, 0); + mddi_wait(5); + mddi_queue_register_write(REG_SYSCTL, 0x0001, FALSE, 0); + mddi_queue_register_write(REG_CLKDIV1, 0x000b, FALSE, 0); + + /* new reg write below */ + if (mddi_sharp_debug_60hz_refresh) + mddi_queue_register_write(REG_CLKCNF, 0x070d, FALSE, 0); + else + mddi_queue_register_write(REG_CLKCNF, 0x0708, FALSE, 0); + + mddi_queue_register_write(REG_SYSCTL, 0x0201, FALSE, 0); + mddi_queue_register_write(REG_PTGCTL, 0x0010, FALSE, 0); + mddi_queue_register_write(REG_PTHP, 4, FALSE, 0); + mddi_queue_register_write(REG_PTHB, 40, FALSE, 0); + mddi_queue_register_write(REG_PTHW, 240, FALSE, 0); + if (mddi_sharp_debug_60hz_refresh) + mddi_queue_register_write(REG_PTHF, 12, FALSE, 0); + else + mddi_queue_register_write(REG_PTHF, 92, FALSE, 0); + + mddi_wait(1); + + mddi_queue_register_write(REG_PTVP, 1, FALSE, 0); + mddi_queue_register_write(REG_PTVB, 2, FALSE, 0); + mddi_queue_register_write(REG_PTVW, 320, FALSE, 0); + mddi_queue_register_write(REG_PTVF, 15, FALSE, 0); + + mddi_wait(1); + + /* vram_color set REG_AGM???? */ + mddi_queue_register_write(REG_AGM, 0x0000, TRUE, 0); + + mddi_queue_register_write(REG_SSDCTL, 0x0000, FALSE, 0); + mddi_queue_register_write(REG_SSDCTL, 0x0001, TRUE, 0); + mddi_wait(1); + mddi_queue_register_write(REG_PSTCTL1, 0x0001, TRUE, 0); + mddi_wait(10); + + serigo(0x0701); + /* software reset */ + mddi_wait(1); + /* Wait over 50us */ + + serigo(0x0400); + /* DCLK~ACHSYNC~ACVSYNC polarity setting */ + serigo(0x2900); + /* EEPROM start read address setting */ + serigo(0x2606); + /* EEPROM start read register setting */ + mddi_wait(20); + /* Wait over 20ms */ + + serigo(0x0503); + /* Horizontal timing setting */ + serigo(0x062C); + /* Veritical timing setting */ + serigo(0x2001); + /* power initialize setting(VDC2) */ + mddi_wait(20); + /* Wait over 20ms */ + + serigo(0x2120); + /* Initialize power setting(CPS) */ + mddi_wait(20); + /* Wait over 20ms */ + + serigo(0x2130); + /* Initialize power setting(CPS) */ + mddi_wait(20); + /* Wait over 20ms */ + + serigo(0x2132); + /* Initialize power setting(CPS) */ + mddi_wait(10); + /* Wait over 10ms */ + + serigo(0x2133); + /* Initialize power setting(CPS) */ + mddi_wait(20); + /* Wait over 20ms */ + + serigo(0x0200); + /* Panel initialize release(INIT) */ + mddi_wait(1); + /* Wait over 1ms */ + + serigo(0x0131); + /* Panel setting(CPS) */ + mddi_wait(1); + /* Wait over 1ms */ + + mddi_queue_register_write(REG_PSTCTL1, 0x0003, TRUE, 0); + + /* if (FFA LCD is upside down) -> serigo(0x0100); */ + serigo(0x0130); + + /* Black mask release(display ON) */ + mddi_wait(1); + /* Wait over 1ms */ + + if (mddi_sharp_vsync_wake) { + mddi_queue_register_write(REG_VBLKS, 0x1001, TRUE, 0); + mddi_queue_register_write(REG_VBLKE, 0x1002, TRUE, 0); + } + + /* Set the MDP pixel data attributes for Primary Display */ + mddi_host_write_pix_attr_reg(0x00C3); + return; + +} + +void mddi_sharp_sub_lcd_init(void) +{ + + mddi_queue_register_write(REG_SYSCTL, 0x4000, FALSE, 0); + mddi_queue_register_write(REG_SYSCTL, 0x0000, TRUE, 0); + mddi_wait(100); + + mddi_queue_register_write(REG_SYSCTL, 0x0001, FALSE, 0); + mddi_queue_register_write(REG_CLKDIV1, 0x000b, FALSE, 0); + mddi_queue_register_write(REG_CLKCNF, 0x0708, FALSE, 0); + mddi_queue_register_write(REG_SYSCTL, 0x0201, FALSE, 0); + mddi_queue_register_write(REG_PTGCTL, 0x0010, FALSE, 0); + mddi_queue_register_write(REG_PTHP, 4, FALSE, 0); + mddi_queue_register_write(REG_PTHB, 40, FALSE, 0); + mddi_queue_register_write(REG_PTHW, 128, FALSE, 0); + mddi_queue_register_write(REG_PTHF, 92, FALSE, 0); + mddi_queue_register_write(REG_PTVP, 1, FALSE, 0); + mddi_queue_register_write(REG_PTVB, 2, FALSE, 0); + mddi_queue_register_write(REG_PTVW, 128, FALSE, 0); + mddi_queue_register_write(REG_PTVF, 15, FALSE, 0); + + /* Now the sub display..... */ + /* Reset High */ + mddi_queue_register_write(REG_SUBCTL, 0x0200, FALSE, 0); + /* CS=1,RD=1,WE=1,RS=1 */ + mddi_queue_register_write(REG_SUBTCMD, 0x000f, TRUE, 0); + mddi_wait(1); + /* Wait 5us */ + + if (sharp_subpanel_type == SHARP_SUB_UNKNOWN) { + uint32 data; + + sub_through_write(1, 0x05); + sub_through_write(1, 0x6A); + sub_through_write(1, 0x1D); + sub_through_write(1, 0x05); + data = sub_through_read(1); + if (data == 0x6A) { + sharp_subpanel_type = SHARP_SUB_HYNIX; + } else { + sub_through_write(0, 0x36); + sub_through_write(1, 0xA8); + sub_through_write(0, 0x09); + data = sub_through_read(1); + data = sub_through_read(1); + if (data == 0x54) { + sub_through_write(0, 0x36); + sub_through_write(1, 0x00); + sharp_subpanel_type = SHARP_SUB_ROHM; + } + } + } + + if (sharp_subpanel_type == SHARP_SUB_HYNIX) { + sub_through_write(1, 0x00); /* Display setting 1 */ + sub_through_write(1, 0x04); + sub_through_write(1, 0x01); + sub_through_write(1, 0x05); + sub_through_write(1, 0x0280); + sub_through_write(1, 0x0301); + sub_through_write(1, 0x0402); + sub_through_write(1, 0x0500); + sub_through_write(1, 0x0681); + sub_through_write(1, 0x077F); + sub_through_write(1, 0x08C0); + sub_through_write(1, 0x0905); + sub_through_write(1, 0x0A02); + sub_through_write(1, 0x0B00); + sub_through_write(1, 0x0C00); + sub_through_write(1, 0x0D00); + sub_through_write(1, 0x0E00); + sub_through_write(1, 0x0F00); + + sub_through_write(1, 0x100B); /* Display setting 2 */ + sub_through_write(1, 0x1103); + sub_through_write(1, 0x1237); + sub_through_write(1, 0x1300); + sub_through_write(1, 0x1400); + sub_through_write(1, 0x1500); + sub_through_write(1, 0x1605); + sub_through_write(1, 0x1700); + sub_through_write(1, 0x1800); + sub_through_write(1, 0x192E); + sub_through_write(1, 0x1A00); + sub_through_write(1, 0x1B00); + sub_through_write(1, 0x1C00); + + sub_through_write(1, 0x151A); /* Power setting */ + + sub_through_write(1, 0x2002); /* Gradation Palette setting */ + sub_through_write(1, 0x2107); + sub_through_write(1, 0x220C); + sub_through_write(1, 0x2310); + sub_through_write(1, 0x2414); + sub_through_write(1, 0x2518); + sub_through_write(1, 0x261C); + sub_through_write(1, 0x2720); + sub_through_write(1, 0x2824); + sub_through_write(1, 0x2928); + sub_through_write(1, 0x2A2B); + sub_through_write(1, 0x2B2E); + sub_through_write(1, 0x2C31); + sub_through_write(1, 0x2D34); + sub_through_write(1, 0x2E37); + sub_through_write(1, 0x2F3A); + sub_through_write(1, 0x303C); + sub_through_write(1, 0x313E); + sub_through_write(1, 0x323F); + sub_through_write(1, 0x3340); + sub_through_write(1, 0x3441); + sub_through_write(1, 0x3543); + sub_through_write(1, 0x3646); + sub_through_write(1, 0x3749); + sub_through_write(1, 0x384C); + sub_through_write(1, 0x394F); + sub_through_write(1, 0x3A52); + sub_through_write(1, 0x3B59); + sub_through_write(1, 0x3C60); + sub_through_write(1, 0x3D67); + sub_through_write(1, 0x3E6E); + sub_through_write(1, 0x3F7F); + sub_through_write(1, 0x4001); + sub_through_write(1, 0x4107); + sub_through_write(1, 0x420C); + sub_through_write(1, 0x4310); + sub_through_write(1, 0x4414); + sub_through_write(1, 0x4518); + sub_through_write(1, 0x461C); + sub_through_write(1, 0x4720); + sub_through_write(1, 0x4824); + sub_through_write(1, 0x4928); + sub_through_write(1, 0x4A2B); + sub_through_write(1, 0x4B2E); + sub_through_write(1, 0x4C31); + sub_through_write(1, 0x4D34); + sub_through_write(1, 0x4E37); + sub_through_write(1, 0x4F3A); + sub_through_write(1, 0x503C); + sub_through_write(1, 0x513E); + sub_through_write(1, 0x523F); + sub_through_write(1, 0x5340); + sub_through_write(1, 0x5441); + sub_through_write(1, 0x5543); + sub_through_write(1, 0x5646); + sub_through_write(1, 0x5749); + sub_through_write(1, 0x584C); + sub_through_write(1, 0x594F); + sub_through_write(1, 0x5A52); + sub_through_write(1, 0x5B59); + sub_through_write(1, 0x5C60); + sub_through_write(1, 0x5D67); + sub_through_write(1, 0x5E6E); + sub_through_write(1, 0x5F7E); + sub_through_write(1, 0x6000); + sub_through_write(1, 0x6107); + sub_through_write(1, 0x620C); + sub_through_write(1, 0x6310); + sub_through_write(1, 0x6414); + sub_through_write(1, 0x6518); + sub_through_write(1, 0x661C); + sub_through_write(1, 0x6720); + sub_through_write(1, 0x6824); + sub_through_write(1, 0x6928); + sub_through_write(1, 0x6A2B); + sub_through_write(1, 0x6B2E); + sub_through_write(1, 0x6C31); + sub_through_write(1, 0x6D34); + sub_through_write(1, 0x6E37); + sub_through_write(1, 0x6F3A); + sub_through_write(1, 0x703C); + sub_through_write(1, 0x713E); + sub_through_write(1, 0x723F); + sub_through_write(1, 0x7340); + sub_through_write(1, 0x7441); + sub_through_write(1, 0x7543); + sub_through_write(1, 0x7646); + sub_through_write(1, 0x7749); + sub_through_write(1, 0x784C); + sub_through_write(1, 0x794F); + sub_through_write(1, 0x7A52); + sub_through_write(1, 0x7B59); + sub_through_write(1, 0x7C60); + sub_through_write(1, 0x7D67); + sub_through_write(1, 0x7E6E); + sub_through_write(1, 0x7F7D); + + sub_through_write(1, 0x1851); /* Display on */ + + mddi_queue_register_write(REG_AGM, 0x0000, TRUE, 0); + + /* 1 pixel / 1 post clock */ + mddi_queue_register_write(REG_CLKDIV2, 0x3b00, FALSE, 0); + + /* SUB LCD select */ + mddi_queue_register_write(REG_PSTCTL2, 0x0080, FALSE, 0); + + /* RS=0,command initiate number=0,select master mode */ + mddi_queue_register_write(REG_SUBCTL, 0x0202, FALSE, 0); + + /* Sub LCD Data transform start */ + mddi_queue_register_write(REG_PSTCTL1, 0x0003, FALSE, 0); + + } else if (sharp_subpanel_type == SHARP_SUB_ROHM) { + + sub_through_write(0, 0x01); /* Display setting */ + sub_through_write(1, 0x00); + + mddi_wait(1); + /* Wait 100us <----- ******* Update 2005/01/24 */ + + sub_through_write(0, 0xB6); + sub_through_write(1, 0x0C); + sub_through_write(1, 0x4A); + sub_through_write(1, 0x20); + sub_through_write(0, 0x3A); + sub_through_write(1, 0x05); + sub_through_write(0, 0xB7); + sub_through_write(1, 0x01); + sub_through_write(0, 0xBA); + sub_through_write(1, 0x20); + sub_through_write(1, 0x02); + sub_through_write(0, 0x25); + sub_through_write(1, 0x4F); + sub_through_write(0, 0xBB); + sub_through_write(1, 0x00); + sub_through_write(0, 0x36); + sub_through_write(1, 0x00); + sub_through_write(0, 0xB1); + sub_through_write(1, 0x05); + sub_through_write(0, 0xBE); + sub_through_write(1, 0x80); + sub_through_write(0, 0x26); + sub_through_write(1, 0x01); + sub_through_write(0, 0x2A); + sub_through_write(1, 0x02); + sub_through_write(1, 0x81); + sub_through_write(0, 0x2B); + sub_through_write(1, 0x00); + sub_through_write(1, 0x7F); + + sub_through_write(0, 0x2C); + sub_through_write(0, 0x11); /* Sleep mode off */ + + mddi_wait(1); + /* Wait 100 ms <----- ******* Update 2005/01/24 */ + + sub_through_write(0, 0x29); /* Display on */ + sub_through_write(0, 0xB3); + sub_through_write(1, 0x20); + sub_through_write(1, 0xAA); + sub_through_write(1, 0xA0); + sub_through_write(1, 0x20); + sub_through_write(1, 0x30); + sub_through_write(1, 0xA6); + sub_through_write(1, 0xFF); + sub_through_write(1, 0x9A); + sub_through_write(1, 0x9F); + sub_through_write(1, 0xAF); + sub_through_write(1, 0xBC); + sub_through_write(1, 0xCF); + sub_through_write(1, 0xDF); + sub_through_write(1, 0x20); + sub_through_write(1, 0x9C); + sub_through_write(1, 0x8A); + + sub_through_write(0, 0x002C); /* Display on */ + + /* 1 pixel / 2 post clock */ + mddi_queue_register_write(REG_CLKDIV2, 0x7b00, FALSE, 0); + + /* SUB LCD select */ + mddi_queue_register_write(REG_PSTCTL2, 0x0080, FALSE, 0); + + /* RS=1,command initiate number=0,select master mode */ + mddi_queue_register_write(REG_SUBCTL, 0x0242, FALSE, 0); + + /* Sub LCD Data transform start */ + mddi_queue_register_write(REG_PSTCTL1, 0x0003, FALSE, 0); + + } + + /* Set the MDP pixel data attributes for Sub Display */ + mddi_host_write_pix_attr_reg(0x00C0); +} + +void mddi_sharp_lcd_vsync_detected(boolean detected) +{ + /* static timetick_type start_time = 0; */ + static struct timeval start_time; + static boolean first_time = TRUE; + /* uint32 mdp_cnt_val = 0; */ + /* timetick_type elapsed_us; */ + struct timeval now; + uint32 elapsed_us; + uint32 num_vsyncs; + + if ((detected) || (mddi_sharp_vsync_attempts > 5)) { + if ((detected) && (mddi_sharp_monitor_refresh_value)) { + /* if (start_time != 0) */ + if (!first_time) { + jiffies_to_timeval(jiffies, &now); + elapsed_us = + (now.tv_sec - start_time.tv_sec) * 1000000 + + now.tv_usec - start_time.tv_usec; + /* + * LCD is configured for a refresh every usecs, + * so to determine the number of vsyncs that + * have occurred since the last measurement add + * half that to the time difference and divide + * by the refresh rate. + */ + num_vsyncs = (elapsed_us + + (mddi_sharp_usecs_per_refresh >> + 1)) / + mddi_sharp_usecs_per_refresh; + /* + * LCD is configured for * hsyncs (rows) per + * refresh cycle. Calculate new rows_per_second + * value based upon these new measurements. + * MDP can update with this new value. + */ + mddi_sharp_rows_per_second = + (mddi_sharp_rows_per_refresh * 1000 * + num_vsyncs) / (elapsed_us / 1000); + } + /* start_time = timetick_get(); */ + first_time = FALSE; + jiffies_to_timeval(jiffies, &start_time); + if (mddi_sharp_report_refresh_measurements) { + /* mdp_cnt_val = MDP_LINE_COUNT; */ + } + } + /* if detected = TRUE, client initiated wakeup was detected */ + if (mddi_sharp_vsync_handler != NULL) { + (*mddi_sharp_vsync_handler) + (mddi_sharp_vsync_handler_arg); + mddi_sharp_vsync_handler = NULL; + } + mddi_vsync_detect_enabled = FALSE; + mddi_sharp_vsync_attempts = 0; + /* need to clear this vsync wakeup */ + if (!mddi_queue_register_write_int(REG_INTR, 0x0000)) { + MDDI_MSG_ERR("Vsync interrupt clear failed!\n"); + } + if (!detected) { + /* give up after 5 failed attempts but show error */ + MDDI_MSG_NOTICE("Vsync detection failed!\n"); + } else if ((mddi_sharp_monitor_refresh_value) && + (mddi_sharp_report_refresh_measurements)) { + MDDI_MSG_NOTICE(" Lines Per Second=%d!\n", + mddi_sharp_rows_per_second); + } + } else + /* if detected = FALSE, we woke up from hibernation, but did not + * detect client initiated wakeup. + */ + mddi_sharp_vsync_attempts++; +} + +/* ISR to be executed */ +void mddi_sharp_vsync_set_handler(msm_fb_vsync_handler_type handler, void *arg) +{ + boolean error = FALSE; + unsigned long flags; + + /* Disable interrupts */ + spin_lock_irqsave(&mddi_host_spin_lock, flags); + /* INTLOCK(); */ + + if (mddi_sharp_vsync_handler != NULL) + error = TRUE; + + /* Register the handler for this particular GROUP interrupt source */ + mddi_sharp_vsync_handler = handler; + mddi_sharp_vsync_handler_arg = arg; + + /* Restore interrupts */ + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + /* INTFREE(); */ + + if (error) + MDDI_MSG_ERR("MDDI: Previous Vsync handler never called\n"); + + /* Enable the vsync wakeup */ + mddi_queue_register_write(REG_INTR, 0x8100, FALSE, 0); + + mddi_sharp_vsync_attempts = 1; + mddi_vsync_detect_enabled = TRUE; +} /* mddi_sharp_vsync_set_handler */ + +static int mddi_sharp_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (mfd->panel.id == SHARP_QVGA_PRIM) + mddi_sharp_prim_lcd_init(); + else + mddi_sharp_sub_lcd_init(); + + return 0; +} + +static int mddi_sharp_lcd_off(struct platform_device *pdev) +{ + mddi_sharp_lcd_powerdown(); + return 0; +} + +static int __init mddi_sharp_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + mddi_sharp_pdata = pdev->dev.platform_data; + return 0; + } + + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mddi_sharp_probe, + .driver = { + .name = "mddi_sharp_qvga", + }, +}; + +static struct msm_fb_panel_data mddi_sharp_panel_data0 = { + .on = mddi_sharp_lcd_on, + .off = mddi_sharp_lcd_off, + .set_backlight = mddi_sharp_lcd_set_backlight, + .set_vsync_notifier = mddi_sharp_vsync_set_handler, +}; + +static struct platform_device this_device_0 = { + .name = "mddi_sharp_qvga", + .id = SHARP_QVGA_PRIM, + .dev = { + .platform_data = &mddi_sharp_panel_data0, + } +}; + +static struct msm_fb_panel_data mddi_sharp_panel_data1 = { + .on = mddi_sharp_lcd_on, + .off = mddi_sharp_lcd_off, +}; + +static struct platform_device this_device_1 = { + .name = "mddi_sharp_qvga", + .id = SHARP_128X128_SECD, + .dev = { + .platform_data = &mddi_sharp_panel_data1, + } +}; + +static int __init mddi_sharp_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; + + ret = msm_fb_detect_client("mddi_sharp_qvga"); + if (ret == -ENODEV) + return 0; + + if (ret) { + id = mddi_get_client_id(); + + if (((id >> 16) != 0x0) || ((id & 0xffff) != 0x8835)) + return 0; + } +#endif + if (mddi_host_core_version > 8) { + /* can use faster refresh with newer hw revisions */ + mddi_sharp_debug_60hz_refresh = TRUE; + + /* Timing variables for tracking vsync */ + /* dot_clock = 6.00MHz + * horizontal count = 296 + * vertical count = 338 + * refresh rate = 6000000/(296+338) = 60Hz + */ + mddi_sharp_rows_per_second = 20270; /* 6000000/296 */ + mddi_sharp_rows_per_refresh = 338; + mddi_sharp_usecs_per_refresh = 16674; /* (296+338)/6000000 */ + } else { + /* Timing variables for tracking vsync */ + /* dot_clock = 5.20MHz + * horizontal count = 376 + * vertical count = 338 + * refresh rate = 5200000/(376+338) = 41Hz + */ + mddi_sharp_rows_per_second = 13830; /* 5200000/376 */ + mddi_sharp_rows_per_refresh = 338; + mddi_sharp_usecs_per_refresh = 24440; /* (376+338)/5200000 */ + } + + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &mddi_sharp_panel_data0.panel_info; + pinfo->xres = 240; + pinfo->yres = 320; + pinfo->type = MDDI_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->clk_rate = 122880000; + pinfo->clk_min = 120000000; + pinfo->clk_max = 125000000; + pinfo->lcd.vsync_enable = TRUE; + pinfo->lcd.refx100 = + (mddi_sharp_rows_per_second * 100) / + mddi_sharp_rows_per_refresh; + pinfo->lcd.v_back_porch = 12; + pinfo->lcd.v_front_porch = 6; + pinfo->lcd.v_pulse_width = 0; + pinfo->lcd.hw_vsync_mode = FALSE; + pinfo->lcd.vsync_notifier_period = (1 * HZ); + pinfo->bl_max = 7; + pinfo->bl_min = 1; + + ret = platform_device_register(&this_device_0); + if (ret) + platform_driver_unregister(&this_driver); + + pinfo = &mddi_sharp_panel_data1.panel_info; + pinfo->xres = 128; + pinfo->yres = 128; + pinfo->type = MDDI_PANEL; + pinfo->pdest = DISPLAY_2; + pinfo->mddi.vdopkt = 0x400; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->clk_rate = 122880000; + pinfo->clk_min = 120000000; + pinfo->clk_max = 125000000; + pinfo->fb_num = 2; + + ret = platform_device_register(&this_device_1); + if (ret) { + platform_device_unregister(&this_device_0); + platform_driver_unregister(&this_driver); + } + } + + if (!ret) + mddi_lcd.vsync_detected = mddi_sharp_lcd_vsync_detected; + + return ret; +} + +module_init(mddi_sharp_init); diff --git a/drivers/staging/msm/mddi_toshiba.c b/drivers/staging/msm/mddi_toshiba.c new file mode 100644 index 000000000000..e96342d477a2 --- /dev/null +++ b/drivers/staging/msm/mddi_toshiba.c @@ -0,0 +1,1741 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" +#include "mddi_toshiba.h" + +#define TM_GET_DID(id) ((id) & 0xff) +#define TM_GET_PID(id) (((id) & 0xff00)>>8) + +#define MDDI_CLIENT_CORE_BASE 0x108000 +#define LCD_CONTROL_BLOCK_BASE 0x110000 +#define SPI_BLOCK_BASE 0x120000 +#define PWM_BLOCK_BASE 0x140000 +#define SYSTEM_BLOCK1_BASE 0x160000 + +#define TTBUSSEL (MDDI_CLIENT_CORE_BASE|0x18) +#define DPSET0 (MDDI_CLIENT_CORE_BASE|0x1C) +#define DPSET1 (MDDI_CLIENT_CORE_BASE|0x20) +#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24) +#define DPRUN (MDDI_CLIENT_CORE_BASE|0x28) +#define SYSCKENA (MDDI_CLIENT_CORE_BASE|0x2C) + +#define BITMAP0 (MDDI_CLIENT_CORE_BASE|0x44) +#define BITMAP1 (MDDI_CLIENT_CORE_BASE|0x48) +#define BITMAP2 (MDDI_CLIENT_CORE_BASE|0x4C) +#define BITMAP3 (MDDI_CLIENT_CORE_BASE|0x50) +#define BITMAP4 (MDDI_CLIENT_CORE_BASE|0x54) + +#define SRST (LCD_CONTROL_BLOCK_BASE|0x00) +#define PORT_ENB (LCD_CONTROL_BLOCK_BASE|0x04) +#define START (LCD_CONTROL_BLOCK_BASE|0x08) +#define PORT (LCD_CONTROL_BLOCK_BASE|0x0C) + +#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18) +#define INTMSK (LCD_CONTROL_BLOCK_BASE|0x1C) +#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20) + +#define PXL (LCD_CONTROL_BLOCK_BASE|0x30) +#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34) +#define HSW (LCD_CONTROL_BLOCK_BASE|0x38) +#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C) +#define HDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x40) +#define VCYCLE (LCD_CONTROL_BLOCK_BASE|0x44) +#define VSW (LCD_CONTROL_BLOCK_BASE|0x48) +#define VDE_START (LCD_CONTROL_BLOCK_BASE|0x4C) +#define VDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x50) +#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54) +#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C) +#define VSYNIF (LCD_CONTROL_BLOCK_BASE|0x60) +#define WRSTB (LCD_CONTROL_BLOCK_BASE|0x64) +#define RDSTB (LCD_CONTROL_BLOCK_BASE|0x68) +#define ASY_DATA (LCD_CONTROL_BLOCK_BASE|0x6C) +#define ASY_DATB (LCD_CONTROL_BLOCK_BASE|0x70) +#define ASY_DATC (LCD_CONTROL_BLOCK_BASE|0x74) +#define ASY_DATD (LCD_CONTROL_BLOCK_BASE|0x78) +#define ASY_DATE (LCD_CONTROL_BLOCK_BASE|0x7C) +#define ASY_DATF (LCD_CONTROL_BLOCK_BASE|0x80) +#define ASY_DATG (LCD_CONTROL_BLOCK_BASE|0x84) +#define ASY_DATH (LCD_CONTROL_BLOCK_BASE|0x88) +#define ASY_CMDSET (LCD_CONTROL_BLOCK_BASE|0x8C) +#define MONI (LCD_CONTROL_BLOCK_BASE|0xB0) +#define VPOS (LCD_CONTROL_BLOCK_BASE|0xC0) + +#define SSICTL (SPI_BLOCK_BASE|0x00) +#define SSITIME (SPI_BLOCK_BASE|0x04) +#define SSITX (SPI_BLOCK_BASE|0x08) +#define SSIINTS (SPI_BLOCK_BASE|0x14) + +#define TIMER0LOAD (PWM_BLOCK_BASE|0x00) +#define TIMER0CTRL (PWM_BLOCK_BASE|0x08) +#define PWM0OFF (PWM_BLOCK_BASE|0x1C) +#define TIMER1LOAD (PWM_BLOCK_BASE|0x20) +#define TIMER1CTRL (PWM_BLOCK_BASE|0x28) +#define PWM1OFF (PWM_BLOCK_BASE|0x3C) +#define TIMER2LOAD (PWM_BLOCK_BASE|0x40) +#define TIMER2CTRL (PWM_BLOCK_BASE|0x48) +#define PWM2OFF (PWM_BLOCK_BASE|0x5C) +#define PWMCR (PWM_BLOCK_BASE|0x68) + +#define GPIOIS (GPIO_BLOCK_BASE|0x08) +#define GPIOIEV (GPIO_BLOCK_BASE|0x10) +#define GPIOIC (GPIO_BLOCK_BASE|0x20) + +#define WKREQ (SYSTEM_BLOCK1_BASE|0x00) +#define CLKENB (SYSTEM_BLOCK1_BASE|0x04) +#define DRAMPWR (SYSTEM_BLOCK1_BASE|0x08) +#define INTMASK (SYSTEM_BLOCK1_BASE|0x0C) +#define CNT_DIS (SYSTEM_BLOCK1_BASE|0x10) + +typedef enum { + TOSHIBA_STATE_OFF, + TOSHIBA_STATE_PRIM_SEC_STANDBY, + TOSHIBA_STATE_PRIM_SEC_READY, + TOSHIBA_STATE_PRIM_NORMAL_MODE, + TOSHIBA_STATE_SEC_NORMAL_MODE +} mddi_toshiba_state_t; + +static uint32 mddi_toshiba_curr_vpos; +static boolean mddi_toshiba_monitor_refresh_value = FALSE; +static boolean mddi_toshiba_report_refresh_measurements = FALSE; + +boolean mddi_toshiba_61Hz_refresh = TRUE; + +/* Modifications to timing to increase refresh rate to > 60Hz. + * 20MHz dot clock. + * 646 total rows. + * 506 total columns. + * refresh rate = 61.19Hz + */ +static uint32 mddi_toshiba_rows_per_second = 39526; +static uint32 mddi_toshiba_usecs_per_refresh = 16344; +static uint32 mddi_toshiba_rows_per_refresh = 646; +extern boolean mddi_vsync_detect_enabled; + +static msm_fb_vsync_handler_type mddi_toshiba_vsync_handler; +static void *mddi_toshiba_vsync_handler_arg; +static uint16 mddi_toshiba_vsync_attempts; + +static mddi_toshiba_state_t toshiba_state = TOSHIBA_STATE_OFF; + +static struct msm_panel_common_pdata *mddi_toshiba_pdata; + +static int mddi_toshiba_lcd_on(struct platform_device *pdev); +static int mddi_toshiba_lcd_off(struct platform_device *pdev); + +static void mddi_toshiba_state_transition(mddi_toshiba_state_t a, + mddi_toshiba_state_t b) +{ + if (toshiba_state != a) { + MDDI_MSG_ERR("toshiba state trans. (%d->%d) found %d\n", a, b, + toshiba_state); + } + toshiba_state = b; +} + +#define GORDON_REG_IMGCTL1 0x10 /* Image interface control 1 */ +#define GORDON_REG_IMGCTL2 0x11 /* Image interface control 2 */ +#define GORDON_REG_IMGSET1 0x12 /* Image interface settings 1 */ +#define GORDON_REG_IMGSET2 0x13 /* Image interface settings 2 */ +#define GORDON_REG_IVBP1 0x14 /* DM0: Vert back porch */ +#define GORDON_REG_IHBP1 0x15 /* DM0: Horiz back porch */ +#define GORDON_REG_IVNUM1 0x16 /* DM0: Num of vert lines */ +#define GORDON_REG_IHNUM1 0x17 /* DM0: Num of pixels per line */ +#define GORDON_REG_IVBP2 0x18 /* DM1: Vert back porch */ +#define GORDON_REG_IHBP2 0x19 /* DM1: Horiz back porch */ +#define GORDON_REG_IVNUM2 0x1A /* DM1: Num of vert lines */ +#define GORDON_REG_IHNUM2 0x1B /* DM1: Num of pixels per line */ +#define GORDON_REG_LCDIFCTL1 0x30 /* LCD interface control 1 */ +#define GORDON_REG_VALTRAN 0x31 /* LCD IF ctl: VALTRAN sync flag */ +#define GORDON_REG_AVCTL 0x33 +#define GORDON_REG_LCDIFCTL2 0x34 /* LCD interface control 2 */ +#define GORDON_REG_LCDIFCTL3 0x35 /* LCD interface control 3 */ +#define GORDON_REG_LCDIFSET1 0x36 /* LCD interface settings 1 */ +#define GORDON_REG_PCCTL 0x3C +#define GORDON_REG_TPARAM1 0x40 +#define GORDON_REG_TLCDIF1 0x41 +#define GORDON_REG_TSSPB_ST1 0x42 +#define GORDON_REG_TSSPB_ED1 0x43 +#define GORDON_REG_TSCK_ST1 0x44 +#define GORDON_REG_TSCK_WD1 0x45 +#define GORDON_REG_TGSPB_VST1 0x46 +#define GORDON_REG_TGSPB_VED1 0x47 +#define GORDON_REG_TGSPB_CH1 0x48 +#define GORDON_REG_TGCK_ST1 0x49 +#define GORDON_REG_TGCK_ED1 0x4A +#define GORDON_REG_TPCTL_ST1 0x4B +#define GORDON_REG_TPCTL_ED1 0x4C +#define GORDON_REG_TPCHG_ED1 0x4D +#define GORDON_REG_TCOM_CH1 0x4E +#define GORDON_REG_THBP1 0x4F +#define GORDON_REG_TPHCTL1 0x50 +#define GORDON_REG_EVPH1 0x51 +#define GORDON_REG_EVPL1 0x52 +#define GORDON_REG_EVNH1 0x53 +#define GORDON_REG_EVNL1 0x54 +#define GORDON_REG_TBIAS1 0x55 +#define GORDON_REG_TPARAM2 0x56 +#define GORDON_REG_TLCDIF2 0x57 +#define GORDON_REG_TSSPB_ST2 0x58 +#define GORDON_REG_TSSPB_ED2 0x59 +#define GORDON_REG_TSCK_ST2 0x5A +#define GORDON_REG_TSCK_WD2 0x5B +#define GORDON_REG_TGSPB_VST2 0x5C +#define GORDON_REG_TGSPB_VED2 0x5D +#define GORDON_REG_TGSPB_CH2 0x5E +#define GORDON_REG_TGCK_ST2 0x5F +#define GORDON_REG_TGCK_ED2 0x60 +#define GORDON_REG_TPCTL_ST2 0x61 +#define GORDON_REG_TPCTL_ED2 0x62 +#define GORDON_REG_TPCHG_ED2 0x63 +#define GORDON_REG_TCOM_CH2 0x64 +#define GORDON_REG_THBP2 0x65 +#define GORDON_REG_TPHCTL2 0x66 +#define GORDON_REG_EVPH2 0x67 +#define GORDON_REG_EVPL2 0x68 +#define GORDON_REG_EVNH2 0x69 +#define GORDON_REG_EVNL2 0x6A +#define GORDON_REG_TBIAS2 0x6B +#define GORDON_REG_POWCTL 0x80 +#define GORDON_REG_POWOSC1 0x81 +#define GORDON_REG_POWOSC2 0x82 +#define GORDON_REG_POWSET 0x83 +#define GORDON_REG_POWTRM1 0x85 +#define GORDON_REG_POWTRM2 0x86 +#define GORDON_REG_POWTRM3 0x87 +#define GORDON_REG_POWTRMSEL 0x88 +#define GORDON_REG_POWHIZ 0x89 + +void serigo(uint16 reg, uint8 data) +{ + uint32 mddi_val = 0; + mddi_queue_register_read(SSIINTS, &mddi_val, TRUE, 0); + if (mddi_val & (1 << 8)) + mddi_wait(1); + /* No De-assert of CS and send 2 bytes */ + mddi_val = 0x90000 | ((0x00FF & reg) << 8) | data; + mddi_queue_register_write(SSITX, mddi_val, TRUE, 0); +} + +void gordon_init(void) +{ + /* Image interface settings ***/ + serigo(GORDON_REG_IMGCTL2, 0x00); + serigo(GORDON_REG_IMGSET1, 0x01); + + /* Exchange the RGB signal for J510(Softbank mobile) */ + serigo(GORDON_REG_IMGSET2, 0x12); + serigo(GORDON_REG_LCDIFSET1, 0x00); + mddi_wait(2); + + /* Pre-charge settings */ + serigo(GORDON_REG_PCCTL, 0x09); + serigo(GORDON_REG_LCDIFCTL2, 0x1B); + mddi_wait(1); +} + +void gordon_disp_on(void) +{ + /*gordon_dispmode setting */ + /*VGA settings */ + serigo(GORDON_REG_TPARAM1, 0x30); + serigo(GORDON_REG_TLCDIF1, 0x00); + serigo(GORDON_REG_TSSPB_ST1, 0x8B); + serigo(GORDON_REG_TSSPB_ED1, 0x93); + mddi_wait(2); + serigo(GORDON_REG_TSCK_ST1, 0x88); + serigo(GORDON_REG_TSCK_WD1, 0x00); + serigo(GORDON_REG_TGSPB_VST1, 0x01); + serigo(GORDON_REG_TGSPB_VED1, 0x02); + mddi_wait(2); + serigo(GORDON_REG_TGSPB_CH1, 0x5E); + serigo(GORDON_REG_TGCK_ST1, 0x80); + serigo(GORDON_REG_TGCK_ED1, 0x3C); + serigo(GORDON_REG_TPCTL_ST1, 0x50); + mddi_wait(2); + serigo(GORDON_REG_TPCTL_ED1, 0x74); + serigo(GORDON_REG_TPCHG_ED1, 0x78); + serigo(GORDON_REG_TCOM_CH1, 0x50); + serigo(GORDON_REG_THBP1, 0x84); + mddi_wait(2); + serigo(GORDON_REG_TPHCTL1, 0x00); + serigo(GORDON_REG_EVPH1, 0x70); + serigo(GORDON_REG_EVPL1, 0x64); + serigo(GORDON_REG_EVNH1, 0x56); + mddi_wait(2); + serigo(GORDON_REG_EVNL1, 0x48); + serigo(GORDON_REG_TBIAS1, 0x88); + mddi_wait(2); + serigo(GORDON_REG_TPARAM2, 0x28); + serigo(GORDON_REG_TLCDIF2, 0x14); + serigo(GORDON_REG_TSSPB_ST2, 0x49); + serigo(GORDON_REG_TSSPB_ED2, 0x4B); + mddi_wait(2); + serigo(GORDON_REG_TSCK_ST2, 0x4A); + serigo(GORDON_REG_TSCK_WD2, 0x02); + serigo(GORDON_REG_TGSPB_VST2, 0x02); + serigo(GORDON_REG_TGSPB_VED2, 0x03); + mddi_wait(2); + serigo(GORDON_REG_TGSPB_CH2, 0x2F); + serigo(GORDON_REG_TGCK_ST2, 0x40); + serigo(GORDON_REG_TGCK_ED2, 0x1E); + serigo(GORDON_REG_TPCTL_ST2, 0x2C); + mddi_wait(2); + serigo(GORDON_REG_TPCTL_ED2, 0x3A); + serigo(GORDON_REG_TPCHG_ED2, 0x3C); + serigo(GORDON_REG_TCOM_CH2, 0x28); + serigo(GORDON_REG_THBP2, 0x4D); + mddi_wait(2); + serigo(GORDON_REG_TPHCTL2, 0x1A); + mddi_wait(2); + serigo(GORDON_REG_IVBP1, 0x02); + serigo(GORDON_REG_IHBP1, 0x90); + serigo(GORDON_REG_IVNUM1, 0xA0); + serigo(GORDON_REG_IHNUM1, 0x78); + mddi_wait(2); + serigo(GORDON_REG_IVBP2, 0x02); + serigo(GORDON_REG_IHBP2, 0x48); + serigo(GORDON_REG_IVNUM2, 0x50); + serigo(GORDON_REG_IHNUM2, 0x3C); + mddi_wait(2); + serigo(GORDON_REG_POWCTL, 0x03); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x07); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x0F); + mddi_wait(15); + serigo(GORDON_REG_AVCTL, 0x03); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x1F); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x5F); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x7F); + mddi_wait(15); + serigo(GORDON_REG_LCDIFCTL1, 0x02); + mddi_wait(15); + serigo(GORDON_REG_IMGCTL1, 0x00); + mddi_wait(15); + serigo(GORDON_REG_LCDIFCTL3, 0x00); + mddi_wait(15); + serigo(GORDON_REG_VALTRAN, 0x01); + mddi_wait(15); + serigo(GORDON_REG_LCDIFCTL1, 0x03); + serigo(GORDON_REG_LCDIFCTL1, 0x03); + mddi_wait(1); +} + +void gordon_disp_off(void) +{ + serigo(GORDON_REG_LCDIFCTL2, 0x7B); + serigo(GORDON_REG_VALTRAN, 0x01); + serigo(GORDON_REG_LCDIFCTL1, 0x02); + serigo(GORDON_REG_LCDIFCTL3, 0x01); + mddi_wait(20); + serigo(GORDON_REG_VALTRAN, 0x01); + serigo(GORDON_REG_IMGCTL1, 0x01); + serigo(GORDON_REG_LCDIFCTL1, 0x00); + mddi_wait(20); + serigo(GORDON_REG_POWCTL, 0x1F); + mddi_wait(40); + serigo(GORDON_REG_POWCTL, 0x07); + mddi_wait(40); + serigo(GORDON_REG_POWCTL, 0x03); + mddi_wait(40); + serigo(GORDON_REG_POWCTL, 0x00); + mddi_wait(40); +} + +void gordon_disp_init(void) +{ + gordon_init(); + mddi_wait(20); + gordon_disp_on(); +} + +static void toshiba_common_initial_setup(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) { + write_client_reg(DPSET0 , 0x4bec0066, TRUE); + write_client_reg(DPSET1 , 0x00000113, TRUE); + write_client_reg(DPSUS , 0x00000000, TRUE); + write_client_reg(DPRUN , 0x00000001, TRUE); + mddi_wait(5); + write_client_reg(SYSCKENA , 0x00000001, TRUE); + write_client_reg(CLKENB , 0x0000a0e9, TRUE); + + write_client_reg(GPIODATA , 0x03FF0000, TRUE); + write_client_reg(GPIODIR , 0x0000024D, TRUE); + write_client_reg(GPIOSEL , 0x00000173, TRUE); + write_client_reg(GPIOPC , 0x03C300C0, TRUE); + write_client_reg(WKREQ , 0x00000000, TRUE); + write_client_reg(GPIOIS , 0x00000000, TRUE); + write_client_reg(GPIOIEV , 0x00000001, TRUE); + write_client_reg(GPIOIC , 0x000003FF, TRUE); + write_client_reg(GPIODATA , 0x00040004, TRUE); + + write_client_reg(GPIODATA , 0x00080008, TRUE); + write_client_reg(DRAMPWR , 0x00000001, TRUE); + write_client_reg(CLKENB , 0x0000a0eb, TRUE); + write_client_reg(PWMCR , 0x00000000, TRUE); + mddi_wait(1); + + write_client_reg(SSICTL , 0x00060399, TRUE); + write_client_reg(SSITIME , 0x00000100, TRUE); + write_client_reg(CNT_DIS , 0x00000002, TRUE); + write_client_reg(SSICTL , 0x0006039b, TRUE); + + write_client_reg(SSITX , 0x00000000, TRUE); + mddi_wait(7); + write_client_reg(SSITX , 0x00000000, TRUE); + mddi_wait(7); + write_client_reg(SSITX , 0x00000000, TRUE); + mddi_wait(7); + + write_client_reg(SSITX , 0x000800BA, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + write_client_reg(SSITX , 0x00080036, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x0008003A, TRUE); + write_client_reg(SSITX , 0x00000160, TRUE); + write_client_reg(SSITX , 0x000800B1, TRUE); + write_client_reg(SSITX , 0x0000015D, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B2, TRUE); + write_client_reg(SSITX , 0x00000133, TRUE); + write_client_reg(SSITX , 0x000800B3, TRUE); + write_client_reg(SSITX , 0x00000122, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B4, TRUE); + write_client_reg(SSITX , 0x00000102, TRUE); + write_client_reg(SSITX , 0x000800B5, TRUE); + write_client_reg(SSITX , 0x0000011E, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B6, TRUE); + write_client_reg(SSITX , 0x00000127, TRUE); + write_client_reg(SSITX , 0x000800B7, TRUE); + write_client_reg(SSITX , 0x00000103, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B9, TRUE); + write_client_reg(SSITX , 0x00000124, TRUE); + write_client_reg(SSITX , 0x000800BD, TRUE); + write_client_reg(SSITX , 0x000001A1, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800BB, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + write_client_reg(SSITX , 0x000800BF, TRUE); + write_client_reg(SSITX , 0x00000101, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800BE, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + write_client_reg(SSITX , 0x000800C0, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C1, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + write_client_reg(SSITX , 0x000800C2, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C3, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C4, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C5, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C6, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C7, TRUE); + write_client_reg(SSITX , 0x00080164, TRUE); + write_client_reg(SSITX , 0x00000145, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C8, TRUE); + write_client_reg(SSITX , 0x00000144, TRUE); + write_client_reg(SSITX , 0x000800C9, TRUE); + write_client_reg(SSITX , 0x00000152, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800CA, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800EC, TRUE); + write_client_reg(SSITX , 0x00080101, TRUE); + write_client_reg(SSITX , 0x000001FC, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800CF, TRUE); + write_client_reg(SSITX , 0x00000101, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D0, TRUE); + write_client_reg(SSITX , 0x00080110, TRUE); + write_client_reg(SSITX , 0x00000104, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D1, TRUE); + write_client_reg(SSITX , 0x00000101, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D2, TRUE); + write_client_reg(SSITX , 0x00080100, TRUE); + write_client_reg(SSITX , 0x00000128, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D3, TRUE); + write_client_reg(SSITX , 0x00080100, TRUE); + write_client_reg(SSITX , 0x00000128, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D4, TRUE); + write_client_reg(SSITX , 0x00080126, TRUE); + write_client_reg(SSITX , 0x000001A4, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D5, TRUE); + write_client_reg(SSITX , 0x00000120, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800EF, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + + write_client_reg(BITMAP0 , 0x032001E0, TRUE); + write_client_reg(BITMAP1 , 0x032001E0, TRUE); + write_client_reg(BITMAP2 , 0x014000F0, TRUE); + write_client_reg(BITMAP3 , 0x014000F0, TRUE); + write_client_reg(BITMAP4 , 0x014000F0, TRUE); + write_client_reg(CLKENB , 0x0000A1EB, TRUE); + write_client_reg(PORT_ENB , 0x00000001, TRUE); + write_client_reg(PORT , 0x00000004, TRUE); + write_client_reg(PXL , 0x00000002, TRUE); + write_client_reg(MPLFBUF , 0x00000000, TRUE); + write_client_reg(HCYCLE , 0x000000FD, TRUE); + write_client_reg(HSW , 0x00000003, TRUE); + write_client_reg(HDE_START , 0x00000007, TRUE); + write_client_reg(HDE_SIZE , 0x000000EF, TRUE); + write_client_reg(VCYCLE , 0x00000325, TRUE); + write_client_reg(VSW , 0x00000001, TRUE); + write_client_reg(VDE_START , 0x00000003, TRUE); + write_client_reg(VDE_SIZE , 0x0000031F, TRUE); + write_client_reg(START , 0x00000001, TRUE); + mddi_wait(32); + write_client_reg(SSITX , 0x000800BC, TRUE); + write_client_reg(SSITX , 0x00000180, TRUE); + write_client_reg(SSITX , 0x0008003B, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B0, TRUE); + write_client_reg(SSITX , 0x00000116, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B8, TRUE); + write_client_reg(SSITX , 0x000801FF, TRUE); + write_client_reg(SSITX , 0x000001F5, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x00000011, TRUE); + mddi_wait(5); + write_client_reg(SSITX , 0x00000029, TRUE); + return; + } + + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + write_client_reg(DPSET0, 0x4BEC0066, TRUE); + write_client_reg(DPSET1, 0x00000113, TRUE); + write_client_reg(DPSUS, 0x00000000, TRUE); + write_client_reg(DPRUN, 0x00000001, TRUE); + mddi_wait(14); + write_client_reg(SYSCKENA, 0x00000001, TRUE); + write_client_reg(CLKENB, 0x000000EF, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x03FF0000, TRUE); + write_client_reg(GPIODIR, 0x0000024D, TRUE); + write_client_reg(SYSTEM_BLOCK2_BASE, 0x00000173, TRUE); + write_client_reg(GPIOPC, 0x03C300C0, TRUE); + write_client_reg(SYSTEM_BLOCK1_BASE, 0x00000000, TRUE); + write_client_reg(GPIOIS, 0x00000000, TRUE); + write_client_reg(GPIOIEV, 0x00000001, TRUE); + write_client_reg(GPIOIC, 0x000003FF, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x00060006, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x00080008, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x02000200, TRUE); + write_client_reg(DRAMPWR, 0x00000001, TRUE); + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(PWM_BLOCK_BASE, 0x00001388, TRUE); + write_client_reg(PWM0OFF, 0x00001387, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00001387, TRUE); + write_client_reg(TIMER0CTRL, 0x000000E0, TRUE); + write_client_reg(TIMER1CTRL, 0x000000E0, TRUE); + write_client_reg(PWMCR, 0x00000003, TRUE); + mddi_wait(1); + write_client_reg(SPI_BLOCK_BASE, 0x00063111, TRUE); + write_client_reg(SSITIME, 0x00000100, TRUE); + write_client_reg(SPI_BLOCK_BASE, 0x00063113, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(CLKENB, 0x0000A1EF, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(WRSTB, 0x0000003F, TRUE); + write_client_reg(RDSTB, 0x00000432, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(10); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x80000000, TRUE); + write_client_reg(ASY_DATC, 0x80000000, TRUE); + write_client_reg(ASY_DATD, 0x80000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + } else { + write_client_reg(DPSET0, 0x4BEC0066, TRUE); + write_client_reg(DPSET1, 0x00000113, TRUE); + write_client_reg(DPSUS, 0x00000000, TRUE); + write_client_reg(DPRUN, 0x00000001, TRUE); + mddi_wait(14); + write_client_reg(SYSCKENA, 0x00000001, TRUE); + write_client_reg(CLKENB, 0x000000EF, TRUE); + write_client_reg(GPIODATA, 0x03FF0000, TRUE); + write_client_reg(GPIODIR, 0x0000024D, TRUE); + write_client_reg(GPIOSEL, 0x00000173, TRUE); + write_client_reg(GPIOPC, 0x03C300C0, TRUE); + write_client_reg(WKREQ, 0x00000000, TRUE); + write_client_reg(GPIOIS, 0x00000000, TRUE); + write_client_reg(GPIOIEV, 0x00000001, TRUE); + write_client_reg(GPIOIC, 0x000003FF, TRUE); + write_client_reg(GPIODATA, 0x00060006, TRUE); + write_client_reg(GPIODATA, 0x00080008, TRUE); + write_client_reg(GPIODATA, 0x02000200, TRUE); + + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA) { + mddi_wait(400); + write_client_reg(DRAMPWR, 0x00000001, TRUE); + + write_client_reg(CNT_DIS, 0x00000002, TRUE); + write_client_reg(BITMAP0, 0x01E00320, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(PORT, 0x00000004, TRUE); + write_client_reg(PXL, 0x0000003A, TRUE); + write_client_reg(MPLFBUF, 0x00000000, TRUE); + write_client_reg(HCYCLE, 0x00000253, TRUE); + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000017, TRUE); + write_client_reg(HDE_SIZE, 0x0000018F, TRUE); + write_client_reg(VCYCLE, 0x000001FF, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x000001DF, TRUE); + write_client_reg(START, 0x00000001, TRUE); + mddi_wait(1); + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00000087, TRUE); + } else { + write_client_reg(DRAMPWR, 0x00000001, TRUE); + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00001387, TRUE); + } + + write_client_reg(TIMER0CTRL, 0x000000E0, TRUE); + write_client_reg(TIMER1CTRL, 0x000000E0, TRUE); + write_client_reg(PWMCR, 0x00000003, TRUE); + mddi_wait(1); + write_client_reg(SSICTL, 0x00000799, TRUE); + write_client_reg(SSITIME, 0x00000100, TRUE); + write_client_reg(SSICTL, 0x0000079b, TRUE); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800BA, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + write_client_reg(SSITX, 0x00080036, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800BB, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x0008003A, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800BF, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x000800B1, TRUE); + write_client_reg(SSITX, 0x0000015D, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B2, TRUE); + write_client_reg(SSITX, 0x00000133, TRUE); + write_client_reg(SSITX, 0x000800B3, TRUE); + write_client_reg(SSITX, 0x00000122, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B4, TRUE); + write_client_reg(SSITX, 0x00000102, TRUE); + write_client_reg(SSITX, 0x000800B5, TRUE); + write_client_reg(SSITX, 0x0000011F, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B6, TRUE); + write_client_reg(SSITX, 0x00000128, TRUE); + write_client_reg(SSITX, 0x000800B7, TRUE); + write_client_reg(SSITX, 0x00000103, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B9, TRUE); + write_client_reg(SSITX, 0x00000120, TRUE); + write_client_reg(SSITX, 0x000800BD, TRUE); + write_client_reg(SSITX, 0x00000102, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800BE, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x000800C0, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C1, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + write_client_reg(SSITX, 0x000800C2, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C3, TRUE); + write_client_reg(SSITX, 0x0008010A, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C4, TRUE); + write_client_reg(SSITX, 0x00080160, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C5, TRUE); + write_client_reg(SSITX, 0x00080160, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C6, TRUE); + write_client_reg(SSITX, 0x00080160, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C7, TRUE); + write_client_reg(SSITX, 0x00080133, TRUE); + write_client_reg(SSITX, 0x00000143, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C8, TRUE); + write_client_reg(SSITX, 0x00000144, TRUE); + write_client_reg(SSITX, 0x000800C9, TRUE); + write_client_reg(SSITX, 0x00000133, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800CA, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800EC, TRUE); + write_client_reg(SSITX, 0x00080102, TRUE); + write_client_reg(SSITX, 0x00000118, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800CF, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D0, TRUE); + write_client_reg(SSITX, 0x00080110, TRUE); + write_client_reg(SSITX, 0x00000104, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D1, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D2, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x0000013A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D3, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x0000013A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D4, TRUE); + write_client_reg(SSITX, 0x00080124, TRUE); + write_client_reg(SSITX, 0x0000016E, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800D5, TRUE); + write_client_reg(SSITX, 0x00000124, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800ED, TRUE); + write_client_reg(SSITX, 0x00080101, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D6, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D7, TRUE); + write_client_reg(SSITX, 0x00080110, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D8, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D9, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x00000114, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800DE, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x00000114, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800DF, TRUE); + write_client_reg(SSITX, 0x00080112, TRUE); + write_client_reg(SSITX, 0x0000013F, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E0, TRUE); + write_client_reg(SSITX, 0x0000010B, TRUE); + write_client_reg(SSITX, 0x000800E2, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E3, TRUE); + write_client_reg(SSITX, 0x00000136, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E4, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x00000103, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E5, TRUE); + write_client_reg(SSITX, 0x00080102, TRUE); + write_client_reg(SSITX, 0x00000104, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E6, TRUE); + write_client_reg(SSITX, 0x00000103, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E7, TRUE); + write_client_reg(SSITX, 0x00080104, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E8, TRUE); + write_client_reg(SSITX, 0x00000104, TRUE); + write_client_reg(CLKENB, 0x000001EF, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(WRSTB, 0x0000003F, TRUE); + write_client_reg(RDSTB, 0x00000432, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(10); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x80000000, TRUE); + write_client_reg(ASY_DATC, 0x80000000, TRUE); + write_client_reg(ASY_DATD, 0x80000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + } + + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_STANDBY, + TOSHIBA_STATE_PRIM_SEC_READY); +} + +static void toshiba_prim_start(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + write_client_reg(BITMAP1, 0x01E000F0, TRUE); + write_client_reg(BITMAP2, 0x01E000F0, TRUE); + write_client_reg(BITMAP3, 0x01E000F0, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(CLKENB, 0x000001EF, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(PORT, 0x00000016, TRUE); + write_client_reg(PXL, 0x00000002, TRUE); + write_client_reg(MPLFBUF, 0x00000000, TRUE); + write_client_reg(HCYCLE, 0x00000185, TRUE); + write_client_reg(HSW, 0x00000018, TRUE); + write_client_reg(HDE_START, 0x0000004A, TRUE); + write_client_reg(HDE_SIZE, 0x000000EF, TRUE); + write_client_reg(VCYCLE, 0x0000028E, TRUE); + write_client_reg(VSW, 0x00000004, TRUE); + write_client_reg(VDE_START, 0x00000009, TRUE); + write_client_reg(VDE_SIZE, 0x0000027F, TRUE); + write_client_reg(START, 0x00000001, TRUE); + write_client_reg(SYSTEM_BLOCK1_BASE, 0x00000002, TRUE); + } else{ + + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(BITMAP1, 0x01E000F0, TRUE); + write_client_reg(BITMAP2, 0x01E000F0, TRUE); + write_client_reg(BITMAP3, 0x01E000F0, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(CLKENB, 0x000001EF, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(PORT, 0x00000004, TRUE); + write_client_reg(PXL, 0x00000002, TRUE); + write_client_reg(MPLFBUF, 0x00000000, TRUE); + + if (mddi_toshiba_61Hz_refresh) { + write_client_reg(HCYCLE, 0x000000FC, TRUE); + mddi_toshiba_rows_per_second = 39526; + mddi_toshiba_rows_per_refresh = 646; + mddi_toshiba_usecs_per_refresh = 16344; + } else { + write_client_reg(HCYCLE, 0x0000010b, TRUE); + mddi_toshiba_rows_per_second = 37313; + mddi_toshiba_rows_per_refresh = 646; + mddi_toshiba_usecs_per_refresh = 17313; + } + + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000007, TRUE); + write_client_reg(HDE_SIZE, 0x000000EF, TRUE); + write_client_reg(VCYCLE, 0x00000285, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x0000027F, TRUE); + write_client_reg(START, 0x00000001, TRUE); + mddi_wait(10); + write_client_reg(SSITX, 0x000800BC, TRUE); + write_client_reg(SSITX, 0x00000180, TRUE); + write_client_reg(SSITX, 0x0008003B, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800B0, TRUE); + write_client_reg(SSITX, 0x00000116, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800B8, TRUE); + write_client_reg(SSITX, 0x000801FF, TRUE); + write_client_reg(SSITX, 0x000001F5, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000011, TRUE); + write_client_reg(SSITX, 0x00000029, TRUE); + write_client_reg(WKREQ, 0x00000000, TRUE); + write_client_reg(WAKEUP, 0x00000000, TRUE); + write_client_reg(INTMSK, 0x00000001, TRUE); + } + + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_READY, + TOSHIBA_STATE_PRIM_NORMAL_MODE); +} + +static void toshiba_sec_start(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(CLKENB, 0x000011EF, TRUE); + write_client_reg(BITMAP0, 0x028001E0, TRUE); + write_client_reg(BITMAP1, 0x00000000, TRUE); + write_client_reg(BITMAP2, 0x00000000, TRUE); + write_client_reg(BITMAP3, 0x00000000, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(PORT, 0x00000000, TRUE); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(MPLFBUF, 0x00000004, TRUE); + write_client_reg(HCYCLE, 0x0000006B, TRUE); + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000007, TRUE); + write_client_reg(HDE_SIZE, 0x00000057, TRUE); + write_client_reg(VCYCLE, 0x000000E6, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x000000DB, TRUE); + write_client_reg(ASY_DATA, 0x80000001, TRUE); + write_client_reg(ASY_DATB, 0x0000011B, TRUE); + write_client_reg(ASY_DATC, 0x80000002, TRUE); + write_client_reg(ASY_DATD, 0x00000700, TRUE); + write_client_reg(ASY_DATE, 0x80000003, TRUE); + write_client_reg(ASY_DATF, 0x00000230, TRUE); + write_client_reg(ASY_DATG, 0x80000008, TRUE); + write_client_reg(ASY_DATH, 0x00000402, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000009, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x8000000B, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x8000000C, TRUE); + write_client_reg(ASY_DATF, 0x00000000, TRUE); + write_client_reg(ASY_DATG, 0x8000000D, TRUE); + write_client_reg(ASY_DATH, 0x00000409, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x8000000E, TRUE); + write_client_reg(ASY_DATB, 0x00000409, TRUE); + write_client_reg(ASY_DATC, 0x80000030, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000031, TRUE); + write_client_reg(ASY_DATF, 0x00000100, TRUE); + write_client_reg(ASY_DATG, 0x80000032, TRUE); + write_client_reg(ASY_DATH, 0x00000104, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000033, TRUE); + write_client_reg(ASY_DATB, 0x00000400, TRUE); + write_client_reg(ASY_DATC, 0x80000034, TRUE); + write_client_reg(ASY_DATD, 0x00000306, TRUE); + write_client_reg(ASY_DATE, 0x80000035, TRUE); + write_client_reg(ASY_DATF, 0x00000706, TRUE); + write_client_reg(ASY_DATG, 0x80000036, TRUE); + write_client_reg(ASY_DATH, 0x00000707, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000037, TRUE); + write_client_reg(ASY_DATB, 0x00000004, TRUE); + write_client_reg(ASY_DATC, 0x80000038, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000039, TRUE); + write_client_reg(ASY_DATF, 0x00000000, TRUE); + write_client_reg(ASY_DATG, 0x8000003A, TRUE); + write_client_reg(ASY_DATH, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000044, TRUE); + write_client_reg(ASY_DATB, 0x0000AF00, TRUE); + write_client_reg(ASY_DATC, 0x80000045, TRUE); + write_client_reg(ASY_DATD, 0x0000DB00, TRUE); + write_client_reg(ASY_DATE, 0x08000042, TRUE); + write_client_reg(ASY_DATF, 0x0000DB00, TRUE); + write_client_reg(ASY_DATG, 0x80000021, TRUE); + write_client_reg(ASY_DATH, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(PXL, 0x0000000C, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(ASY_DATA, 0x80000022, TRUE); + write_client_reg(ASY_CMDSET, 0x00000003, TRUE); + write_client_reg(START, 0x00000001, TRUE); + mddi_wait(60); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000050, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x80000051, TRUE); + write_client_reg(ASY_DATD, 0x00000E00, TRUE); + write_client_reg(ASY_DATE, 0x80000052, TRUE); + write_client_reg(ASY_DATF, 0x00000D01, TRUE); + write_client_reg(ASY_DATG, 0x80000053, TRUE); + write_client_reg(ASY_DATH, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000058, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x8000005A, TRUE); + write_client_reg(ASY_DATD, 0x00000E01, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + write_client_reg(ASY_DATA, 0x80000011, TRUE); + write_client_reg(ASY_DATB, 0x00000812, TRUE); + write_client_reg(ASY_DATC, 0x80000012, TRUE); + write_client_reg(ASY_DATD, 0x00000003, TRUE); + write_client_reg(ASY_DATE, 0x80000013, TRUE); + write_client_reg(ASY_DATF, 0x00000909, TRUE); + write_client_reg(ASY_DATG, 0x80000010, TRUE); + write_client_reg(ASY_DATH, 0x00000040, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + mddi_wait(40); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000340, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(60); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00003340, TRUE); + write_client_reg(ASY_DATC, 0x80000007, TRUE); + write_client_reg(ASY_DATD, 0x00004007, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + mddi_wait(1); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004017, TRUE); + write_client_reg(ASY_DATC, 0x8000005B, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000059, TRUE); + write_client_reg(ASY_DATF, 0x00000011, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000D, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000C, TRUE); + mddi_wait(20); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + /* LTPS I/F control */ + write_client_reg(ASY_DATB, 0x00000019, TRUE); + /* Direct cmd transfer enable */ + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + /* Direct cmd transfer disable */ + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + /* Index setting of SUB LCDD */ + write_client_reg(ASY_DATA, 0x80000059, TRUE); + /* LTPS I/F control */ + write_client_reg(ASY_DATB, 0x00000079, TRUE); + /* Direct cmd transfer enable */ + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + /* Direct cmd transfer disable */ + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + /* Index setting of SUB LCDD */ + write_client_reg(ASY_DATA, 0x80000059, TRUE); + /* LTPS I/F control */ + write_client_reg(ASY_DATB, 0x000003FD, TRUE); + /* Direct cmd transfer enable */ + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + /* Direct cmd transfer disable */ + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_READY, + TOSHIBA_STATE_SEC_NORMAL_MODE); +} + +static void toshiba_prim_lcd_off(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + gordon_disp_off(); + } else{ + + /* Main panel power off (Deep standby in) */ + write_client_reg(SSITX, 0x000800BC, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x00000028, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800B8, TRUE); + write_client_reg(SSITX, 0x00000180, TRUE); + write_client_reg(SSITX, 0x00000102, TRUE); + write_client_reg(SSITX, 0x00000010, TRUE); + } + write_client_reg(PORT, 0x00000003, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + mddi_wait(1); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + mddi_wait(3); + if (TM_GET_PID(mfd->panel.id) != LCD_SHARP_2P4_VGA) { + write_client_reg(SSITX, 0x000800B0, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + } + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_NORMAL_MODE, + TOSHIBA_STATE_PRIM_SEC_STANDBY); +} + +static void toshiba_sec_lcd_off(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004016, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000019, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x0000000B, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000002, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000300, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004004, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(PORT, 0x00000000, TRUE); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + mddi_toshiba_state_transition(TOSHIBA_STATE_SEC_NORMAL_MODE, + TOSHIBA_STATE_PRIM_SEC_STANDBY); +} + +static void toshiba_sec_cont_update_start(struct msm_fb_data_type *mfd) +{ + + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(INTMASK, 0x00000001, TRUE); + write_client_reg(TTBUSSEL, 0x0000000B, TRUE); + write_client_reg(MONI, 0x00000008, TRUE); + write_client_reg(CLKENB, 0x000000EF, TRUE); + write_client_reg(CLKENB, 0x000010EF, TRUE); + write_client_reg(CLKENB, 0x000011EF, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(HCYCLE, 0x0000006B, TRUE); + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000002, TRUE); + write_client_reg(HDE_SIZE, 0x00000057, TRUE); + write_client_reg(VCYCLE, 0x000000E6, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x000000DB, TRUE); + write_client_reg(WRSTB, 0x00000015, TRUE); + write_client_reg(MPLFBUF, 0x00000004, TRUE); + write_client_reg(ASY_DATA, 0x80000021, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x80000022, TRUE); + write_client_reg(ASY_CMDSET, 0x00000007, TRUE); + write_client_reg(PXL, 0x00000089, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + mddi_wait(2); +} + +static void toshiba_sec_cont_update_stop(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + mddi_wait(3); + write_client_reg(SRST, 0x00000002, TRUE); + mddi_wait(3); + write_client_reg(SRST, 0x00000003, TRUE); +} + +static void toshiba_sec_backlight_on(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + write_client_reg(PWM0OFF, 0x00000001, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00001387, TRUE); + write_client_reg(TIMER0CTRL, 0x000000E0, TRUE); + write_client_reg(TIMER1CTRL, 0x000000E0, TRUE); + write_client_reg(PWMCR, 0x00000003, TRUE); +} + +static void toshiba_sec_sleep_in(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004016, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000019, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x0000000B, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000002, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000300, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004004, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(PORT, 0x00000000, TRUE); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + /* Sleep in sequence */ + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000302, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); +} + +static void toshiba_sec_sleep_out(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000300, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + /* Display ON sequence */ + write_client_reg(ASY_DATA, 0x80000011, TRUE); + write_client_reg(ASY_DATB, 0x00000812, TRUE); + write_client_reg(ASY_DATC, 0x80000012, TRUE); + write_client_reg(ASY_DATD, 0x00000003, TRUE); + write_client_reg(ASY_DATE, 0x80000013, TRUE); + write_client_reg(ASY_DATF, 0x00000909, TRUE); + write_client_reg(ASY_DATG, 0x80000010, TRUE); + write_client_reg(ASY_DATH, 0x00000040, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000340, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(6); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00003340, TRUE); + write_client_reg(ASY_DATC, 0x80000007, TRUE); + write_client_reg(ASY_DATD, 0x00004007, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + mddi_wait(1); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004017, TRUE); + write_client_reg(ASY_DATC, 0x8000005B, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000059, TRUE); + write_client_reg(ASY_DATF, 0x00000011, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000D, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000C, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000019, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000079, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x000003FD, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); +} + +static void mddi_toshiba_lcd_set_backlight(struct msm_fb_data_type *mfd) +{ + int32 level; + int ret = -EPERM; + int max = mfd->panel_info.bl_max; + int min = mfd->panel_info.bl_min; + + if (mddi_toshiba_pdata && mddi_toshiba_pdata->pmic_backlight) { + ret = mddi_toshiba_pdata->pmic_backlight(mfd->bl_level); + if (!ret) + return; + } + + if (ret && mddi_toshiba_pdata && mddi_toshiba_pdata->backlight_level) { + level = mddi_toshiba_pdata->backlight_level(mfd->bl_level, + max, min); + + if (level < 0) + return; + + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + } else { + if (!max) + level = 0; + else + level = (mfd->bl_level * 4999) / max; + } + + write_client_reg(PWM0OFF, level, TRUE); +} + +static void mddi_toshiba_vsync_set_handler(msm_fb_vsync_handler_type handler, /* ISR to be executed */ + void *arg) +{ + boolean error = FALSE; + unsigned long flags; + + /* Disable interrupts */ + spin_lock_irqsave(&mddi_host_spin_lock, flags); + /* INTLOCK(); */ + + if (mddi_toshiba_vsync_handler != NULL) { + error = TRUE; + } else { + /* Register the handler for this particular GROUP interrupt source */ + mddi_toshiba_vsync_handler = handler; + mddi_toshiba_vsync_handler_arg = arg; + } + + /* Restore interrupts */ + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + /* MDDI_INTFREE(); */ + if (error) { + MDDI_MSG_ERR("MDDI: Previous Vsync handler never called\n"); + } else { + /* Enable the vsync wakeup */ + mddi_queue_register_write(INTMSK, 0x0000, FALSE, 0); + + mddi_toshiba_vsync_attempts = 1; + mddi_vsync_detect_enabled = TRUE; + } +} /* mddi_toshiba_vsync_set_handler */ + +static void mddi_toshiba_lcd_vsync_detected(boolean detected) +{ + /* static timetick_type start_time = 0; */ + static struct timeval start_time; + static boolean first_time = TRUE; + /* uint32 mdp_cnt_val = 0; */ + /* timetick_type elapsed_us; */ + struct timeval now; + uint32 elapsed_us; + uint32 num_vsyncs; + + if ((detected) || (mddi_toshiba_vsync_attempts > 5)) { + if ((detected) && (mddi_toshiba_monitor_refresh_value)) { + /* if (start_time != 0) */ + if (!first_time) { + jiffies_to_timeval(jiffies, &now); + elapsed_us = + (now.tv_sec - start_time.tv_sec) * 1000000 + + now.tv_usec - start_time.tv_usec; + /* + * LCD is configured for a refresh every usecs, + * so to determine the number of vsyncs that + * have occurred since the last measurement + * add half that to the time difference and + * divide by the refresh rate. + */ + num_vsyncs = (elapsed_us + + (mddi_toshiba_usecs_per_refresh >> + 1)) / + mddi_toshiba_usecs_per_refresh; + /* + * LCD is configured for * hsyncs (rows) per + * refresh cycle. Calculate new rows_per_second + * value based upon these new measurements. + * MDP can update with this new value. + */ + mddi_toshiba_rows_per_second = + (mddi_toshiba_rows_per_refresh * 1000 * + num_vsyncs) / (elapsed_us / 1000); + } + /* start_time = timetick_get(); */ + first_time = FALSE; + jiffies_to_timeval(jiffies, &start_time); + if (mddi_toshiba_report_refresh_measurements) { + (void)mddi_queue_register_read_int(VPOS, + &mddi_toshiba_curr_vpos); + /* mdp_cnt_val = MDP_LINE_COUNT; */ + } + } + /* if detected = TRUE, client initiated wakeup was detected */ + if (mddi_toshiba_vsync_handler != NULL) { + (*mddi_toshiba_vsync_handler) + (mddi_toshiba_vsync_handler_arg); + mddi_toshiba_vsync_handler = NULL; + } + mddi_vsync_detect_enabled = FALSE; + mddi_toshiba_vsync_attempts = 0; + /* need to disable the interrupt wakeup */ + if (!mddi_queue_register_write_int(INTMSK, 0x0001)) + MDDI_MSG_ERR("Vsync interrupt disable failed!\n"); + if (!detected) { + /* give up after 5 failed attempts but show error */ + MDDI_MSG_NOTICE("Vsync detection failed!\n"); + } else if ((mddi_toshiba_monitor_refresh_value) && + (mddi_toshiba_report_refresh_measurements)) { + MDDI_MSG_NOTICE(" Last Line Counter=%d!\n", + mddi_toshiba_curr_vpos); + /* MDDI_MSG_NOTICE(" MDP Line Counter=%d!\n",mdp_cnt_val); */ + MDDI_MSG_NOTICE(" Lines Per Second=%d!\n", + mddi_toshiba_rows_per_second); + } + /* clear the interrupt */ + if (!mddi_queue_register_write_int(INTFLG, 0x0001)) + MDDI_MSG_ERR("Vsync interrupt clear failed!\n"); + } else { + /* if detected = FALSE, we woke up from hibernation, but did not + * detect client initiated wakeup. + */ + mddi_toshiba_vsync_attempts++; + } +} + +static void mddi_toshiba_prim_init(struct msm_fb_data_type *mfd) +{ + + switch (toshiba_state) { + case TOSHIBA_STATE_PRIM_SEC_READY: + break; + case TOSHIBA_STATE_OFF: + toshiba_state = TOSHIBA_STATE_PRIM_SEC_STANDBY; + toshiba_common_initial_setup(mfd); + break; + case TOSHIBA_STATE_PRIM_SEC_STANDBY: + toshiba_common_initial_setup(mfd); + break; + case TOSHIBA_STATE_SEC_NORMAL_MODE: + toshiba_sec_cont_update_stop(mfd); + toshiba_sec_sleep_in(mfd); + toshiba_sec_sleep_out(mfd); + toshiba_sec_lcd_off(mfd); + toshiba_common_initial_setup(mfd); + break; + default: + MDDI_MSG_ERR("mddi_toshiba_prim_init from state %d\n", + toshiba_state); + } + + toshiba_prim_start(mfd); + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) + gordon_disp_init(); + mddi_host_write_pix_attr_reg(0x00C3); +} + +static void mddi_toshiba_sec_init(struct msm_fb_data_type *mfd) +{ + + switch (toshiba_state) { + case TOSHIBA_STATE_PRIM_SEC_READY: + break; + case TOSHIBA_STATE_PRIM_SEC_STANDBY: + toshiba_common_initial_setup(mfd); + break; + case TOSHIBA_STATE_PRIM_NORMAL_MODE: + toshiba_prim_lcd_off(mfd); + toshiba_common_initial_setup(mfd); + break; + default: + MDDI_MSG_ERR("mddi_toshiba_sec_init from state %d\n", + toshiba_state); + } + + toshiba_sec_start(mfd); + toshiba_sec_backlight_on(mfd); + toshiba_sec_cont_update_start(mfd); + mddi_host_write_pix_attr_reg(0x0400); +} + +static void mddi_toshiba_lcd_powerdown(struct msm_fb_data_type *mfd) +{ + switch (toshiba_state) { + case TOSHIBA_STATE_PRIM_SEC_READY: + mddi_toshiba_prim_init(mfd); + mddi_toshiba_lcd_powerdown(mfd); + return; + case TOSHIBA_STATE_PRIM_SEC_STANDBY: + break; + case TOSHIBA_STATE_PRIM_NORMAL_MODE: + toshiba_prim_lcd_off(mfd); + break; + case TOSHIBA_STATE_SEC_NORMAL_MODE: + toshiba_sec_cont_update_stop(mfd); + toshiba_sec_sleep_in(mfd); + toshiba_sec_sleep_out(mfd); + toshiba_sec_lcd_off(mfd); + break; + default: + MDDI_MSG_ERR("mddi_toshiba_lcd_powerdown from state %d\n", + toshiba_state); + } +} + +static int mddi_sharpgordon_firsttime = 1; + +static int mddi_toshiba_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + mfd = platform_get_drvdata(pdev); + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (TM_GET_DID(mfd->panel.id) == TOSHIBA_VGA_PRIM) + mddi_toshiba_prim_init(mfd); + else + mddi_toshiba_sec_init(mfd); + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + if (mddi_sharpgordon_firsttime) { + mddi_sharpgordon_firsttime = 0; + write_client_reg(REGENB, 0x00000001, TRUE); + } + } + return 0; +} + +static int mddi_toshiba_lcd_off(struct platform_device *pdev) +{ + mddi_toshiba_lcd_powerdown(platform_get_drvdata(pdev)); + return 0; +} + +static int __init mddi_toshiba_lcd_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + mddi_toshiba_pdata = pdev->dev.platform_data; + return 0; + } + + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mddi_toshiba_lcd_probe, + .driver = { + .name = "mddi_toshiba", + }, +}; + +static struct msm_fb_panel_data toshiba_panel_data = { + .on = mddi_toshiba_lcd_on, + .off = mddi_toshiba_lcd_off, +}; + +static int ch_used[3]; + +int mddi_toshiba_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + if ((channel != TOSHIBA_VGA_PRIM) && + mddi_toshiba_pdata && mddi_toshiba_pdata->panel_num) + if (mddi_toshiba_pdata->panel_num() < 2) + return -ENODEV; + + ch_used[channel] = TRUE; + + pdev = platform_device_alloc("mddi_toshiba", (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + if (channel == TOSHIBA_VGA_PRIM) { + toshiba_panel_data.set_backlight = + mddi_toshiba_lcd_set_backlight; + + if (pinfo->lcd.vsync_enable) { + toshiba_panel_data.set_vsync_notifier = + mddi_toshiba_vsync_set_handler; + mddi_lcd.vsync_detected = + mddi_toshiba_lcd_vsync_detected; + } + } else { + toshiba_panel_data.set_backlight = NULL; + toshiba_panel_data.set_vsync_notifier = NULL; + } + + toshiba_panel_data.panel_info = *pinfo; + + ret = platform_device_add_data(pdev, &toshiba_panel_data, + sizeof(toshiba_panel_data)); + if (ret) { + printk(KERN_ERR + "%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + printk(KERN_ERR + "%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static int __init mddi_toshiba_lcd_init(void) +{ + return platform_driver_register(&this_driver); +} + +module_init(mddi_toshiba_lcd_init); diff --git a/drivers/staging/msm/mddi_toshiba.h b/drivers/staging/msm/mddi_toshiba.h new file mode 100644 index 000000000000..2d22b9a2c413 --- /dev/null +++ b/drivers/staging/msm/mddi_toshiba.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * + */ + +#ifndef MDDI_TOSHIBA_H +#define MDDI_TOSHIBA_H + +#define TOSHIBA_VGA_PRIM 1 +#define TOSHIBA_VGA_SECD 2 + +#define LCD_TOSHIBA_2P4_VGA 0 +#define LCD_TOSHIBA_2P4_WVGA 1 +#define LCD_TOSHIBA_2P4_WVGA_PT 2 +#define LCD_SHARP_2P4_VGA 3 + +#define GPIO_BLOCK_BASE 0x150000 +#define SYSTEM_BLOCK2_BASE 0x170000 + +#define GPIODIR (GPIO_BLOCK_BASE|0x04) +#define GPIOSEL (SYSTEM_BLOCK2_BASE|0x00) +#define GPIOPC (GPIO_BLOCK_BASE|0x28) +#define GPIODATA (GPIO_BLOCK_BASE|0x00) + +#define write_client_reg(__X, __Y, __Z) {\ + mddi_queue_register_write(__X, __Y, TRUE, 0);\ +} + +#endif /* MDDI_TOSHIBA_H */ diff --git a/drivers/staging/msm/mddi_toshiba_vga.c b/drivers/staging/msm/mddi_toshiba_vga.c new file mode 100644 index 000000000000..7e61d3a5b8f1 --- /dev/null +++ b/drivers/staging/msm/mddi_toshiba_vga.c @@ -0,0 +1,136 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" +#include "mddi_toshiba.h" + +static uint32 read_client_reg(uint32 addr) +{ + uint32 val; + mddi_queue_register_read(addr, &val, TRUE, 0); + return val; +} + +static uint32 toshiba_lcd_gpio_read(void) +{ + uint32 val; + + write_client_reg(GPIODIR, 0x0000000C, TRUE); + write_client_reg(GPIOSEL, 0x00000000, TRUE); + write_client_reg(GPIOSEL, 0x00000000, TRUE); + write_client_reg(GPIOPC, 0x03CF00C0, TRUE); + val = read_client_reg(GPIODATA) & 0x2C0; + + return val; +} + +static u32 mddi_toshiba_panel_detect(void) +{ + mddi_host_type host_idx = MDDI_HOST_PRIM; + uint32 lcd_gpio; + u32 mddi_toshiba_lcd = LCD_TOSHIBA_2P4_VGA; + + /* Toshiba display requires larger drive_lo value */ + mddi_host_reg_out(DRIVE_LO, 0x0050); + + lcd_gpio = toshiba_lcd_gpio_read(); + switch (lcd_gpio) { + case 0x0080: + mddi_toshiba_lcd = LCD_SHARP_2P4_VGA; + break; + + case 0x00C0: + default: + mddi_toshiba_lcd = LCD_TOSHIBA_2P4_VGA; + break; + } + + return mddi_toshiba_lcd; +} + +static int __init mddi_toshiba_vga_init(void) +{ + int ret; + struct msm_panel_info pinfo; + u32 panel; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; + + ret = msm_fb_detect_client("mddi_toshiba_vga"); + if (ret == -ENODEV) + return 0; + + if (ret) { + id = mddi_get_client_id(); + if ((id >> 16) != 0xD263) + return 0; + } +#endif + + panel = mddi_toshiba_panel_detect(); + + pinfo.xres = 480; + pinfo.yres = 640; + pinfo.type = MDDI_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.lcd.vsync_enable = TRUE; + pinfo.lcd.refx100 = 6118; + pinfo.lcd.v_back_porch = 6; + pinfo.lcd.v_front_porch = 0; + pinfo.lcd.v_pulse_width = 0; + pinfo.lcd.hw_vsync_mode = FALSE; + pinfo.lcd.vsync_notifier_period = (1 * HZ); + pinfo.bl_max = 99; + pinfo.bl_min = 1; + pinfo.clk_rate = 122880000; + pinfo.clk_min = 120000000; + pinfo.clk_max = 200000000; + pinfo.fb_num = 2; + + ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM, panel); + if (ret) { + printk(KERN_ERR "%s: failed to register device!\n", __func__); + return ret; + } + + pinfo.xres = 176; + pinfo.yres = 220; + pinfo.type = MDDI_PANEL; + pinfo.pdest = DISPLAY_2; + pinfo.mddi.vdopkt = 0x400; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.clk_rate = 122880000; + pinfo.clk_min = 120000000; + pinfo.clk_max = 200000000; + pinfo.fb_num = 2; + + ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_SECD, panel); + if (ret) + printk(KERN_WARNING + "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mddi_toshiba_vga_init); diff --git a/drivers/staging/msm/mddi_toshiba_wvga.c b/drivers/staging/msm/mddi_toshiba_wvga.c new file mode 100644 index 000000000000..557b0f08faf8 --- /dev/null +++ b/drivers/staging/msm/mddi_toshiba_wvga.c @@ -0,0 +1,63 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddi_toshiba.h" + +static int __init mddi_toshiba_wvga_init(void) +{ + int ret; + struct msm_panel_info pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + if (msm_fb_detect_client("mddi_toshiba_wvga")) + return 0; +#endif + + pinfo.xres = 800; + pinfo.yres = 480; + pinfo.pdest = DISPLAY_2; + pinfo.type = MDDI_PANEL; + pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.lcd.vsync_enable = TRUE; + pinfo.lcd.refx100 = 6118; + pinfo.lcd.v_back_porch = 6; + pinfo.lcd.v_front_porch = 0; + pinfo.lcd.v_pulse_width = 0; + pinfo.lcd.hw_vsync_mode = FALSE; + pinfo.lcd.vsync_notifier_period = (1 * HZ); + pinfo.bl_max = 4; + pinfo.bl_min = 1; + pinfo.clk_rate = 192000000; + pinfo.clk_min = 190000000; + pinfo.clk_max = 200000000; + pinfo.fb_num = 2; + + ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM, + LCD_TOSHIBA_2P4_WVGA); + if (ret) { + printk(KERN_ERR "%s: failed to register device!\n", __func__); + return ret; + } + + return ret; +} + +module_init(mddi_toshiba_wvga_init); diff --git a/drivers/staging/msm/mddi_toshiba_wvga_pt.c b/drivers/staging/msm/mddi_toshiba_wvga_pt.c new file mode 100644 index 000000000000..fc7d4e0d294f --- /dev/null +++ b/drivers/staging/msm/mddi_toshiba_wvga_pt.c @@ -0,0 +1,64 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" +#include "mddi_toshiba.h" + +static int __init mddi_toshiba_wvga_pt_init(void) +{ + int ret; + struct msm_panel_info pinfo; +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + uint id; + + ret = msm_fb_detect_client("mddi_toshiba_wvga_pt"); + if (ret == -ENODEV) + return 0; + + if (ret) { + id = mddi_get_client_id(); + if (id != 0xd2638722) + return 0; + } +#endif + + pinfo.xres = 480; + pinfo.yres = 800; + pinfo.type = MDDI_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.lcd.vsync_enable = FALSE; + pinfo.bl_max = 15; + pinfo.bl_min = 1; + pinfo.clk_rate = 192000000; + pinfo.clk_min = 190000000; + pinfo.clk_max = 200000000; + pinfo.fb_num = 2; + + ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM, + LCD_TOSHIBA_2P4_WVGA_PT); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mddi_toshiba_wvga_pt_init); diff --git a/drivers/staging/msm/mddihost.c b/drivers/staging/msm/mddihost.c new file mode 100644 index 000000000000..c6c1ee4eda05 --- /dev/null +++ b/drivers/staging/msm/mddihost.c @@ -0,0 +1,377 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +#include <linux/clk.h> +#include <mach/clk.h> + +struct semaphore mddi_host_mutex; + +struct clk *mddi_io_clk; +static boolean mddi_host_powered = FALSE; +static boolean mddi_host_initialized = FALSE; +extern uint32 *mddi_reg_read_value_ptr; + +mddi_lcd_func_type mddi_lcd; + +extern mddi_client_capability_type mddi_client_capability_pkt; + +#ifdef FEATURE_MDDI_HITACHI +extern void mddi_hitachi_window_adjust(uint16 x1, + uint16 x2, uint16 y1, uint16 y2); +#endif + +extern void mddi_toshiba_lcd_init(void); + +#ifdef FEATURE_MDDI_S6D0142 +extern void mddi_s6d0142_lcd_init(void); +extern void mddi_s6d0142_window_adjust(uint16 x1, + uint16 x2, + uint16 y1, + uint16 y2, + mddi_llist_done_cb_type done_cb); +#endif + +void mddi_init(void) +{ + if (mddi_host_initialized) + return; + + mddi_host_initialized = TRUE; + + init_MUTEX(&mddi_host_mutex); + + if (!mddi_host_powered) { + down(&mddi_host_mutex); + mddi_host_init(MDDI_HOST_PRIM); + mddi_host_powered = TRUE; + up(&mddi_host_mutex); + mdelay(10); + } +} + +int mddi_host_register_read(uint32 reg_addr, + uint32 *reg_value_ptr, boolean wait, mddi_host_type host) { + mddi_linked_list_type *curr_llist_ptr; + mddi_register_access_packet_type *regacc_pkt_ptr; + uint16 curr_llist_idx; + int ret = 0; + + if (in_interrupt()) + MDDI_MSG_CRIT("Called from ISR context\n"); + + if (!mddi_host_powered) { + MDDI_MSG_ERR("MDDI powered down!\n"); + mddi_init(); + } + + down(&mddi_host_mutex); + + mddi_reg_read_value_ptr = reg_value_ptr; + curr_llist_idx = mddi_get_reg_read_llist_item(host, TRUE); + if (curr_llist_idx == UNASSIGNED_INDEX) { + up(&mddi_host_mutex); + + /* need to change this to some sort of wait */ + MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n"); + return -EINVAL; + } + + curr_llist_ptr = &llist_extern[host][curr_llist_idx]; + curr_llist_ptr->link_controller_flags = 0x11; + curr_llist_ptr->packet_header_count = 14; + curr_llist_ptr->packet_data_count = 0; + + curr_llist_ptr->next_packet_pointer = NULL; + curr_llist_ptr->packet_data_pointer = NULL; + curr_llist_ptr->reserved = 0; + + regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; + + regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count; + regacc_pkt_ptr->packet_type = 146; /* register access packet */ + regacc_pkt_ptr->bClient_ID = 0; + regacc_pkt_ptr->read_write_info = 0x8001; + regacc_pkt_ptr->register_address = reg_addr; + + /* now adjust pointers */ + mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait, + NULL, host); + /* need to check if we can write the pointer or not */ + + up(&mddi_host_mutex); + + if (wait) { + int wait_ret; + + mddi_linked_list_notify_type *llist_notify_ptr; + llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx]; + wait_ret = wait_for_completion_timeout( + &(llist_notify_ptr->done_comp), 5 * HZ); + + if (wait_ret <= 0) + ret = -EBUSY; + + if (wait_ret < 0) + printk(KERN_ERR "%s: failed to wait for completion!\n", + __func__); + else if (!wait_ret) + printk(KERN_ERR "%s: Timed out waiting!\n", __func__); + } + + MDDI_MSG_DEBUG("Reg Read value=0x%x\n", *reg_value_ptr); + + return ret; +} /* mddi_host_register_read */ + +int mddi_host_register_write(uint32 reg_addr, + uint32 reg_val, enum mddi_data_packet_size_type packet_size, + boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host) { + mddi_linked_list_type *curr_llist_ptr; + mddi_linked_list_type *curr_llist_dma_ptr; + mddi_register_access_packet_type *regacc_pkt_ptr; + uint16 curr_llist_idx; + int ret = 0; + + if (in_interrupt()) + MDDI_MSG_CRIT("Called from ISR context\n"); + + if (!mddi_host_powered) { + MDDI_MSG_ERR("MDDI powered down!\n"); + mddi_init(); + } + + down(&mddi_host_mutex); + + curr_llist_idx = mddi_get_next_free_llist_item(host, TRUE); + curr_llist_ptr = &llist_extern[host][curr_llist_idx]; + curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx]; + + curr_llist_ptr->link_controller_flags = 1; + curr_llist_ptr->packet_header_count = 14; + curr_llist_ptr->packet_data_count = 4; + + curr_llist_ptr->next_packet_pointer = NULL; + curr_llist_ptr->reserved = 0; + + regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; + + regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + + (uint16)packet_size; + regacc_pkt_ptr->packet_type = 146; /* register access packet */ + regacc_pkt_ptr->bClient_ID = 0; + regacc_pkt_ptr->read_write_info = 0x0001; + regacc_pkt_ptr->register_address = reg_addr; + regacc_pkt_ptr->register_data_list = reg_val; + + MDDI_MSG_DEBUG("Reg Access write reg=0x%x, value=0x%x\n", + regacc_pkt_ptr->register_address, + regacc_pkt_ptr->register_data_list); + + regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt; + curr_llist_ptr->packet_data_pointer = + (void *)(®acc_pkt_ptr->register_data_list); + + /* now adjust pointers */ + mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait, + done_cb, host); + + up(&mddi_host_mutex); + + if (wait) { + int wait_ret; + + mddi_linked_list_notify_type *llist_notify_ptr; + llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx]; + wait_ret = wait_for_completion_timeout( + &(llist_notify_ptr->done_comp), 5 * HZ); + + if (wait_ret <= 0) + ret = -EBUSY; + + if (wait_ret < 0) + printk(KERN_ERR "%s: failed to wait for completion!\n", + __func__); + else if (!wait_ret) + printk(KERN_ERR "%s: Timed out waiting!\n", __func__); + } + + return ret; +} /* mddi_host_register_write */ + +boolean mddi_host_register_read_int + (uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host) { + mddi_linked_list_type *curr_llist_ptr; + mddi_register_access_packet_type *regacc_pkt_ptr; + uint16 curr_llist_idx; + + if (!in_interrupt()) + MDDI_MSG_CRIT("Called from TASK context\n"); + + if (!mddi_host_powered) { + MDDI_MSG_ERR("MDDI powered down!\n"); + return FALSE; + } + + if (down_trylock(&mddi_host_mutex) != 0) + return FALSE; + + mddi_reg_read_value_ptr = reg_value_ptr; + curr_llist_idx = mddi_get_reg_read_llist_item(host, FALSE); + if (curr_llist_idx == UNASSIGNED_INDEX) { + up(&mddi_host_mutex); + return FALSE; + } + + curr_llist_ptr = &llist_extern[host][curr_llist_idx]; + curr_llist_ptr->link_controller_flags = 0x11; + curr_llist_ptr->packet_header_count = 14; + curr_llist_ptr->packet_data_count = 0; + + curr_llist_ptr->next_packet_pointer = NULL; + curr_llist_ptr->packet_data_pointer = NULL; + curr_llist_ptr->reserved = 0; + + regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; + + regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count; + regacc_pkt_ptr->packet_type = 146; /* register access packet */ + regacc_pkt_ptr->bClient_ID = 0; + regacc_pkt_ptr->read_write_info = 0x8001; + regacc_pkt_ptr->register_address = reg_addr; + + /* now adjust pointers */ + mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE, + NULL, host); + /* need to check if we can write the pointer or not */ + + up(&mddi_host_mutex); + + return TRUE; + +} /* mddi_host_register_read */ + +boolean mddi_host_register_write_int + (uint32 reg_addr, + uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host) { + mddi_linked_list_type *curr_llist_ptr; + mddi_linked_list_type *curr_llist_dma_ptr; + mddi_register_access_packet_type *regacc_pkt_ptr; + uint16 curr_llist_idx; + + if (!in_interrupt()) + MDDI_MSG_CRIT("Called from TASK context\n"); + + if (!mddi_host_powered) { + MDDI_MSG_ERR("MDDI powered down!\n"); + return FALSE; + } + + if (down_trylock(&mddi_host_mutex) != 0) + return FALSE; + + curr_llist_idx = mddi_get_next_free_llist_item(host, FALSE); + if (curr_llist_idx == UNASSIGNED_INDEX) { + up(&mddi_host_mutex); + return FALSE; + } + + curr_llist_ptr = &llist_extern[host][curr_llist_idx]; + curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx]; + + curr_llist_ptr->link_controller_flags = 1; + curr_llist_ptr->packet_header_count = 14; + curr_llist_ptr->packet_data_count = 4; + + curr_llist_ptr->next_packet_pointer = NULL; + curr_llist_ptr->reserved = 0; + + regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; + + regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + 4; + regacc_pkt_ptr->packet_type = 146; /* register access packet */ + regacc_pkt_ptr->bClient_ID = 0; + regacc_pkt_ptr->read_write_info = 0x0001; + regacc_pkt_ptr->register_address = reg_addr; + regacc_pkt_ptr->register_data_list = reg_val; + + regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt; + curr_llist_ptr->packet_data_pointer = + (void *)(&(regacc_pkt_ptr->register_data_list)); + + /* now adjust pointers */ + mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE, + done_cb, host); + up(&mddi_host_mutex); + + return TRUE; + +} /* mddi_host_register_write */ + +void mddi_wait(uint16 time_ms) +{ + mdelay(time_ms); +} + +void mddi_client_lcd_vsync_detected(boolean detected) +{ + if (mddi_lcd.vsync_detected) + (*mddi_lcd.vsync_detected) (detected); +} + +/* extended version of function includes done callback */ +void mddi_window_adjust_ext(struct msm_fb_data_type *mfd, + uint16 x1, + uint16 x2, + uint16 y1, + uint16 y2, mddi_llist_done_cb_type done_cb) +{ +#ifdef FEATURE_MDDI_HITACHI + if (mfd->panel.id == HITACHI) + mddi_hitachi_window_adjust(x1, x2, y1, y2); +#elif defined(FEATURE_MDDI_S6D0142) + if (mfd->panel.id == MDDI_LCD_S6D0142) + mddi_s6d0142_window_adjust(x1, x2, y1, y2, done_cb); +#else + /* Do nothing then... except avoid lint/compiler warnings */ + (void)x1; + (void)x2; + (void)y1; + (void)y2; + (void)done_cb; +#endif +} + +void mddi_window_adjust(struct msm_fb_data_type *mfd, + uint16 x1, uint16 x2, uint16 y1, uint16 y2) +{ + mddi_window_adjust_ext(mfd, x1, x2, y1, y2, NULL); +} diff --git a/drivers/staging/msm/mddihost.h b/drivers/staging/msm/mddihost.h new file mode 100644 index 000000000000..20b817841c4a --- /dev/null +++ b/drivers/staging/msm/mddihost.h @@ -0,0 +1,225 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * + */ + +#ifndef MDDIHOST_H +#define MDDIHOST_H + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include "linux/proc_fs.h" +#include <linux/types.h> +#include <linux/dma-mapping.h> +#include <linux/clk.h> + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/types.h> +#include <linux/dma-mapping.h> + +#include "msm_fb_panel.h" + +#undef FEATURE_MDDI_MC4 +#undef FEATURE_MDDI_S6D0142 +#undef FEATURE_MDDI_HITACHI +#define FEATURE_MDDI_SHARP +#define FEATURE_MDDI_TOSHIBA +#undef FEATURE_MDDI_E751 +#define FEATURE_MDDI_CORONA +#define FEATURE_MDDI_PRISM + +#define T_MSM7500 + +typedef enum { + format_16bpp, + format_18bpp, + format_24bpp +} mddi_video_format; + +typedef enum { + MDDI_LCD_NONE = 0, + MDDI_LCD_MC4, + MDDI_LCD_S6D0142, + MDDI_LCD_SHARP, + MDDI_LCD_E751, + MDDI_LCD_CORONA, + MDDI_LCD_HITACHI, + MDDI_LCD_TOSHIBA, + MDDI_LCD_PRISM, + MDDI_LCD_TP2, + MDDI_NUM_LCD_TYPES, + MDDI_LCD_DEFAULT = MDDI_LCD_TOSHIBA +} mddi_lcd_type; + +typedef enum { + MDDI_HOST_PRIM = 0, + MDDI_HOST_EXT, + MDDI_NUM_HOST_CORES +} mddi_host_type; + +typedef enum { + MDDI_DRIVER_RESET, /* host core registers have not been written. */ + MDDI_DRIVER_DISABLED, /* registers written, interrupts disabled. */ + MDDI_DRIVER_ENABLED /* registers written, interrupts enabled. */ +} mddi_host_driver_state_type; + +typedef enum { + MDDI_GPIO_INT_0 = 0, + MDDI_GPIO_INT_1, + MDDI_GPIO_INT_2, + MDDI_GPIO_INT_3, + MDDI_GPIO_INT_4, + MDDI_GPIO_INT_5, + MDDI_GPIO_INT_6, + MDDI_GPIO_INT_7, + MDDI_GPIO_INT_8, + MDDI_GPIO_INT_9, + MDDI_GPIO_INT_10, + MDDI_GPIO_INT_11, + MDDI_GPIO_INT_12, + MDDI_GPIO_INT_13, + MDDI_GPIO_INT_14, + MDDI_GPIO_INT_15, + MDDI_GPIO_NUM_INTS +} mddi_gpio_int_type; + +enum mddi_data_packet_size_type { + MDDI_DATA_PACKET_4_BYTES = 4, + MDDI_DATA_PACKET_8_BYTES = 8, + MDDI_DATA_PACKET_12_BYTES = 12, + MDDI_DATA_PACKET_16_BYTES = 16, + MDDI_DATA_PACKET_24_BYTES = 24 +}; + +typedef struct { + uint32 addr; + uint32 value; +} mddi_reg_write_type; + +boolean mddi_vsync_set_handler(msm_fb_vsync_handler_type handler, void *arg); + +typedef void (*mddi_llist_done_cb_type) (void); + +typedef void (*mddi_rev_handler_type) (void *); + +boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type); + +#define MDDI_DEFAULT_PRIM_PIX_ATTR 0xC3 +#define MDDI_DEFAULT_SECD_PIX_ATTR 0xC0 + +typedef int gpio_int_polarity_type; +typedef int gpio_int_handler_type; + +typedef struct { + void (*vsync_detected) (boolean); +} mddi_lcd_func_type; + +extern mddi_lcd_func_type mddi_lcd; +void mddi_init(void); + +void mddi_powerdown(void); + +void mddi_host_start_ext_display(void); +void mddi_host_stop_ext_display(void); + +extern spinlock_t mddi_host_spin_lock; +#ifdef T_MSM7500 +void mddi_reset(void); +#ifdef FEATURE_DUAL_PROC_MODEM_DISPLAY +void mddi_host_switch_proc_control(boolean on); +#endif +#endif +void mddi_host_exit_power_collapse(void); + +void mddi_queue_splash_screen + (void *buf_ptr, + boolean clear_area, + int16 src_width, + int16 src_starting_row, + int16 src_starting_column, + int16 num_of_rows, + int16 num_of_columns, int16 dst_starting_row, int16 dst_starting_column); + +void mddi_queue_image + (void *buf_ptr, + uint8 stereo_video, + boolean clear_area, + int16 src_width, + int16 src_starting_row, + int16 src_starting_column, + int16 num_of_rows, + int16 num_of_columns, int16 dst_starting_row, int16 dst_starting_column); + +int mddi_host_register_read + (uint32 reg_addr, + uint32 *reg_value_ptr, boolean wait, mddi_host_type host_idx); +int mddi_host_register_write + (uint32 reg_addr, uint32 reg_val, + enum mddi_data_packet_size_type packet_size, + boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host); +boolean mddi_host_register_write_int + (uint32 reg_addr, + uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host); +boolean mddi_host_register_read_int + (uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host_idx); +void mddi_queue_register_write_static + (uint32 reg_addr, + uint32 reg_val, boolean wait, mddi_llist_done_cb_type done_cb); +void mddi_queue_static_window_adjust + (const mddi_reg_write_type *reg_write, + uint16 num_writes, mddi_llist_done_cb_type done_cb); + +#define mddi_queue_register_read(reg, val_ptr, wait, sig) \ + mddi_host_register_read(reg, val_ptr, wait, MDDI_HOST_PRIM) +#define mddi_queue_register_write(reg, val, wait, sig) \ + mddi_host_register_write(reg, val, MDDI_DATA_PACKET_4_BYTES,\ + wait, NULL, MDDI_HOST_PRIM) +#define mddi_queue_register_write_extn(reg, val, pkt_size, wait, sig) \ + mddi_host_register_write(reg, val, pkt_size, \ + wait, NULL, MDDI_HOST_PRIM) +#define mddi_queue_register_write_int(reg, val) \ + mddi_host_register_write_int(reg, val, NULL, MDDI_HOST_PRIM) +#define mddi_queue_register_read_int(reg, val_ptr) \ + mddi_host_register_read_int(reg, val_ptr, MDDI_HOST_PRIM) +#define mddi_queue_register_writes(reg_ptr, val, wait, sig) \ + mddi_host_register_writes(reg_ptr, val, wait, sig, MDDI_HOST_PRIM) + +void mddi_wait(uint16 time_ms); +void mddi_assign_max_pkt_dimensions(uint16 image_cols, + uint16 image_rows, + uint16 bpp, + uint16 *max_cols, uint16 * max_rows); +uint16 mddi_assign_pkt_height(uint16 pkt_width, uint16 pkt_height, uint16 bpp); +void mddi_queue_reverse_encapsulation(boolean wait); +void mddi_disable(int lock); +#endif /* MDDIHOST_H */ diff --git a/drivers/staging/msm/mddihost_e.c b/drivers/staging/msm/mddihost_e.c new file mode 100644 index 000000000000..7de5eda71ce3 --- /dev/null +++ b/drivers/staging/msm/mddihost_e.c @@ -0,0 +1,63 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +#include <linux/clk.h> +#include <mach/clk.h> + +extern struct semaphore mddi_host_mutex; +static boolean mddi_host_ext_powered = FALSE; + +void mddi_host_start_ext_display(void) +{ + down(&mddi_host_mutex); + + if (!mddi_host_ext_powered) { + mddi_host_init(MDDI_HOST_EXT); + + mddi_host_ext_powered = TRUE; + } + + up(&mddi_host_mutex); +} + +void mddi_host_stop_ext_display(void) +{ + down(&mddi_host_mutex); + + if (mddi_host_ext_powered) { + mddi_host_powerdown(MDDI_HOST_EXT); + + mddi_host_ext_powered = FALSE; + } + + up(&mddi_host_mutex); +} diff --git a/drivers/staging/msm/mddihosti.c b/drivers/staging/msm/mddihosti.c new file mode 100644 index 000000000000..f9d6e91e8d5d --- /dev/null +++ b/drivers/staging/msm/mddihosti.c @@ -0,0 +1,2239 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> + +#include "msm_fb_panel.h" +#include "mddihost.h" +#include "mddihosti.h" + +#define FEATURE_MDDI_UNDERRUN_RECOVERY +#ifndef FEATURE_MDDI_DISABLE_REVERSE +static void mddi_read_rev_packet(byte *data_ptr); +#endif + +struct timer_list mddi_host_timer; + +#define MDDI_DEFAULT_TIMER_LENGTH 5000 /* 5 seconds */ +uint32 mddi_rtd_frequency = 60000; /* send RTD every 60 seconds */ +uint32 mddi_client_status_frequency = 60000; /* get status pkt every 60 secs */ + +boolean mddi_vsync_detect_enabled = FALSE; +mddi_gpio_info_type mddi_gpio; + +uint32 mddi_host_core_version; +boolean mddi_debug_log_statistics = FALSE; +/* #define FEATURE_MDDI_HOST_ENABLE_EARLY_HIBERNATION */ +/* default to TRUE in case MDP does not vote */ +static boolean mddi_host_mdp_active_flag = TRUE; +static uint32 mddi_log_stats_counter; +uint32 mddi_log_stats_frequency = 4000; + +#define MDDI_DEFAULT_REV_PKT_SIZE 0x20 + +#ifndef FEATURE_MDDI_DISABLE_REVERSE +static boolean mddi_rev_ptr_workaround = TRUE; +static uint32 mddi_reg_read_retry; +static uint32 mddi_reg_read_retry_max = 20; +static boolean mddi_enable_reg_read_retry = TRUE; +static boolean mddi_enable_reg_read_retry_once = FALSE; + +#define MDDI_MAX_REV_PKT_SIZE 0x60 + +#define MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE 0x60 + +#define MDDI_VIDEO_REV_PKT_SIZE 0x40 +#define MDDI_REV_BUFFER_SIZE MDDI_MAX_REV_PKT_SIZE +static byte rev_packet_data[MDDI_MAX_REV_PKT_SIZE]; +#endif /* FEATURE_MDDI_DISABLE_REVERSE */ +/* leave these variables so graphics will compile */ + +#define MDDI_MAX_REV_DATA_SIZE 128 +/*lint -d__align(x) */ +boolean mddi_debug_clear_rev_data = TRUE; + +uint32 *mddi_reg_read_value_ptr; + +mddi_client_capability_type mddi_client_capability_pkt; +static boolean mddi_client_capability_request = FALSE; + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + +#define MAX_MDDI_REV_HANDLERS 2 +#define INVALID_PKT_TYPE 0xFFFF + +typedef struct { + mddi_rev_handler_type handler; /* ISR to be executed */ + uint16 pkt_type; +} mddi_rev_pkt_handler_type; +static mddi_rev_pkt_handler_type mddi_rev_pkt_handler[MAX_MDDI_REV_HANDLERS] = + { {NULL, INVALID_PKT_TYPE}, {NULL, INVALID_PKT_TYPE} }; + +static boolean mddi_rev_encap_user_request = FALSE; +static mddi_linked_list_notify_type mddi_rev_user; + +spinlock_t mddi_host_spin_lock; +extern uint32 mdp_in_processing; +#endif + +typedef enum { + MDDI_REV_IDLE +#ifndef FEATURE_MDDI_DISABLE_REVERSE + , MDDI_REV_REG_READ_ISSUED, + MDDI_REV_REG_READ_SENT, + MDDI_REV_ENCAP_ISSUED, + MDDI_REV_STATUS_REQ_ISSUED, + MDDI_REV_CLIENT_CAP_ISSUED +#endif +} mddi_rev_link_state_type; + +typedef enum { + MDDI_LINK_DISABLED, + MDDI_LINK_HIBERNATING, + MDDI_LINK_ACTIVATING, + MDDI_LINK_ACTIVE +} mddi_host_link_state_type; + +typedef struct { + uint32 count; + uint32 in_count; + uint32 disp_req_count; + uint32 state_change_count; + uint32 ll_done_count; + uint32 rev_avail_count; + uint32 error_count; + uint32 rev_encap_count; + uint32 llist_ptr_write_1; + uint32 llist_ptr_write_2; +} mddi_host_int_type; + +typedef struct { + uint32 fwd_crc_count; + uint32 rev_crc_count; + uint32 pri_underflow; + uint32 sec_underflow; + uint32 rev_overflow; + uint32 pri_overwrite; + uint32 sec_overwrite; + uint32 rev_overwrite; + uint32 dma_failure; + uint32 rtd_failure; + uint32 reg_read_failure; +#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY + uint32 pri_underrun_detected; +#endif +} mddi_host_stat_type; + +typedef struct { + uint32 rtd_cnt; + uint32 rev_enc_cnt; + uint32 vid_cnt; + uint32 reg_acc_cnt; + uint32 cli_stat_cnt; + uint32 cli_cap_cnt; + uint32 reg_read_cnt; + uint32 link_active_cnt; + uint32 link_hibernate_cnt; + uint32 vsync_response_cnt; + uint32 fwd_crc_cnt; + uint32 rev_crc_cnt; +} mddi_log_params_struct_type; + +typedef struct { + uint32 rtd_value; + uint32 rtd_counter; + uint32 client_status_cnt; + boolean rev_ptr_written; + uint8 *rev_ptr_start; + uint8 *rev_ptr_curr; + uint32 mddi_rev_ptr_write_val; + dma_addr_t rev_data_dma_addr; + uint16 rev_pkt_size; + mddi_rev_link_state_type rev_state; + mddi_host_link_state_type link_state; + mddi_host_driver_state_type driver_state; + boolean disable_hibernation; + uint32 saved_int_reg; + uint32 saved_int_en; + mddi_linked_list_type *llist_ptr; + dma_addr_t llist_dma_addr; + mddi_linked_list_type *llist_dma_ptr; + uint32 *rev_data_buf; + struct completion mddi_llist_avail_comp; + boolean mddi_waiting_for_llist_avail; + mddi_host_int_type int_type; + mddi_host_stat_type stats; + mddi_log_params_struct_type log_parms; + mddi_llist_info_type llist_info; + mddi_linked_list_notify_type llist_notify[MDDI_MAX_NUM_LLIST_ITEMS]; +} mddi_host_cntl_type; + +static mddi_host_type mddi_curr_host = MDDI_HOST_PRIM; +static mddi_host_cntl_type mhctl[MDDI_NUM_HOST_CORES]; +mddi_linked_list_type *llist_extern[MDDI_NUM_HOST_CORES]; +mddi_linked_list_type *llist_dma_extern[MDDI_NUM_HOST_CORES]; +mddi_linked_list_notify_type *llist_extern_notify[MDDI_NUM_HOST_CORES]; +static mddi_log_params_struct_type prev_parms[MDDI_NUM_HOST_CORES]; + +extern uint32 mdp_total_vdopkts; + +static boolean mddi_host_io_clock_on = FALSE; +static boolean mddi_host_hclk_on = FALSE; + +int int_mddi_pri_flag = FALSE; +int int_mddi_ext_flag = FALSE; + +static void mddi_report_errors(uint32 int_reg) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (int_reg & MDDI_INT_PRI_UNDERFLOW) { + pmhctl->stats.pri_underflow++; + MDDI_MSG_ERR("!!! MDDI Primary Underflow !!!\n"); + } + if (int_reg & MDDI_INT_SEC_UNDERFLOW) { + pmhctl->stats.sec_underflow++; + MDDI_MSG_ERR("!!! MDDI Secondary Underflow !!!\n"); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (int_reg & MDDI_INT_REV_OVERFLOW) { + pmhctl->stats.rev_overflow++; + MDDI_MSG_ERR("!!! MDDI Reverse Overflow !!!\n"); + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + mddi_host_reg_out(REV_PTR, pmhctl->mddi_rev_ptr_write_val); + + } + if (int_reg & MDDI_INT_CRC_ERROR) + MDDI_MSG_ERR("!!! MDDI Reverse CRC Error !!!\n"); +#endif + if (int_reg & MDDI_INT_PRI_OVERWRITE) { + pmhctl->stats.pri_overwrite++; + MDDI_MSG_ERR("!!! MDDI Primary Overwrite !!!\n"); + } + if (int_reg & MDDI_INT_SEC_OVERWRITE) { + pmhctl->stats.sec_overwrite++; + MDDI_MSG_ERR("!!! MDDI Secondary Overwrite !!!\n"); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (int_reg & MDDI_INT_REV_OVERWRITE) { + pmhctl->stats.rev_overwrite++; + /* This will show up normally and is not a problem */ + MDDI_MSG_DEBUG("MDDI Reverse Overwrite!\n"); + } + if (int_reg & MDDI_INT_RTD_FAILURE) { + mddi_host_reg_outm(INTEN, MDDI_INT_RTD_FAILURE, 0); + pmhctl->stats.rtd_failure++; + MDDI_MSG_ERR("!!! MDDI RTD Failure !!!\n"); + } +#endif + if (int_reg & MDDI_INT_DMA_FAILURE) { + pmhctl->stats.dma_failure++; + MDDI_MSG_ERR("!!! MDDI DMA Abort !!!\n"); + } +} + +static void mddi_host_enable_io_clock(void) +{ + if (!MDDI_HOST_IS_IO_CLOCK_ON) + MDDI_HOST_ENABLE_IO_CLOCK; +} + +static void mddi_host_enable_hclk(void) +{ + + if (!MDDI_HOST_IS_HCLK_ON) + MDDI_HOST_ENABLE_HCLK; +} + +static void mddi_host_disable_io_clock(void) +{ +#ifndef FEATURE_MDDI_HOST_IO_CLOCK_CONTROL_DISABLE + if (MDDI_HOST_IS_IO_CLOCK_ON) + MDDI_HOST_DISABLE_IO_CLOCK; +#endif +} + +static void mddi_host_disable_hclk(void) +{ +#ifndef FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE + if (MDDI_HOST_IS_HCLK_ON) + MDDI_HOST_DISABLE_HCLK; +#endif +} + +static void mddi_vote_to_sleep(mddi_host_type host_idx, boolean sleep) +{ + uint16 vote_mask; + + if (host_idx == MDDI_HOST_PRIM) + vote_mask = 0x01; + else + vote_mask = 0x02; +} + +static void mddi_report_state_change(uint32 int_reg) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if ((pmhctl->saved_int_reg & MDDI_INT_IN_HIBERNATION) && + (pmhctl->saved_int_reg & MDDI_INT_LINK_ACTIVE)) { + /* recover from condition where the io_clock was turned off by the + clock driver during a transition to hibernation. The io_clock + disable is to prevent MDP/MDDI underruns when changing ARM + clock speeds. In the process of halting the ARM, the hclk + divider needs to be set to 1. When it is set to 1, there is + a small time (usecs) when hclk is off or slow, and this can + cause an underrun. To prevent the underrun, clock driver turns + off the MDDI io_clock before making the change. */ + mddi_host_reg_out(CMD, MDDI_CMD_POWERUP); + } + + if (int_reg & MDDI_INT_LINK_ACTIVE) { + pmhctl->link_state = MDDI_LINK_ACTIVE; + pmhctl->log_parms.link_active_cnt++; + pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL); + MDDI_MSG_DEBUG("!!! MDDI Active RTD:0x%x!!!\n", + pmhctl->rtd_value); + /* now interrupt on hibernation */ + mddi_host_reg_outm(INTEN, + (MDDI_INT_IN_HIBERNATION | + MDDI_INT_LINK_ACTIVE), + MDDI_INT_IN_HIBERNATION); + +#ifdef DEBUG_MDDIHOSTI + /* if gpio interrupt is enabled, start polling at fastest + * registered rate + */ + if (mddi_gpio.polling_enabled) { + timer_reg(&mddi_gpio_poll_timer, + mddi_gpio_poll_timer_cb, 0, mddi_gpio.polling_interval, 0); + } +#endif +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (mddi_rev_ptr_workaround) { + /* HW CR: need to reset reverse register stuff */ + pmhctl->rev_ptr_written = FALSE; + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + } +#endif + /* vote on sleep */ + mddi_vote_to_sleep(host_idx, FALSE); + + if (host_idx == MDDI_HOST_PRIM) { + if (mddi_vsync_detect_enabled) { + /* + * Indicate to client specific code that vsync + * was enabled, but we did not detect a client + * intiated wakeup. The client specific + * handler can either reassert vsync detection, + * or treat this as a valid vsync. + */ + mddi_client_lcd_vsync_detected(FALSE); + pmhctl->log_parms.vsync_response_cnt++; + } + } + } + if (int_reg & MDDI_INT_IN_HIBERNATION) { + pmhctl->link_state = MDDI_LINK_HIBERNATING; + pmhctl->log_parms.link_hibernate_cnt++; + MDDI_MSG_DEBUG("!!! MDDI Hibernating !!!\n"); + /* now interrupt on link_active */ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + mddi_host_reg_outm(INTEN, + (MDDI_INT_MDDI_IN | + MDDI_INT_IN_HIBERNATION | + MDDI_INT_LINK_ACTIVE), + MDDI_INT_LINK_ACTIVE); +#else + mddi_host_reg_outm(INTEN, + (MDDI_INT_MDDI_IN | + MDDI_INT_IN_HIBERNATION | + MDDI_INT_LINK_ACTIVE), + (MDDI_INT_MDDI_IN | MDDI_INT_LINK_ACTIVE)); + + pmhctl->rtd_counter = mddi_rtd_frequency; + + if (pmhctl->rev_state != MDDI_REV_IDLE) { + /* a rev_encap will not wake up the link, so we do that here */ + pmhctl->link_state = MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + } +#endif + + if (pmhctl->disable_hibernation) { + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE); + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + pmhctl->link_state = MDDI_LINK_ACTIVATING; + } +#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY + if ((pmhctl->llist_info.transmitting_start_idx != + UNASSIGNED_INDEX) + && + ((pmhctl-> + saved_int_reg & (MDDI_INT_PRI_LINK_LIST_DONE | + MDDI_INT_PRI_PTR_READ)) == + MDDI_INT_PRI_PTR_READ)) { + mddi_linked_list_type *llist_dma; + llist_dma = pmhctl->llist_dma_ptr; + /* + * All indications are that we have not received a + * linked list done interrupt, due to an underrun + * condition. Recovery attempt is to send again. + */ + dma_coherent_pre_ops(); + /* Write to primary pointer register again */ + mddi_host_reg_out(PRI_PTR, + &llist_dma[pmhctl->llist_info. + transmitting_start_idx]); + pmhctl->stats.pri_underrun_detected++; + } +#endif + + /* vote on sleep */ + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + mddi_vote_to_sleep(host_idx, TRUE); + } + +#ifdef DEBUG_MDDIHOSTI + /* need to stop polling timer */ + if (mddi_gpio.polling_enabled) { + (void) timer_clr(&mddi_gpio_poll_timer, T_NONE); + } +#endif + } +} + +void mddi_host_timer_service(unsigned long data) +{ +#ifndef FEATURE_MDDI_DISABLE_REVERSE + unsigned long flags; +#endif + mddi_host_type host_idx; + mddi_host_cntl_type *pmhctl; + + unsigned long time_ms = MDDI_DEFAULT_TIMER_LENGTH; + init_timer(&mddi_host_timer); + mddi_host_timer.function = mddi_host_timer_service; + mddi_host_timer.data = 0; + + mddi_host_timer.expires = jiffies + ((time_ms * HZ) / 1000); + add_timer(&mddi_host_timer); + + for (host_idx = MDDI_HOST_PRIM; host_idx < MDDI_NUM_HOST_CORES; + host_idx++) { + pmhctl = &(mhctl[host_idx]); + mddi_log_stats_counter += (uint32) time_ms; +#ifndef FEATURE_MDDI_DISABLE_REVERSE + pmhctl->rtd_counter += (uint32) time_ms; + pmhctl->client_status_cnt += (uint32) time_ms; + + if (host_idx == MDDI_HOST_PRIM) { + if (pmhctl->client_status_cnt >= + mddi_client_status_frequency) { + if ((pmhctl->link_state == + MDDI_LINK_HIBERNATING) + && (pmhctl->client_status_cnt > + mddi_client_status_frequency)) { + /* + * special case where we are hibernating + * and mddi_host_isr is not firing, so + * kick the link so that the status can + * be retrieved + */ + + /* need to wake up link before issuing + * rev encap command + */ + MDDI_MSG_INFO("wake up link!\n"); + spin_lock_irqsave(&mddi_host_spin_lock, + flags); + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + pmhctl->link_state = + MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, + MDDI_CMD_LINK_ACTIVE); + spin_unlock_irqrestore + (&mddi_host_spin_lock, flags); + } else + if ((pmhctl->link_state == MDDI_LINK_ACTIVE) + && pmhctl->disable_hibernation) { + /* + * special case where we have disabled + * hibernation and mddi_host_isr + * is not firing, so enable interrupt + * for no pkts pending, which will + * generate an interrupt + */ + MDDI_MSG_INFO("kick isr!\n"); + spin_lock_irqsave(&mddi_host_spin_lock, + flags); + mddi_host_enable_hclk(); + mddi_host_reg_outm(INTEN, + MDDI_INT_NO_CMD_PKTS_PEND, + MDDI_INT_NO_CMD_PKTS_PEND); + spin_unlock_irqrestore + (&mddi_host_spin_lock, flags); + } + } + } +#endif /* #ifndef FEATURE_MDDI_DISABLE_REVERSE */ + } + + /* Check if logging is turned on */ + for (host_idx = MDDI_HOST_PRIM; host_idx < MDDI_NUM_HOST_CORES; + host_idx++) { + mddi_log_params_struct_type *prev_ptr = &(prev_parms[host_idx]); + pmhctl = &(mhctl[host_idx]); + + if (mddi_debug_log_statistics) { + + /* get video pkt count from MDP, since MDDI sw cannot know this */ + pmhctl->log_parms.vid_cnt = mdp_total_vdopkts; + + if (mddi_log_stats_counter >= mddi_log_stats_frequency) { + /* mddi_log_stats_counter = 0; */ + if (mddi_debug_log_statistics) { + MDDI_MSG_NOTICE + ("MDDI Statistics since last report:\n"); + MDDI_MSG_NOTICE(" Packets sent:\n"); + MDDI_MSG_NOTICE + (" %d RTD packet(s)\n", + pmhctl->log_parms.rtd_cnt - + prev_ptr->rtd_cnt); + if (prev_ptr->rtd_cnt != + pmhctl->log_parms.rtd_cnt) { + unsigned long flags; + spin_lock_irqsave + (&mddi_host_spin_lock, + flags); + mddi_host_enable_hclk(); + pmhctl->rtd_value = + mddi_host_reg_in(RTD_VAL); + spin_unlock_irqrestore + (&mddi_host_spin_lock, + flags); + MDDI_MSG_NOTICE + (" RTD value=%d\n", + pmhctl->rtd_value); + } + MDDI_MSG_NOTICE + (" %d VIDEO packets\n", + pmhctl->log_parms.vid_cnt - + prev_ptr->vid_cnt); + MDDI_MSG_NOTICE + (" %d Register Access packets\n", + pmhctl->log_parms.reg_acc_cnt - + prev_ptr->reg_acc_cnt); + MDDI_MSG_NOTICE + (" %d Reverse Encapsulation packet(s)\n", + pmhctl->log_parms.rev_enc_cnt - + prev_ptr->rev_enc_cnt); + if (prev_ptr->rev_enc_cnt != + pmhctl->log_parms.rev_enc_cnt) { + /* report # of reverse CRC errors */ + MDDI_MSG_NOTICE + (" %d reverse CRC errors detected\n", + pmhctl->log_parms. + rev_crc_cnt - + prev_ptr->rev_crc_cnt); + } + MDDI_MSG_NOTICE + (" Packets received:\n"); + MDDI_MSG_NOTICE + (" %d Client Status packets", + pmhctl->log_parms.cli_stat_cnt - + prev_ptr->cli_stat_cnt); + if (prev_ptr->cli_stat_cnt != + pmhctl->log_parms.cli_stat_cnt) { + MDDI_MSG_NOTICE + (" %d forward CRC errors reported\n", + pmhctl->log_parms. + fwd_crc_cnt - + prev_ptr->fwd_crc_cnt); + } + MDDI_MSG_NOTICE + (" %d Register Access Read packets\n", + pmhctl->log_parms.reg_read_cnt - + prev_ptr->reg_read_cnt); + + if (pmhctl->link_state == + MDDI_LINK_ACTIVE) { + MDDI_MSG_NOTICE + (" Current Link Status: Active\n"); + } else + if ((pmhctl->link_state == + MDDI_LINK_HIBERNATING) + || (pmhctl->link_state == + MDDI_LINK_ACTIVATING)) { + MDDI_MSG_NOTICE + (" Current Link Status: Hibernation\n"); + } else { + MDDI_MSG_NOTICE + (" Current Link Status: Inactive\n"); + } + MDDI_MSG_NOTICE + (" Active state entered %d times\n", + pmhctl->log_parms.link_active_cnt - + prev_ptr->link_active_cnt); + MDDI_MSG_NOTICE + (" Hibernation state entered %d times\n", + pmhctl->log_parms. + link_hibernate_cnt - + prev_ptr->link_hibernate_cnt); + } + } + prev_parms[host_idx] = pmhctl->log_parms; + } + } + if (mddi_log_stats_counter >= mddi_log_stats_frequency) + mddi_log_stats_counter = 0; + + return; +} /* mddi_host_timer_cb */ + +static void mddi_process_link_list_done(void) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + /* normal forward linked list packet(s) were sent */ + if (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) { + MDDI_MSG_ERR("**** getting LL done, but no list ****\n"); + } else { + uint16 idx; + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (pmhctl->rev_state == MDDI_REV_REG_READ_ISSUED) { + /* special case where a register read packet was sent */ + pmhctl->rev_state = MDDI_REV_REG_READ_SENT; + if (pmhctl->llist_info.reg_read_idx == UNASSIGNED_INDEX) { + MDDI_MSG_ERR + ("**** getting LL done, but no list ****\n"); + } + } +#endif + for (idx = pmhctl->llist_info.transmitting_start_idx;;) { + uint16 next_idx = pmhctl->llist_notify[idx].next_idx; + /* with reg read we don't release the waiting tcb until after + * the reverse encapsulation has completed. + */ + if (idx != pmhctl->llist_info.reg_read_idx) { + /* notify task that may be waiting on this completion */ + if (pmhctl->llist_notify[idx].waiting) { + complete(& + (pmhctl->llist_notify[idx]. + done_comp)); + } + if (pmhctl->llist_notify[idx].done_cb != NULL) { + (*(pmhctl->llist_notify[idx].done_cb)) + (); + } + + pmhctl->llist_notify[idx].in_use = FALSE; + pmhctl->llist_notify[idx].waiting = FALSE; + pmhctl->llist_notify[idx].done_cb = NULL; + if (idx < MDDI_NUM_DYNAMIC_LLIST_ITEMS) { + /* static LLIST items are configured only once */ + pmhctl->llist_notify[idx].next_idx = + UNASSIGNED_INDEX; + } + /* + * currently, all linked list packets are + * register access, so we can increment the + * counter for that packet type here. + */ + pmhctl->log_parms.reg_acc_cnt++; + } + if (idx == pmhctl->llist_info.transmitting_end_idx) + break; + idx = next_idx; + if (idx == UNASSIGNED_INDEX) + MDDI_MSG_CRIT("MDDI linked list corruption!\n"); + } + + pmhctl->llist_info.transmitting_start_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.transmitting_end_idx = UNASSIGNED_INDEX; + + if (pmhctl->mddi_waiting_for_llist_avail) { + if (! + (pmhctl-> + llist_notify[pmhctl->llist_info.next_free_idx]. + in_use)) { + pmhctl->mddi_waiting_for_llist_avail = FALSE; + complete(&(pmhctl->mddi_llist_avail_comp)); + } + } + } + + /* Turn off MDDI_INT_PRI_LINK_LIST_DONE interrupt */ + mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, 0); + +} + +static void mddi_queue_forward_linked_list(void) +{ + uint16 first_pkt_index; + mddi_linked_list_type *llist_dma; + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + llist_dma = pmhctl->llist_dma_ptr; + + first_pkt_index = UNASSIGNED_INDEX; + + if (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) { +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (pmhctl->llist_info.reg_read_waiting) { + if (pmhctl->rev_state == MDDI_REV_IDLE) { + /* + * we have a register read to send and + * can send it now + */ + pmhctl->rev_state = MDDI_REV_REG_READ_ISSUED; + mddi_reg_read_retry = 0; + first_pkt_index = + pmhctl->llist_info.waiting_start_idx; + pmhctl->llist_info.reg_read_waiting = FALSE; + } + } else +#endif + { + /* + * not register read to worry about, go ahead and write + * anything that may be on the waiting list. + */ + first_pkt_index = pmhctl->llist_info.waiting_start_idx; + } + } + + if (first_pkt_index != UNASSIGNED_INDEX) { + pmhctl->llist_info.transmitting_start_idx = + pmhctl->llist_info.waiting_start_idx; + pmhctl->llist_info.transmitting_end_idx = + pmhctl->llist_info.waiting_end_idx; + pmhctl->llist_info.waiting_start_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.waiting_end_idx = UNASSIGNED_INDEX; + + /* write to the primary pointer register */ + MDDI_MSG_DEBUG("MDDI writing primary ptr with idx=%d\n", + first_pkt_index); + + pmhctl->int_type.llist_ptr_write_2++; + + dma_coherent_pre_ops(); + mddi_host_reg_out(PRI_PTR, &llist_dma[first_pkt_index]); + + /* enable interrupt when complete */ + mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, + MDDI_INT_PRI_LINK_LIST_DONE); + + } + +} + +#ifndef FEATURE_MDDI_DISABLE_REVERSE +static void mddi_read_rev_packet(byte *data_ptr) +{ + uint16 i, length; + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + uint8 *rev_ptr_overflow = + (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE); + + /* first determine the length and handle invalid lengths */ + length = *pmhctl->rev_ptr_curr++; + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + length |= ((*pmhctl->rev_ptr_curr++) << 8); + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + if (length > (pmhctl->rev_pkt_size - 2)) { + MDDI_MSG_ERR("Invalid rev pkt length %d\n", length); + /* rev_pkt_size should always be <= rev_ptr_size so limit to packet size */ + length = pmhctl->rev_pkt_size - 2; + } + + /* If the data pointer is NULL, just increment the pmhctl->rev_ptr_curr. + * Loop around if necessary. Don't bother reading the data. + */ + if (data_ptr == NULL) { + pmhctl->rev_ptr_curr += length; + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr -= MDDI_REV_BUFFER_SIZE; + return; + } + + data_ptr[0] = length & 0x0ff; + data_ptr[1] = length >> 8; + data_ptr += 2; + /* copy the data to data_ptr byte-at-a-time */ + for (i = 0; (i < length) && (pmhctl->rev_ptr_curr < rev_ptr_overflow); + i++) + *data_ptr++ = *pmhctl->rev_ptr_curr++; + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + for (; (i < length) && (pmhctl->rev_ptr_curr < rev_ptr_overflow); i++) + *data_ptr++ = *pmhctl->rev_ptr_curr++; +} + +static void mddi_process_rev_packets(void) +{ + uint32 rev_packet_count; + word i; + uint32 crc_errors; + boolean mddi_reg_read_successful = FALSE; + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + pmhctl->log_parms.rev_enc_cnt++; + if ((pmhctl->rev_state != MDDI_REV_ENCAP_ISSUED) && + (pmhctl->rev_state != MDDI_REV_STATUS_REQ_ISSUED) && + (pmhctl->rev_state != MDDI_REV_CLIENT_CAP_ISSUED)) { + MDDI_MSG_ERR("Wrong state %d for reverse int\n", + pmhctl->rev_state); + } + /* Turn off MDDI_INT_REV_AVAIL interrupt */ + mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL, 0); + + /* Clear rev data avail int */ + mddi_host_reg_out(INT, MDDI_INT_REV_DATA_AVAIL); + + /* Get Number of packets */ + rev_packet_count = mddi_host_reg_in(REV_PKT_CNT); + +#ifndef T_MSM7500 + /* Clear out rev packet counter */ + mddi_host_reg_out(REV_PKT_CNT, 0x0000); +#endif + +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + if ((pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED) && + (rev_packet_count > 0) && + (mddi_host_core_version == 0x28 || + mddi_host_core_version == 0x30)) { + + uint32 int_reg; + uint32 max_count = 0; + + mddi_host_reg_out(REV_PTR, pmhctl->mddi_rev_ptr_write_val); + int_reg = mddi_host_reg_in(INT); + while ((int_reg & 0x100000) == 0) { + udelay(3); + int_reg = mddi_host_reg_in(INT); + if (++max_count > 100) + break; + } + } +#endif + + /* Get CRC error count */ + crc_errors = mddi_host_reg_in(REV_CRC_ERR); + if (crc_errors != 0) { + pmhctl->log_parms.rev_crc_cnt += crc_errors; + pmhctl->stats.rev_crc_count += crc_errors; + MDDI_MSG_ERR("!!! MDDI %d Reverse CRC Error(s) !!!\n", + crc_errors); +#ifndef T_MSM7500 + /* Clear CRC error count */ + mddi_host_reg_out(REV_CRC_ERR, 0x0000); +#endif + /* also issue an RTD to attempt recovery */ + pmhctl->rtd_counter = mddi_rtd_frequency; + } + + pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL); + + MDDI_MSG_DEBUG("MDDI rev pkt cnt=%d, ptr=0x%x, RTD:0x%x\n", + rev_packet_count, + pmhctl->rev_ptr_curr - pmhctl->rev_ptr_start, + pmhctl->rtd_value); + + if (rev_packet_count >= 1) { + mddi_invalidate_cache_lines((uint32 *) pmhctl->rev_ptr_start, + MDDI_REV_BUFFER_SIZE); + } + /* order the reads */ + dma_coherent_post_ops(); + for (i = 0; i < rev_packet_count; i++) { + mddi_rev_packet_type *rev_pkt_ptr; + + mddi_read_rev_packet(rev_packet_data); + + rev_pkt_ptr = (mddi_rev_packet_type *) rev_packet_data; + + if (rev_pkt_ptr->packet_length > pmhctl->rev_pkt_size) { + MDDI_MSG_ERR("!!!invalid packet size: %d\n", + rev_pkt_ptr->packet_length); + } + + MDDI_MSG_DEBUG("MDDI rev pkt 0x%x size 0x%x\n", + rev_pkt_ptr->packet_type, + rev_pkt_ptr->packet_length); + + /* Do whatever you want to do with the data based on the packet type */ + switch (rev_pkt_ptr->packet_type) { + case 66: /* Client Capability */ + { + mddi_client_capability_type + *client_capability_pkt_ptr; + + client_capability_pkt_ptr = + (mddi_client_capability_type *) + rev_packet_data; + MDDI_MSG_NOTICE + ("Client Capability: Week=%d, Year=%d\n", + client_capability_pkt_ptr-> + Week_of_Manufacture, + client_capability_pkt_ptr-> + Year_of_Manufacture); + memcpy((void *)&mddi_client_capability_pkt, + (void *)rev_packet_data, + sizeof(mddi_client_capability_type)); + pmhctl->log_parms.cli_cap_cnt++; + } + break; + + case 70: /* Display Status */ + { + mddi_client_status_type *client_status_pkt_ptr; + + client_status_pkt_ptr = + (mddi_client_status_type *) rev_packet_data; + if ((client_status_pkt_ptr->crc_error_count != + 0) + || (client_status_pkt_ptr-> + reverse_link_request != 0)) { + MDDI_MSG_ERR + ("Client Status: RevReq=%d, CrcErr=%d\n", + client_status_pkt_ptr-> + reverse_link_request, + client_status_pkt_ptr-> + crc_error_count); + } else { + MDDI_MSG_DEBUG + ("Client Status: RevReq=%d, CrcErr=%d\n", + client_status_pkt_ptr-> + reverse_link_request, + client_status_pkt_ptr-> + crc_error_count); + } + pmhctl->log_parms.fwd_crc_cnt += + client_status_pkt_ptr->crc_error_count; + pmhctl->stats.fwd_crc_count += + client_status_pkt_ptr->crc_error_count; + pmhctl->log_parms.cli_stat_cnt++; + } + break; + + case 146: /* register access packet */ + { + mddi_register_access_packet_type + * regacc_pkt_ptr; + + regacc_pkt_ptr = + (mddi_register_access_packet_type *) + rev_packet_data; + + MDDI_MSG_DEBUG + ("Reg Acc parse reg=0x%x, value=0x%x\n", + regacc_pkt_ptr->register_address, + regacc_pkt_ptr->register_data_list); + + /* Copy register value to location passed in */ + if (mddi_reg_read_value_ptr) { +#if defined(T_MSM6280) && !defined(T_MSM7200) + /* only least significant 16 bits are valid with 6280 */ + *mddi_reg_read_value_ptr = + regacc_pkt_ptr-> + register_data_list & 0x0000ffff; +#else + *mddi_reg_read_value_ptr = + regacc_pkt_ptr->register_data_list; +#endif + mddi_reg_read_successful = TRUE; + mddi_reg_read_value_ptr = NULL; + } + +#ifdef DEBUG_MDDIHOSTI + if ((mddi_gpio.polling_enabled) && + (regacc_pkt_ptr->register_address == + mddi_gpio.polling_reg)) { + /* + * ToDo: need to call Linux GPIO call + * here... + */ + mddi_client_lcd_gpio_poll( + regacc_pkt_ptr->register_data_list); + } +#endif + pmhctl->log_parms.reg_read_cnt++; + } + break; + + default: /* any other packet */ + { + uint16 hdlr; + + for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; + hdlr++) { + if (mddi_rev_pkt_handler[hdlr]. + pkt_type == + rev_pkt_ptr->packet_type) { + (* + (mddi_rev_pkt_handler[hdlr]. + handler)) (rev_pkt_ptr); + /* pmhctl->rev_state = MDDI_REV_IDLE; */ + break; + } + } + if (hdlr >= MAX_MDDI_REV_HANDLERS) + MDDI_MSG_ERR("MDDI unknown rev pkt\n"); + } + break; + } + } + if ((pmhctl->rev_ptr_curr + pmhctl->rev_pkt_size) >= + (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE)) { + pmhctl->rev_ptr_written = FALSE; + } + + if (pmhctl->rev_state == MDDI_REV_ENCAP_ISSUED) { + pmhctl->rev_state = MDDI_REV_IDLE; + if (mddi_rev_user.waiting) { + mddi_rev_user.waiting = FALSE; + complete(&(mddi_rev_user.done_comp)); + } else if (pmhctl->llist_info.reg_read_idx == UNASSIGNED_INDEX) { + MDDI_MSG_ERR + ("Reverse Encap state, but no reg read in progress\n"); + } else { + if ((!mddi_reg_read_successful) && + (mddi_reg_read_retry < mddi_reg_read_retry_max) && + (mddi_enable_reg_read_retry)) { + /* + * There is a race condition that can happen + * where the reverse encapsulation message is + * sent out by the MDDI host before the register + * read packet is sent. As a work-around for + * that problem we issue the reverse + * encapsulation one more time before giving up. + */ + if (mddi_enable_reg_read_retry_once) + mddi_reg_read_retry = + mddi_reg_read_retry_max; + pmhctl->rev_state = MDDI_REV_REG_READ_SENT; + pmhctl->stats.reg_read_failure++; + } else { + uint16 reg_read_idx = + pmhctl->llist_info.reg_read_idx; + + mddi_reg_read_retry = 0; + if (pmhctl->llist_notify[reg_read_idx].waiting) { + complete(& + (pmhctl-> + llist_notify[reg_read_idx]. + done_comp)); + } + pmhctl->llist_info.reg_read_idx = + UNASSIGNED_INDEX; + if (pmhctl->llist_notify[reg_read_idx]. + done_cb != NULL) { + (* + (pmhctl->llist_notify[reg_read_idx]. + done_cb)) (); + } + pmhctl->llist_notify[reg_read_idx].next_idx = + UNASSIGNED_INDEX; + pmhctl->llist_notify[reg_read_idx].in_use = + FALSE; + pmhctl->llist_notify[reg_read_idx].waiting = + FALSE; + pmhctl->llist_notify[reg_read_idx].done_cb = + NULL; + if (!mddi_reg_read_successful) + pmhctl->stats.reg_read_failure++; + } + } + } else if (pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED) { +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + if (mddi_host_core_version == 0x28 || + mddi_host_core_version == 0x30) { + mddi_host_reg_out(FIFO_ALLOC, 0x00); + pmhctl->rev_ptr_written = TRUE; + mddi_host_reg_out(REV_PTR, + pmhctl->mddi_rev_ptr_write_val); + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + mddi_host_reg_out(CMD, 0xC00); + } +#endif + + if (mddi_rev_user.waiting) { + mddi_rev_user.waiting = FALSE; + complete(&(mddi_rev_user.done_comp)); + } + pmhctl->rev_state = MDDI_REV_IDLE; + } else { + pmhctl->rev_state = MDDI_REV_IDLE; + } + + /* pmhctl->rev_state = MDDI_REV_IDLE; */ + + /* Re-enable interrupt */ + mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL, + MDDI_INT_REV_DATA_AVAIL); + +} + +static void mddi_issue_reverse_encapsulation(void) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + /* Only issue a reverse encapsulation packet if: + * 1) another reverse is not in progress (MDDI_REV_IDLE). + * 2) a register read has been sent (MDDI_REV_REG_READ_SENT). + * 3) forward is not in progress, because of a hw bug in client that + * causes forward crc errors on packet immediately after rev encap. + */ + if (((pmhctl->rev_state == MDDI_REV_IDLE) || + (pmhctl->rev_state == MDDI_REV_REG_READ_SENT)) && + (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) && + (!mdp_in_processing)) { + uint32 mddi_command = MDDI_CMD_SEND_REV_ENCAP; + + if ((pmhctl->rev_state == MDDI_REV_REG_READ_SENT) || + (mddi_rev_encap_user_request == TRUE)) { + mddi_host_enable_io_clock(); + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + /* need to wake up link before issuing rev encap command */ + MDDI_MSG_DEBUG("wake up link!\n"); + pmhctl->link_state = MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + } else { + if (pmhctl->rtd_counter >= mddi_rtd_frequency) { + MDDI_MSG_DEBUG + ("mddi sending RTD command!\n"); + mddi_host_reg_out(CMD, + MDDI_CMD_SEND_RTD); + pmhctl->rtd_counter = 0; + pmhctl->log_parms.rtd_cnt++; + } + if (pmhctl->rev_state != MDDI_REV_REG_READ_SENT) { + /* this is generic reverse request by user, so + * reset the waiting flag. */ + mddi_rev_encap_user_request = FALSE; + } + /* link is active so send reverse encap to get register read results */ + pmhctl->rev_state = MDDI_REV_ENCAP_ISSUED; + mddi_command = MDDI_CMD_SEND_REV_ENCAP; + MDDI_MSG_DEBUG("sending rev encap!\n"); + } + } else + if ((pmhctl->client_status_cnt >= + mddi_client_status_frequency) + || mddi_client_capability_request) { + mddi_host_enable_io_clock(); + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + /* only wake up the link if it client status is overdue */ + if ((pmhctl->client_status_cnt >= + (mddi_client_status_frequency * 2)) + || mddi_client_capability_request) { + /* need to wake up link before issuing rev encap command */ + MDDI_MSG_DEBUG("wake up link!\n"); + pmhctl->link_state = + MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, + MDDI_CMD_LINK_ACTIVE); + } + } else { + if (pmhctl->rtd_counter >= mddi_rtd_frequency) { + MDDI_MSG_DEBUG + ("mddi sending RTD command!\n"); + mddi_host_reg_out(CMD, + MDDI_CMD_SEND_RTD); + pmhctl->rtd_counter = 0; + pmhctl->log_parms.rtd_cnt++; + } + /* periodically get client status */ + MDDI_MSG_DEBUG + ("mddi sending rev enc! (get status)\n"); + if (mddi_client_capability_request) { + pmhctl->rev_state = + MDDI_REV_CLIENT_CAP_ISSUED; + mddi_command = MDDI_CMD_GET_CLIENT_CAP; + mddi_client_capability_request = FALSE; + } else { + pmhctl->rev_state = + MDDI_REV_STATUS_REQ_ISSUED; + pmhctl->client_status_cnt = 0; + mddi_command = + MDDI_CMD_GET_CLIENT_STATUS; + } + } + } + if ((pmhctl->rev_state == MDDI_REV_ENCAP_ISSUED) || + (pmhctl->rev_state == MDDI_REV_STATUS_REQ_ISSUED) || + (pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED)) { + pmhctl->int_type.rev_encap_count++; +#if defined(T_MSM6280) && !defined(T_MSM7200) + mddi_rev_pointer_written = TRUE; + mddi_host_reg_out(REV_PTR, mddi_rev_ptr_write_val); + mddi_rev_ptr_curr = mddi_rev_ptr_start; + /* force new rev ptr command */ + mddi_host_reg_out(CMD, 0xC00); +#else + if (!pmhctl->rev_ptr_written) { + MDDI_MSG_DEBUG("writing reverse pointer!\n"); + pmhctl->rev_ptr_written = TRUE; +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + if ((pmhctl->rev_state == + MDDI_REV_CLIENT_CAP_ISSUED) && + (mddi_host_core_version == 0x28 || + mddi_host_core_version == 0x30)) { + pmhctl->rev_ptr_written = FALSE; + mddi_host_reg_out(FIFO_ALLOC, 0x02); + } else + mddi_host_reg_out(REV_PTR, + pmhctl-> + mddi_rev_ptr_write_val); +#else + mddi_host_reg_out(REV_PTR, + pmhctl-> + mddi_rev_ptr_write_val); +#endif + } +#endif + if (mddi_debug_clear_rev_data) { + uint16 i; + for (i = 0; i < MDDI_MAX_REV_DATA_SIZE / 4; i++) + pmhctl->rev_data_buf[i] = 0xdddddddd; + /* clean cache */ + mddi_flush_cache_lines(pmhctl->rev_data_buf, + MDDI_MAX_REV_DATA_SIZE); + } + + /* send reverse encapsulation to get needed data */ + mddi_host_reg_out(CMD, mddi_command); + } + } + +} + +static void mddi_process_client_initiated_wakeup(void) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + /* Disable MDDI_INT Interrupt, we detect client initiated wakeup one + * time for each entry into hibernation */ + mddi_host_reg_outm(INTEN, MDDI_INT_MDDI_IN, 0); + + if (host_idx == MDDI_HOST_PRIM) { + if (mddi_vsync_detect_enabled) { + mddi_host_enable_io_clock(); +#ifndef MDDI_HOST_DISP_LISTEN + /* issue command to bring up link */ + /* need to do this to clear the vsync condition */ + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + pmhctl->link_state = MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + } +#endif + /* + * Indicate to client specific code that vsync was + * enabled, and we did not detect a client initiated + * wakeup. The client specific handler can clear the + * condition if necessary to prevent subsequent + * client initiated wakeups. + */ + mddi_client_lcd_vsync_detected(TRUE); + pmhctl->log_parms.vsync_response_cnt++; + MDDI_MSG_NOTICE("MDDI_INT_IN condition\n"); + + } + } + + if (mddi_gpio.polling_enabled) { + mddi_host_enable_io_clock(); + /* check interrupt status now */ + (void)mddi_queue_register_read_int(mddi_gpio.polling_reg, + &mddi_gpio.polling_val); + } +} +#endif /* FEATURE_MDDI_DISABLE_REVERSE */ + +static void mddi_host_isr(void) +{ + uint32 int_reg, int_en; +#ifndef FEATURE_MDDI_DISABLE_REVERSE + uint32 status_reg; +#endif + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (!MDDI_HOST_IS_HCLK_ON) { + MDDI_HOST_ENABLE_HCLK; + MDDI_MSG_DEBUG("HCLK disabled, but isr is firing\n"); + } + int_reg = mddi_host_reg_in(INT); + int_en = mddi_host_reg_in(INTEN); + pmhctl->saved_int_reg = int_reg; + pmhctl->saved_int_en = int_en; + int_reg = int_reg & int_en; + pmhctl->int_type.count++; + + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + status_reg = mddi_host_reg_in(STAT); + + if ((int_reg & MDDI_INT_MDDI_IN) || + ((int_en & MDDI_INT_MDDI_IN) && + ((int_reg == 0) || (status_reg & MDDI_STAT_CLIENT_WAKEUP_REQ)))) { + /* + * The MDDI_IN condition will clear itself, and so it is + * possible that MDDI_IN was the reason for the isr firing, + * even though the interrupt register does not have the + * MDDI_IN bit set. To check if this was the case we need to + * look at the status register bit that signifies a client + * initiated wakeup. If the status register bit is set, as well + * as the MDDI_IN interrupt enabled, then we treat this as a + * client initiated wakeup. + */ + if (int_reg & MDDI_INT_MDDI_IN) + pmhctl->int_type.in_count++; + mddi_process_client_initiated_wakeup(); + } +#endif + + if (int_reg & MDDI_INT_LINK_STATE_CHANGES) { + pmhctl->int_type.state_change_count++; + mddi_report_state_change(int_reg); + } + + if (int_reg & MDDI_INT_PRI_LINK_LIST_DONE) { + pmhctl->int_type.ll_done_count++; + mddi_process_link_list_done(); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (int_reg & MDDI_INT_REV_DATA_AVAIL) { + pmhctl->int_type.rev_avail_count++; + mddi_process_rev_packets(); + } +#endif + + if (int_reg & MDDI_INT_ERROR_CONDITIONS) { + pmhctl->int_type.error_count++; + mddi_report_errors(int_reg); + + mddi_host_reg_out(INT, int_reg & MDDI_INT_ERROR_CONDITIONS); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + mddi_issue_reverse_encapsulation(); + + if ((pmhctl->rev_state != MDDI_REV_ENCAP_ISSUED) && + (pmhctl->rev_state != MDDI_REV_STATUS_REQ_ISSUED)) +#endif + /* don't want simultaneous reverse and forward with Eagle */ + mddi_queue_forward_linked_list(); + + if (int_reg & MDDI_INT_NO_CMD_PKTS_PEND) { + /* this interrupt is used to kick the isr when hibernation is disabled */ + mddi_host_reg_outm(INTEN, MDDI_INT_NO_CMD_PKTS_PEND, 0); + } + + if ((!mddi_host_mdp_active_flag) && + (!mddi_vsync_detect_enabled) && + (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->rev_state == MDDI_REV_IDLE)) { + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + mddi_host_disable_io_clock(); + mddi_host_disable_hclk(); + } +#ifdef FEATURE_MDDI_HOST_ENABLE_EARLY_HIBERNATION + else if ((pmhctl->link_state == MDDI_LINK_ACTIVE) && + (!pmhctl->disable_hibernation)) { + mddi_host_reg_out(CMD, MDDI_CMD_POWERDOWN); + } +#endif + } +} + +static void mddi_host_isr_primary(void) +{ + mddi_curr_host = MDDI_HOST_PRIM; + mddi_host_isr(); +} + +irqreturn_t mddi_pmdh_isr_proxy(int irq, void *ptr) +{ + mddi_host_isr_primary(); + return IRQ_HANDLED; +} + +static void mddi_host_isr_external(void) +{ + mddi_curr_host = MDDI_HOST_EXT; + mddi_host_isr(); + mddi_curr_host = MDDI_HOST_PRIM; +} + +irqreturn_t mddi_emdh_isr_proxy(int irq, void *ptr) +{ + mddi_host_isr_external(); + return IRQ_HANDLED; +} + +static void mddi_host_initialize_registers(mddi_host_type host_idx) +{ + uint32 pad_reg_val; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (pmhctl->driver_state == MDDI_DRIVER_ENABLED) + return; + + /* turn on HCLK to MDDI host core */ + mddi_host_enable_hclk(); + + /* MDDI Reset command */ + mddi_host_reg_out(CMD, MDDI_CMD_RESET); + + /* Version register (= 0x01) */ + mddi_host_reg_out(VERSION, 0x0001); + + /* Bytes per subframe register */ + mddi_host_reg_out(BPS, MDDI_HOST_BYTES_PER_SUBFRAME); + + /* Subframes per media frames register (= 0x03) */ + mddi_host_reg_out(SPM, 0x0003); + + /* Turn Around 1 register (= 0x05) */ + mddi_host_reg_out(TA1_LEN, 0x0005); + + /* Turn Around 2 register (= 0x0C) */ + mddi_host_reg_out(TA2_LEN, MDDI_HOST_TA2_LEN); + + /* Drive hi register (= 0x96) */ + mddi_host_reg_out(DRIVE_HI, 0x0096); + + /* Drive lo register (= 0x32) */ + mddi_host_reg_out(DRIVE_LO, 0x0032); + + /* Display wakeup count register (= 0x3c) */ + mddi_host_reg_out(DISP_WAKE, 0x003c); + + /* Reverse Rate Divisor register (= 0x2) */ + mddi_host_reg_out(REV_RATE_DIV, MDDI_HOST_REV_RATE_DIV); + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + /* Reverse Pointer Size */ + mddi_host_reg_out(REV_SIZE, MDDI_REV_BUFFER_SIZE); + + /* Rev Encap Size */ + mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size); +#endif + + /* Periodic Rev Encap */ + /* don't send periodically */ + mddi_host_reg_out(CMD, MDDI_CMD_PERIODIC_REV_ENCAP); + + pad_reg_val = mddi_host_reg_in(PAD_CTL); + if (pad_reg_val == 0) { + /* If we are turning on band gap, need to wait 5us before turning + * on the rest of the PAD */ + mddi_host_reg_out(PAD_CTL, 0x08000); + udelay(5); + } +#ifdef T_MSM7200 + /* Recommendation from PAD hw team */ + mddi_host_reg_out(PAD_CTL, 0xa850a); +#else + /* Recommendation from PAD hw team */ + mddi_host_reg_out(PAD_CTL, 0xa850f); +#endif + +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + mddi_host_reg_out(PAD_IO_CTL, 0x00320000); + mddi_host_reg_out(PAD_CAL, 0x00220020); +#endif + + mddi_host_core_version = mddi_host_reg_inm(CORE_VER, 0xffff); + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (mddi_host_core_version >= 8) + mddi_rev_ptr_workaround = FALSE; + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; +#endif + + if ((mddi_host_core_version > 8) && (mddi_host_core_version < 0x19)) + mddi_host_reg_out(TEST, 0x2); + + /* Need an even number for counts */ + mddi_host_reg_out(DRIVER_START_CNT, 0x60006); + +#ifndef T_MSM7500 + /* Setup defaults for MDP related register */ + mddi_host_reg_out(MDP_VID_FMT_DES, 0x5666); + mddi_host_reg_out(MDP_VID_PIX_ATTR, 0x00C3); + mddi_host_reg_out(MDP_VID_CLIENTID, 0); +#endif + + /* automatically hibernate after 1 empty subframe */ + if (pmhctl->disable_hibernation) + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE); + else + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1); + + /* Bring up link if display (client) requests it */ +#ifdef MDDI_HOST_DISP_LISTEN + mddi_host_reg_out(CMD, MDDI_CMD_DISP_LISTEN); +#else + mddi_host_reg_out(CMD, MDDI_CMD_DISP_IGNORE); +#endif + +} + +void mddi_host_configure_interrupts(mddi_host_type host_idx, boolean enable) +{ + unsigned long flags; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + /* turn on HCLK to MDDI host core if it has been disabled */ + mddi_host_enable_hclk(); + /* Clear MDDI Interrupt enable reg */ + mddi_host_reg_out(INTEN, 0); + + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (enable) { + pmhctl->driver_state = MDDI_DRIVER_ENABLED; + + if (host_idx == MDDI_HOST_PRIM) { + if (request_irq + (INT_MDDI_PRI, mddi_pmdh_isr_proxy, IRQF_DISABLED, + "PMDH", 0) != 0) + printk(KERN_ERR + "a mddi: unable to request_irq\n"); + else + int_mddi_pri_flag = TRUE; + } else { + if (request_irq + (INT_MDDI_EXT, mddi_emdh_isr_proxy, IRQF_DISABLED, + "EMDH", 0) != 0) + printk(KERN_ERR + "b mddi: unable to request_irq\n"); + else + int_mddi_ext_flag = TRUE; + } + + /* Set MDDI Interrupt enable reg -- Enable Reverse data avail */ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + mddi_host_reg_out(INTEN, + MDDI_INT_ERROR_CONDITIONS | + MDDI_INT_LINK_STATE_CHANGES); +#else + /* Reverse Pointer register */ + pmhctl->rev_ptr_written = FALSE; + + mddi_host_reg_out(INTEN, + MDDI_INT_REV_DATA_AVAIL | + MDDI_INT_ERROR_CONDITIONS | + MDDI_INT_LINK_STATE_CHANGES); + pmhctl->rtd_counter = mddi_rtd_frequency; + pmhctl->client_status_cnt = 0; +#endif + } else { + if (pmhctl->driver_state == MDDI_DRIVER_ENABLED) + pmhctl->driver_state = MDDI_DRIVER_DISABLED; + } + +} + +static void mddi_host_powerup(mddi_host_type host_idx) +{ + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (pmhctl->link_state != MDDI_LINK_DISABLED) + return; + + /* enable IO_CLK and hclk to MDDI host core */ + mddi_host_enable_io_clock(); + + mddi_host_initialize_registers(host_idx); + mddi_host_configure_interrupts(host_idx, TRUE); + + pmhctl->link_state = MDDI_LINK_ACTIVATING; + + /* Link activate command */ + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + +#ifdef CLKRGM_MDDI_IO_CLOCK_IN_MHZ + MDDI_MSG_NOTICE("MDDI Host: Activating Link %d Mbps\n", + CLKRGM_MDDI_IO_CLOCK_IN_MHZ * 2); +#else + MDDI_MSG_NOTICE("MDDI Host: Activating Link\n"); +#endif + + /* Initialize the timer */ + if (host_idx == MDDI_HOST_PRIM) + mddi_host_timer_service(0); +} + +void mddi_host_init(mddi_host_type host_idx) +/* Write out the MDDI configuration registers */ +{ + static boolean initialized = FALSE; + mddi_host_cntl_type *pmhctl; + + if (host_idx >= MDDI_NUM_HOST_CORES) { + MDDI_MSG_ERR("Invalid host core index\n"); + return; + } + + if (!initialized) { + uint16 idx; + mddi_host_type host; + for (host = MDDI_HOST_PRIM; host < MDDI_NUM_HOST_CORES; host++) { + pmhctl = &(mhctl[host]); + initialized = TRUE; + + pmhctl->llist_ptr = + dma_alloc_coherent(NULL, MDDI_LLIST_POOL_SIZE, + &(pmhctl->llist_dma_addr), + GFP_KERNEL); + pmhctl->llist_dma_ptr = + (mddi_linked_list_type *) (void *)pmhctl-> + llist_dma_addr; +#ifdef FEATURE_MDDI_DISABLE_REVERSE + pmhctl->rev_data_buf = NULL; + if (pmhctl->llist_ptr == NULL) +#else + mddi_rev_user.waiting = FALSE; + init_completion(&(mddi_rev_user.done_comp)); + pmhctl->rev_data_buf = + dma_alloc_coherent(NULL, MDDI_MAX_REV_DATA_SIZE, + &(pmhctl->rev_data_dma_addr), + GFP_KERNEL); + if ((pmhctl->llist_ptr == NULL) + || (pmhctl->rev_data_buf == NULL)) +#endif + { + MDDI_MSG_CRIT + ("unable to alloc non-cached memory\n"); + } + llist_extern[host] = pmhctl->llist_ptr; + llist_dma_extern[host] = pmhctl->llist_dma_ptr; + llist_extern_notify[host] = pmhctl->llist_notify; + + for (idx = 0; idx < UNASSIGNED_INDEX; idx++) { + init_completion(& + (pmhctl->llist_notify[idx]. + done_comp)); + } + init_completion(&(pmhctl->mddi_llist_avail_comp)); + spin_lock_init(&mddi_host_spin_lock); + pmhctl->mddi_waiting_for_llist_avail = FALSE; + pmhctl->mddi_rev_ptr_write_val = + (uint32) (void *)(pmhctl->rev_data_dma_addr); + pmhctl->rev_ptr_start = (void *)pmhctl->rev_data_buf; + + pmhctl->rev_pkt_size = MDDI_DEFAULT_REV_PKT_SIZE; + pmhctl->rev_state = MDDI_REV_IDLE; +#ifdef IMAGE_MODEM_PROC + /* assume hibernation state is last state from APPS proc, so that + * we don't reinitialize the host core */ + pmhctl->link_state = MDDI_LINK_HIBERNATING; +#else + pmhctl->link_state = MDDI_LINK_DISABLED; +#endif + pmhctl->driver_state = MDDI_DRIVER_DISABLED; + pmhctl->disable_hibernation = FALSE; + + /* initialize llist variables */ + pmhctl->llist_info.transmitting_start_idx = + UNASSIGNED_INDEX; + pmhctl->llist_info.transmitting_end_idx = + UNASSIGNED_INDEX; + pmhctl->llist_info.waiting_start_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.waiting_end_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.reg_read_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.next_free_idx = + MDDI_FIRST_DYNAMIC_LLIST_IDX; + pmhctl->llist_info.reg_read_waiting = FALSE; + + mddi_vsync_detect_enabled = FALSE; + mddi_gpio.polling_enabled = FALSE; + + pmhctl->int_type.count = 0; + pmhctl->int_type.in_count = 0; + pmhctl->int_type.disp_req_count = 0; + pmhctl->int_type.state_change_count = 0; + pmhctl->int_type.ll_done_count = 0; + pmhctl->int_type.rev_avail_count = 0; + pmhctl->int_type.error_count = 0; + pmhctl->int_type.rev_encap_count = 0; + pmhctl->int_type.llist_ptr_write_1 = 0; + pmhctl->int_type.llist_ptr_write_2 = 0; + + pmhctl->stats.fwd_crc_count = 0; + pmhctl->stats.rev_crc_count = 0; + pmhctl->stats.pri_underflow = 0; + pmhctl->stats.sec_underflow = 0; + pmhctl->stats.rev_overflow = 0; + pmhctl->stats.pri_overwrite = 0; + pmhctl->stats.sec_overwrite = 0; + pmhctl->stats.rev_overwrite = 0; + pmhctl->stats.dma_failure = 0; + pmhctl->stats.rtd_failure = 0; + pmhctl->stats.reg_read_failure = 0; +#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY + pmhctl->stats.pri_underrun_detected = 0; +#endif + + pmhctl->log_parms.rtd_cnt = 0; + pmhctl->log_parms.rev_enc_cnt = 0; + pmhctl->log_parms.vid_cnt = 0; + pmhctl->log_parms.reg_acc_cnt = 0; + pmhctl->log_parms.cli_stat_cnt = 0; + pmhctl->log_parms.cli_cap_cnt = 0; + pmhctl->log_parms.reg_read_cnt = 0; + pmhctl->log_parms.link_active_cnt = 0; + pmhctl->log_parms.link_hibernate_cnt = 0; + pmhctl->log_parms.fwd_crc_cnt = 0; + pmhctl->log_parms.rev_crc_cnt = 0; + pmhctl->log_parms.vsync_response_cnt = 0; + + prev_parms[host_idx] = pmhctl->log_parms; + mddi_client_capability_pkt.packet_length = 0; + } + +#ifndef T_MSM7500 + /* tell clock driver we are user of this PLL */ + MDDI_HOST_ENABLE_IO_CLOCK; +#endif + } + + mddi_host_powerup(host_idx); + pmhctl = &(mhctl[host_idx]); +} + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT +static uint32 mddi_client_id; + +uint32 mddi_get_client_id(void) +{ + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + mddi_host_type host_idx = MDDI_HOST_PRIM; + static boolean client_detection_try = FALSE; + mddi_host_cntl_type *pmhctl; + unsigned long flags; + uint16 saved_rev_pkt_size; + + if (!client_detection_try) { + /* Toshiba display requires larger drive_lo value */ + mddi_host_reg_out(DRIVE_LO, 0x0050); + + pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + saved_rev_pkt_size = pmhctl->rev_pkt_size; + + /* Increase Rev Encap Size */ + pmhctl->rev_pkt_size = MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE; + mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size); + + /* disable hibernation temporarily */ + if (!pmhctl->disable_hibernation) + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE); + + mddi_rev_user.waiting = TRUE; + INIT_COMPLETION(mddi_rev_user.done_comp); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + /* turn on clock(s), if they have been disabled */ + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + + mddi_client_capability_request = TRUE; + + if (pmhctl->rev_state == MDDI_REV_IDLE) { + /* attempt to send the reverse encapsulation now */ + mddi_issue_reverse_encapsulation(); + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + wait_for_completion_killable(&(mddi_rev_user.done_comp)); + + /* Set Rev Encap Size back to its original value */ + pmhctl->rev_pkt_size = saved_rev_pkt_size; + mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size); + + /* reenable auto-hibernate */ + if (!pmhctl->disable_hibernation) + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1); + + mddi_host_reg_out(DRIVE_LO, 0x0032); + client_detection_try = TRUE; + + mddi_client_id = (mddi_client_capability_pkt.Mfr_Name<<16) | + mddi_client_capability_pkt.Product_Code; + + if (!mddi_client_id) + mddi_disable(1); + } + +#if 0 + switch (mddi_client_capability_pkt.Mfr_Name) { + case 0x4474: + if ((mddi_client_capability_pkt.Product_Code != 0x8960) && + (target == DISPLAY_1)) { + ret = PRISM_WVGA; + } + break; + + case 0xD263: + if (target == DISPLAY_1) + ret = TOSHIBA_VGA_PRIM; + else if (target == DISPLAY_2) + ret = TOSHIBA_QCIF_SECD; + break; + + case 0: + if (mddi_client_capability_pkt.Product_Code == 0x8835) { + if (target == DISPLAY_1) + ret = SHARP_QVGA_PRIM; + else if (target == DISPLAY_2) + ret = SHARP_128x128_SECD; + } + break; + + default: + break; + } + + if ((!client_detection_try) && (ret != TOSHIBA_VGA_PRIM) + && (ret != TOSHIBA_QCIF_SECD)) { + /* Not a Toshiba display, so change drive_lo back to default value */ + mddi_host_reg_out(DRIVE_LO, 0x0032); + } +#endif + +#endif + + return mddi_client_id; +} +#endif + +void mddi_host_powerdown(mddi_host_type host_idx) +{ + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (host_idx >= MDDI_NUM_HOST_CORES) { + MDDI_MSG_ERR("Invalid host core index\n"); + return; + } + + if (pmhctl->driver_state == MDDI_DRIVER_RESET) { + return; + } + + if (host_idx == MDDI_HOST_PRIM) { + /* disable timer */ + del_timer(&mddi_host_timer); + } + + mddi_host_configure_interrupts(host_idx, FALSE); + + /* turn on HCLK to MDDI host core if it has been disabled */ + mddi_host_enable_hclk(); + + /* MDDI Reset command */ + mddi_host_reg_out(CMD, MDDI_CMD_RESET); + + /* Pad Control Register */ + mddi_host_reg_out(PAD_CTL, 0x0); + + /* disable IO_CLK and hclk to MDDI host core */ + mddi_host_disable_io_clock(); + mddi_host_disable_hclk(); + + pmhctl->link_state = MDDI_LINK_DISABLED; + pmhctl->driver_state = MDDI_DRIVER_RESET; + + MDDI_MSG_NOTICE("MDDI Host: Disabling Link\n"); + +} + +uint16 mddi_get_next_free_llist_item(mddi_host_type host_idx, boolean wait) +{ + unsigned long flags; + uint16 ret_idx; + boolean forced_wait = FALSE; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + ret_idx = pmhctl->llist_info.next_free_idx; + + pmhctl->llist_info.next_free_idx++; + if (pmhctl->llist_info.next_free_idx >= MDDI_NUM_DYNAMIC_LLIST_ITEMS) + pmhctl->llist_info.next_free_idx = MDDI_FIRST_DYNAMIC_LLIST_IDX; + spin_lock_irqsave(&mddi_host_spin_lock, flags); + if (pmhctl->llist_notify[ret_idx].in_use) { + if (!wait) { + pmhctl->llist_info.next_free_idx = ret_idx; + ret_idx = UNASSIGNED_INDEX; + } else { + forced_wait = TRUE; + INIT_COMPLETION(pmhctl->mddi_llist_avail_comp); + } + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (forced_wait) { + wait_for_completion_killable(& + (pmhctl-> + mddi_llist_avail_comp)); + MDDI_MSG_ERR("task waiting on mddi llist item\n"); + } + + if (ret_idx != UNASSIGNED_INDEX) { + pmhctl->llist_notify[ret_idx].waiting = FALSE; + pmhctl->llist_notify[ret_idx].done_cb = NULL; + pmhctl->llist_notify[ret_idx].in_use = TRUE; + pmhctl->llist_notify[ret_idx].next_idx = UNASSIGNED_INDEX; + } + + return ret_idx; +} + +uint16 mddi_get_reg_read_llist_item(mddi_host_type host_idx, boolean wait) +{ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + MDDI_MSG_CRIT("No reverse link available\n"); + (void)wait; + return FALSE; +#else + unsigned long flags; + uint16 ret_idx; + boolean error = FALSE; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + if (pmhctl->llist_info.reg_read_idx != UNASSIGNED_INDEX) { + /* need to block here or is this an error condition? */ + error = TRUE; + ret_idx = UNASSIGNED_INDEX; + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (!error) { + ret_idx = pmhctl->llist_info.reg_read_idx = + mddi_get_next_free_llist_item(host_idx, wait); + /* clear the reg_read_waiting flag */ + pmhctl->llist_info.reg_read_waiting = FALSE; + } + + if (error) + MDDI_MSG_ERR("***** Reg read still in progress! ****\n"); + return ret_idx; +#endif + +} + +void mddi_queue_forward_packets(uint16 first_llist_idx, + uint16 last_llist_idx, + boolean wait, + mddi_llist_done_cb_type llist_done_cb, + mddi_host_type host_idx) +{ + unsigned long flags; + mddi_linked_list_type *llist; + mddi_linked_list_type *llist_dma; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if ((first_llist_idx >= UNASSIGNED_INDEX) || + (last_llist_idx >= UNASSIGNED_INDEX)) { + MDDI_MSG_ERR("MDDI queueing invalid linked list\n"); + return; + } + + if (pmhctl->link_state == MDDI_LINK_DISABLED) + MDDI_MSG_CRIT("MDDI host powered down!\n"); + + llist = pmhctl->llist_ptr; + llist_dma = pmhctl->llist_dma_ptr; + + /* clean cache so MDDI host can read data */ + memory_barrier(); + + pmhctl->llist_notify[last_llist_idx].waiting = wait; + if (wait) + INIT_COMPLETION(pmhctl->llist_notify[last_llist_idx].done_comp); + pmhctl->llist_notify[last_llist_idx].done_cb = llist_done_cb; + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + if ((pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->rev_state == MDDI_REV_IDLE)) { + /* no packets are currently transmitting */ +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (first_llist_idx == pmhctl->llist_info.reg_read_idx) { + /* This is the special case where the packet is a register read. */ + pmhctl->rev_state = MDDI_REV_REG_READ_ISSUED; + mddi_reg_read_retry = 0; + /* mddi_rev_reg_read_attempt = 1; */ + } +#endif + /* assign transmitting index values */ + pmhctl->llist_info.transmitting_start_idx = first_llist_idx; + pmhctl->llist_info.transmitting_end_idx = last_llist_idx; + + /* turn on clock(s), if they have been disabled */ + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + pmhctl->int_type.llist_ptr_write_1++; + /* Write to primary pointer register */ + dma_coherent_pre_ops(); + mddi_host_reg_out(PRI_PTR, &llist_dma[first_llist_idx]); + + /* enable interrupt when complete */ + mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, + MDDI_INT_PRI_LINK_LIST_DONE); + + } else if (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) { +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (first_llist_idx == pmhctl->llist_info.reg_read_idx) { + /* + * we have a register read to send but need to wait + * for current reverse activity to end or there are + * packets currently transmitting + */ + /* mddi_rev_reg_read_attempt = 0; */ + pmhctl->llist_info.reg_read_waiting = TRUE; + } +#endif + + /* assign waiting index values */ + pmhctl->llist_info.waiting_start_idx = first_llist_idx; + pmhctl->llist_info.waiting_end_idx = last_llist_idx; + } else { + uint16 prev_end_idx = pmhctl->llist_info.waiting_end_idx; +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (first_llist_idx == pmhctl->llist_info.reg_read_idx) { + /* + * we have a register read to send but need to wait + * for current reverse activity to end or there are + * packets currently transmitting + */ + /* mddi_rev_reg_read_attempt = 0; */ + pmhctl->llist_info.reg_read_waiting = TRUE; + } +#endif + + llist = pmhctl->llist_ptr; + + /* clear end flag in previous last packet */ + llist[prev_end_idx].link_controller_flags = 0; + pmhctl->llist_notify[prev_end_idx].next_idx = first_llist_idx; + + /* set the next_packet_pointer of the previous last packet */ + llist[prev_end_idx].next_packet_pointer = + (void *)(&llist_dma[first_llist_idx]); + + /* clean cache so MDDI host can read data */ + memory_barrier(); + + /* assign new waiting last index value */ + pmhctl->llist_info.waiting_end_idx = last_llist_idx; + } + + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + +} + +void mddi_host_write_pix_attr_reg(uint32 value) +{ + (void)value; +} + +void mddi_queue_reverse_encapsulation(boolean wait) +{ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + MDDI_MSG_CRIT("No reverse link available\n"); + (void)wait; +#else + unsigned long flags; + boolean error = FALSE; + mddi_host_type host_idx = MDDI_HOST_PRIM; + mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + /* turn on clock(s), if they have been disabled */ + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + + if (wait) { + if (!mddi_rev_user.waiting) { + mddi_rev_user.waiting = TRUE; + INIT_COMPLETION(mddi_rev_user.done_comp); + } else + error = TRUE; + } + mddi_rev_encap_user_request = TRUE; + + if (pmhctl->rev_state == MDDI_REV_IDLE) { + /* attempt to send the reverse encapsulation now */ + mddi_host_type orig_host_idx = mddi_curr_host; + mddi_curr_host = host_idx; + mddi_issue_reverse_encapsulation(); + mddi_curr_host = orig_host_idx; + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (error) { + MDDI_MSG_ERR("Reverse Encap request already in progress\n"); + } else if (wait) + wait_for_completion_killable(&(mddi_rev_user.done_comp)); +#endif +} + +/* ISR to be executed */ +boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type) +{ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + MDDI_MSG_CRIT("No reverse link available\n"); + (void)handler; + (void)pkt_type; + return (FALSE); +#else + unsigned long flags; + uint16 hdlr; + boolean handler_set = FALSE; + boolean overwrite = FALSE; + mddi_host_type host_idx = MDDI_HOST_PRIM; + mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + /* Disable interrupts */ + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; hdlr++) { + if (mddi_rev_pkt_handler[hdlr].pkt_type == pkt_type) { + mddi_rev_pkt_handler[hdlr].handler = handler; + if (handler == NULL) { + /* clearing handler from table */ + mddi_rev_pkt_handler[hdlr].pkt_type = + INVALID_PKT_TYPE; + handler_set = TRUE; + if (pkt_type == 0x10) { /* video stream packet */ + /* ensure HCLK on to MDDI host core before register write */ + mddi_host_enable_hclk(); + /* No longer getting video, so reset rev encap size to default */ + pmhctl->rev_pkt_size = + MDDI_DEFAULT_REV_PKT_SIZE; + mddi_host_reg_out(REV_ENCAP_SZ, + pmhctl->rev_pkt_size); + } + } else { + /* already a handler for this packet */ + overwrite = TRUE; + } + break; + } + } + if ((hdlr >= MAX_MDDI_REV_HANDLERS) && (handler != NULL)) { + /* assigning new handler */ + for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; hdlr++) { + if (mddi_rev_pkt_handler[hdlr].pkt_type == + INVALID_PKT_TYPE) { + if ((pkt_type == 0x10) && /* video stream packet */ + (pmhctl->rev_pkt_size < + MDDI_VIDEO_REV_PKT_SIZE)) { + /* ensure HCLK on to MDDI host core before register write */ + mddi_host_enable_hclk(); + /* Increase Rev Encap Size */ + pmhctl->rev_pkt_size = + MDDI_VIDEO_REV_PKT_SIZE; + mddi_host_reg_out(REV_ENCAP_SZ, + pmhctl->rev_pkt_size); + } + mddi_rev_pkt_handler[hdlr].handler = handler; + mddi_rev_pkt_handler[hdlr].pkt_type = pkt_type; + handler_set = TRUE; + break; + } + } + } + + /* Restore interrupts */ + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (overwrite) + MDDI_MSG_ERR("Overwriting previous rev packet handler\n"); + + return handler_set; + +#endif +} /* mddi_set_rev_handler */ + +void mddi_host_disable_hibernation(boolean disable) +{ + mddi_host_type host_idx = MDDI_HOST_PRIM; + mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + if (disable) { + pmhctl->disable_hibernation = TRUE; + /* hibernation will be turned off by isr next time it is entered */ + } else { + if (pmhctl->disable_hibernation) { + unsigned long flags; + spin_lock_irqsave(&mddi_host_spin_lock, flags); + if (!MDDI_HOST_IS_HCLK_ON) + MDDI_HOST_ENABLE_HCLK; + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1); + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + pmhctl->disable_hibernation = FALSE; + } + } +} + +void mddi_mhctl_remove(mddi_host_type host_idx) +{ + mddi_host_cntl_type *pmhctl; + + pmhctl = &(mhctl[host_idx]); + + dma_free_coherent(NULL, MDDI_LLIST_POOL_SIZE, (void *)pmhctl->llist_ptr, + pmhctl->llist_dma_addr); + + dma_free_coherent(NULL, MDDI_MAX_REV_DATA_SIZE, + (void *)pmhctl->rev_data_buf, + pmhctl->rev_data_dma_addr); +} diff --git a/drivers/staging/msm/mddihosti.h b/drivers/staging/msm/mddihosti.h new file mode 100644 index 000000000000..7b26a4253896 --- /dev/null +++ b/drivers/staging/msm/mddihosti.h @@ -0,0 +1,547 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * + */ + +#ifndef MDDIHOSTI_H +#define MDDIHOSTI_H + +#include "msm_fb.h" +#include "mddihost.h" +#include <linux/clk.h> + +/* Register offsets in MDDI, applies to both msm_pmdh_base and + * (u32)msm_emdh_base. */ +#define MDDI_CMD 0x0000 +#define MDDI_VERSION 0x0004 +#define MDDI_PRI_PTR 0x0008 +#define MDDI_BPS 0x0010 +#define MDDI_SPM 0x0014 +#define MDDI_INT 0x0018 +#define MDDI_INTEN 0x001c +#define MDDI_REV_PTR 0x0020 +#define MDDI_REV_SIZE 0x0024 +#define MDDI_STAT 0x0028 +#define MDDI_REV_RATE_DIV 0x002c +#define MDDI_REV_CRC_ERR 0x0030 +#define MDDI_TA1_LEN 0x0034 +#define MDDI_TA2_LEN 0x0038 +#define MDDI_TEST 0x0040 +#define MDDI_REV_PKT_CNT 0x0044 +#define MDDI_DRIVE_HI 0x0048 +#define MDDI_DRIVE_LO 0x004c +#define MDDI_DISP_WAKE 0x0050 +#define MDDI_REV_ENCAP_SZ 0x0054 +#define MDDI_RTD_VAL 0x0058 +#define MDDI_PAD_CTL 0x0068 +#define MDDI_DRIVER_START_CNT 0x006c +#define MDDI_CORE_VER 0x008c +#define MDDI_FIFO_ALLOC 0x0090 +#define MDDI_PAD_IO_CTL 0x00a0 +#define MDDI_PAD_CAL 0x00a4 + +extern u32 mddi_msg_level; + +/* No longer need to write to clear these registers */ +#define xxxx_mddi_host_reg_outm(reg, mask, val) \ +do { \ + if (host_idx == MDDI_HOST_PRIM) \ + mddi_host_reg_outm_pmdh(reg, mask, val); \ + else \ + mddi_host_reg_outm_emdh(reg, mask, val); \ +} while (0) + +#define mddi_host_reg_outm(reg, mask, val) \ +do { \ + unsigned long __addr; \ + if (host_idx == MDDI_HOST_PRIM) \ + __addr = (u32)msm_pmdh_base + MDDI_##reg; \ + else \ + __addr = (u32)msm_emdh_base + MDDI_##reg; \ + writel((readl(__addr) & ~(mask)) | ((val) & (mask)), __addr); \ +} while (0) + +#define xxxx_mddi_host_reg_out(reg, val) \ +do { \ + if (host_idx == MDDI_HOST_PRIM) \ + mddi_host_reg_out_pmdh(reg, val); \ + else \ + mddi_host_reg_out_emdh(reg, val); \ + } while (0) + +#define mddi_host_reg_out(reg, val) \ +do { \ + if (host_idx == MDDI_HOST_PRIM) \ + writel(val, (u32)msm_pmdh_base + MDDI_##reg); \ + else \ + writel(val, (u32)msm_emdh_base + MDDI_##reg); \ +} while (0) + +#define xxxx_mddi_host_reg_in(reg) \ + ((host_idx) ? \ + mddi_host_reg_in_emdh(reg) : mddi_host_reg_in_pmdh(reg)); + +#define mddi_host_reg_in(reg) \ +((host_idx) ? \ + readl((u32)msm_emdh_base + MDDI_##reg) : \ + readl((u32)msm_pmdh_base + MDDI_##reg)) \ + +#define xxxx_mddi_host_reg_inm(reg, mask) \ + ((host_idx) ? \ + mddi_host_reg_inm_emdh(reg, mask) : \ + mddi_host_reg_inm_pmdh(reg, mask);) + +#define mddi_host_reg_inm(reg, mask) \ +((host_idx) ? \ + readl((u32)msm_emdh_base + MDDI_##reg) & (mask) : \ + readl((u32)msm_pmdh_base + MDDI_##reg) & (mask)) \ + +/* Using non-cacheable pmem, so do nothing */ +#define mddi_invalidate_cache_lines(addr_start, num_bytes) +/* + * Using non-cacheable pmem, so do nothing with cache + * but, ensure write goes out to memory + */ +#define mddi_flush_cache_lines(addr_start, num_bytes) \ + (void) addr_start; \ + (void) num_bytes; \ + memory_barrier() + +/* Since this translates to Remote Procedure Calls to check on clock status +* just use a local variable to keep track of io_clock */ +#define MDDI_HOST_IS_IO_CLOCK_ON mddi_host_io_clock_on +#define MDDI_HOST_ENABLE_IO_CLOCK +#define MDDI_HOST_DISABLE_IO_CLOCK +#define MDDI_HOST_IS_HCLK_ON mddi_host_hclk_on +#define MDDI_HOST_ENABLE_HCLK +#define MDDI_HOST_DISABLE_HCLK +#define FEATURE_MDDI_HOST_IO_CLOCK_CONTROL_DISABLE +#define FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE + +#define TRAMP_MDDI_HOST_ISR TRAMP_MDDI_PRI_ISR +#define TRAMP_MDDI_HOST_EXT_ISR TRAMP_MDDI_EXT_ISR +#define MDP_LINE_COUNT_BMSK 0x3ff +#define MDP_SYNC_STATUS 0x000c +#define MDP_LINE_COUNT \ +(readl(msm_mdp_base + MDP_SYNC_STATUS) & MDP_LINE_COUNT_BMSK) + +/* MDP sends 256 pixel packets, so lower value hibernates more without +* significantly increasing latency of waiting for next subframe */ +#define MDDI_HOST_BYTES_PER_SUBFRAME 0x3C00 + +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) +#define MDDI_HOST_TA2_LEN 0x001a +#define MDDI_HOST_REV_RATE_DIV 0x0004 +#else +#define MDDI_HOST_TA2_LEN 0x000c +#define MDDI_HOST_REV_RATE_DIV 0x0002 +#endif + +#define MDDI_MSG_EMERG(msg, ...) \ + if (mddi_msg_level > 0) \ + printk(KERN_EMERG msg, ## __VA_ARGS__); +#define MDDI_MSG_ALERT(msg, ...) \ + if (mddi_msg_level > 1) \ + printk(KERN_ALERT msg, ## __VA_ARGS__); +#define MDDI_MSG_CRIT(msg, ...) \ + if (mddi_msg_level > 2) \ + printk(KERN_CRIT msg, ## __VA_ARGS__); +#define MDDI_MSG_ERR(msg, ...) \ + if (mddi_msg_level > 3) \ + printk(KERN_ERR msg, ## __VA_ARGS__); +#define MDDI_MSG_WARNING(msg, ...) \ + if (mddi_msg_level > 4) \ + printk(KERN_WARNING msg, ## __VA_ARGS__); +#define MDDI_MSG_NOTICE(msg, ...) \ + if (mddi_msg_level > 5) \ + printk(KERN_NOTICE msg, ## __VA_ARGS__); +#define MDDI_MSG_INFO(msg, ...) \ + if (mddi_msg_level > 6) \ + printk(KERN_INFO msg, ## __VA_ARGS__); +#define MDDI_MSG_DEBUG(msg, ...) \ + if (mddi_msg_level > 7) \ + printk(KERN_DEBUG msg, ## __VA_ARGS__); + +#define GCC_PACKED __attribute__((packed)) +typedef struct GCC_PACKED { + uint16 packet_length; + /* total # of bytes in the packet not including + the packet_length field. */ + + uint16 packet_type; + /* A Packet Type of 70 identifies the packet as + a Client status Packet. */ + + uint16 bClient_ID; + /* This field is reserved for future use and shall + be set to zero. */ + +} mddi_rev_packet_type; + +typedef struct GCC_PACKED { + uint16 packet_length; + /* total # of bytes in the packet not including + the packet_length field. */ + + uint16 packet_type; + /* A Packet Type of 70 identifies the packet as + a Client status Packet. */ + + uint16 bClient_ID; + /* This field is reserved for future use and shall + be set to zero. */ + + uint16 reverse_link_request; + /* 16 bit unsigned integer with number of bytes client + needs in the * reverse encapsulation message + to transmit data. */ + + uint8 crc_error_count; + uint8 capability_change; + uint16 graphics_busy_flags; + + uint16 parameter_CRC; + /* 16-bit CRC of all the bytes in the packet + including Packet Length. */ + +} mddi_client_status_type; + +typedef struct GCC_PACKED { + uint16 packet_length; + /* total # of bytes in the packet not including + the packet_length field. */ + + uint16 packet_type; + /* A Packet Type of 66 identifies the packet as + a Client Capability Packet. */ + + uint16 bClient_ID; + /* This field is reserved for future use and + shall be set to zero. */ + + uint16 Protocol_Version; + uint16 Minimum_Protocol_Version; + uint16 Data_Rate_Capability; + uint8 Interface_Type_Capability; + uint8 Number_of_Alt_Displays; + uint16 PostCal_Data_Rate; + uint16 Bitmap_Width; + uint16 Bitmap_Height; + uint16 Display_Window_Width; + uint16 Display_Window_Height; + uint32 Color_Map_Size; + uint16 Color_Map_RGB_Width; + uint16 RGB_Capability; + uint8 Monochrome_Capability; + uint8 Reserved_1; + uint16 Y_Cb_Cr_Capability; + uint16 Bayer_Capability; + uint16 Alpha_Cursor_Image_Planes; + uint32 Client_Feature_Capability_Indicators; + uint8 Maximum_Video_Frame_Rate_Capability; + uint8 Minimum_Video_Frame_Rate_Capability; + uint16 Minimum_Sub_frame_Rate; + uint16 Audio_Buffer_Depth; + uint16 Audio_Channel_Capability; + uint16 Audio_Sample_Rate_Capability; + uint8 Audio_Sample_Resolution; + uint8 Mic_Audio_Sample_Resolution; + uint16 Mic_Sample_Rate_Capability; + uint8 Keyboard_Data_Format; + uint8 pointing_device_data_format; + uint16 content_protection_type; + uint16 Mfr_Name; + uint16 Product_Code; + uint16 Reserved_3; + uint32 Serial_Number; + uint8 Week_of_Manufacture; + uint8 Year_of_Manufacture; + + uint16 parameter_CRC; + /* 16-bit CRC of all the bytes in the packet including Packet Length. */ + +} mddi_client_capability_type; + +typedef struct GCC_PACKED { + uint16 packet_length; + /* total # of bytes in the packet not including the packet_length field. */ + + uint16 packet_type; + /* A Packet Type of 16 identifies the packet as a Video Stream Packet. */ + + uint16 bClient_ID; + /* This field is reserved for future use and shall be set to zero. */ + + uint16 video_data_format_descriptor; + /* format of each pixel in the Pixel Data in the present stream in the + * present packet. + * If bits [15:13] = 000 monochrome + * If bits [15:13] = 001 color pixels (palette). + * If bits [15:13] = 010 color pixels in raw RGB + * If bits [15:13] = 011 data in 4:2:2 Y Cb Cr format + * If bits [15:13] = 100 Bayer pixels + */ + + uint16 pixel_data_attributes; + /* interpreted as follows: + * Bits [1:0] = 11 pixel data is displayed to both eyes + * Bits [1:0] = 10 pixel data is routed to the left eye only. + * Bits [1:0] = 01 pixel data is routed to the right eye only. + * Bits [1:0] = 00 pixel data is routed to the alternate display. + * Bit 2 is 0 Pixel Data is in the standard progressive format. + * Bit 2 is 1 Pixel Data is in interlace format. + * Bit 3 is 0 Pixel Data is in the standard progressive format. + * Bit 3 is 1 Pixel Data is in alternate pixel format. + * Bit 4 is 0 Pixel Data is to or from the display frame buffer. + * Bit 4 is 1 Pixel Data is to or from the camera. + * Bit 5 is 0 pixel data contains the next consecutive row of pixels. + * Bit 5 is 1 X Left Edge, Y Top Edge, X Right Edge, Y Bottom Edge, + * X Start, and Y Start parameters are not defined and + * shall be ignored by the client. + * Bits [7:6] = 01 Pixel data is written to the offline image buffer. + * Bits [7:6] = 00 Pixel data is written to the buffer to refresh display. + * Bits [7:6] = 11 Pixel data is written to all image buffers. + * Bits [7:6] = 10 Invalid. Reserved for future use. + * Bits 8 through 11 alternate display number. + * Bits 12 through 14 are reserved for future use and shall be set to zero. + * Bit 15 is 1 the row of pixels is the last row of pixels in a frame. + */ + + uint16 x_left_edge; + uint16 y_top_edge; + /* X,Y coordinate of the top left edge of the screen window */ + + uint16 x_right_edge; + uint16 y_bottom_edge; + /* X,Y coordinate of the bottom right edge of the window being updated. */ + + uint16 x_start; + uint16 y_start; + /* (X Start, Y Start) is the first pixel in the Pixel Data field below. */ + + uint16 pixel_count; + /* number of pixels in the Pixel Data field below. */ + + uint16 parameter_CRC; + /* 16-bit CRC of all bytes from the Packet Length to the Pixel Count. */ + + uint16 reserved; + /* 16-bit variable to make structure align on 4 byte boundary */ + +} mddi_video_stream_packet_type; + +typedef struct GCC_PACKED { + uint16 packet_length; + /* total # of bytes in the packet not including the packet_length field. */ + + uint16 packet_type; + /* A Packet Type of 146 identifies the packet as a Register Access Packet. */ + + uint16 bClient_ID; + /* This field is reserved for future use and shall be set to zero. */ + + uint16 read_write_info; + /* Bits 13:0 a 14-bit unsigned integer that specifies the number of + * 32-bit Register Data List items to be transferred in the + * Register Data List field. + * Bits[15:14] = 00 Write to register(s); + * Bits[15:14] = 10 Read from register(s); + * Bits[15:14] = 11 Response to a Read. + * Bits[15:14] = 01 this value is reserved for future use. */ + + uint32 register_address; + /* the register address that is to be written to or read from. */ + + uint16 parameter_CRC; + /* 16-bit CRC of all bytes from the Packet Length to the Register Address. */ + + uint32 register_data_list; + /* list of 4-byte register data values for/from client registers */ + +} mddi_register_access_packet_type; + +typedef union GCC_PACKED { + mddi_video_stream_packet_type video_pkt; + mddi_register_access_packet_type register_pkt; + /* add 48 byte pad to ensure 64 byte llist struct, that can be + * manipulated easily with cache */ + uint32 alignment_pad[12]; /* 48 bytes */ +} mddi_packet_header_type; + +typedef struct GCC_PACKED mddi_host_llist_struct { + uint16 link_controller_flags; + uint16 packet_header_count; + uint16 packet_data_count; + void *packet_data_pointer; + struct mddi_host_llist_struct *next_packet_pointer; + uint16 reserved; + mddi_packet_header_type packet_header; +} mddi_linked_list_type; + +typedef struct { + struct completion done_comp; + mddi_llist_done_cb_type done_cb; + uint16 next_idx; + boolean waiting; + boolean in_use; +} mddi_linked_list_notify_type; + +#define MDDI_LLIST_POOL_SIZE 0x1000 +#define MDDI_MAX_NUM_LLIST_ITEMS (MDDI_LLIST_POOL_SIZE / \ + sizeof(mddi_linked_list_type)) +#define UNASSIGNED_INDEX MDDI_MAX_NUM_LLIST_ITEMS +#define MDDI_FIRST_DYNAMIC_LLIST_IDX 0 + +/* Static llist items can be used for applications that frequently send + * the same set of packets using the linked list interface. */ +/* Here we configure for 6 static linked list items: + * The 1st is used for a the adaptive backlight setting. + * and the remaining 5 are used for sending window adjustments for + * MDDI clients that need windowing info sent separate from video + * packets. */ +#define MDDI_NUM_STATIC_ABL_ITEMS 1 +#define MDDI_NUM_STATIC_WINDOW_ITEMS 5 +#define MDDI_NUM_STATIC_LLIST_ITEMS (MDDI_NUM_STATIC_ABL_ITEMS + \ + MDDI_NUM_STATIC_WINDOW_ITEMS) +#define MDDI_NUM_DYNAMIC_LLIST_ITEMS (MDDI_MAX_NUM_LLIST_ITEMS - \ + MDDI_NUM_STATIC_LLIST_ITEMS) + +#define MDDI_FIRST_STATIC_LLIST_IDX MDDI_NUM_DYNAMIC_LLIST_ITEMS +#define MDDI_FIRST_STATIC_ABL_IDX MDDI_FIRST_STATIC_LLIST_IDX +#define MDDI_FIRST_STATIC_WINDOW_IDX (MDDI_FIRST_STATIC_LLIST_IDX + \ + MDDI_NUM_STATIC_ABL_ITEMS) + +/* GPIO registers */ +#define VSYNC_WAKEUP_REG 0x80 +#define GPIO_REG 0x81 +#define GPIO_OUTPUT_REG 0x82 +#define GPIO_INTERRUPT_REG 0x83 +#define GPIO_INTERRUPT_ENABLE_REG 0x84 +#define GPIO_POLARITY_REG 0x85 + +/* Interrupt Bits */ +#define MDDI_INT_PRI_PTR_READ 0x0001 +#define MDDI_INT_SEC_PTR_READ 0x0002 +#define MDDI_INT_REV_DATA_AVAIL 0x0004 +#define MDDI_INT_DISP_REQ 0x0008 +#define MDDI_INT_PRI_UNDERFLOW 0x0010 +#define MDDI_INT_SEC_UNDERFLOW 0x0020 +#define MDDI_INT_REV_OVERFLOW 0x0040 +#define MDDI_INT_CRC_ERROR 0x0080 +#define MDDI_INT_MDDI_IN 0x0100 +#define MDDI_INT_PRI_OVERWRITE 0x0200 +#define MDDI_INT_SEC_OVERWRITE 0x0400 +#define MDDI_INT_REV_OVERWRITE 0x0800 +#define MDDI_INT_DMA_FAILURE 0x1000 +#define MDDI_INT_LINK_ACTIVE 0x2000 +#define MDDI_INT_IN_HIBERNATION 0x4000 +#define MDDI_INT_PRI_LINK_LIST_DONE 0x8000 +#define MDDI_INT_SEC_LINK_LIST_DONE 0x10000 +#define MDDI_INT_NO_CMD_PKTS_PEND 0x20000 +#define MDDI_INT_RTD_FAILURE 0x40000 + +#define MDDI_INT_ERROR_CONDITIONS ( \ + MDDI_INT_PRI_UNDERFLOW | MDDI_INT_SEC_UNDERFLOW | \ + MDDI_INT_REV_OVERFLOW | MDDI_INT_CRC_ERROR | \ + MDDI_INT_PRI_OVERWRITE | MDDI_INT_SEC_OVERWRITE | \ + MDDI_INT_RTD_FAILURE | \ + MDDI_INT_REV_OVERWRITE | MDDI_INT_DMA_FAILURE) + +#define MDDI_INT_LINK_STATE_CHANGES ( \ + MDDI_INT_LINK_ACTIVE | MDDI_INT_IN_HIBERNATION) + +/* Status Bits */ +#define MDDI_STAT_LINK_ACTIVE 0x0001 +#define MDDI_STAT_NEW_REV_PTR 0x0002 +#define MDDI_STAT_NEW_PRI_PTR 0x0004 +#define MDDI_STAT_NEW_SEC_PTR 0x0008 +#define MDDI_STAT_IN_HIBERNATION 0x0010 +#define MDDI_STAT_PRI_LINK_LIST_DONE 0x0020 +#define MDDI_STAT_SEC_LINK_LIST_DONE 0x0040 +#define MDDI_STAT_PENDING_TIMING_PKT 0x0080 +#define MDDI_STAT_PENDING_REV_ENCAP 0x0100 +#define MDDI_STAT_PENDING_POWERDOWN 0x0200 +#define MDDI_STAT_RTD_MEAS_FAIL 0x0800 +#define MDDI_STAT_CLIENT_WAKEUP_REQ 0x1000 + +/* Command Bits */ +#define MDDI_CMD_POWERDOWN 0x0100 +#define MDDI_CMD_POWERUP 0x0200 +#define MDDI_CMD_HIBERNATE 0x0300 +#define MDDI_CMD_RESET 0x0400 +#define MDDI_CMD_DISP_IGNORE 0x0501 +#define MDDI_CMD_DISP_LISTEN 0x0500 +#define MDDI_CMD_SEND_REV_ENCAP 0x0600 +#define MDDI_CMD_GET_CLIENT_CAP 0x0601 +#define MDDI_CMD_GET_CLIENT_STATUS 0x0602 +#define MDDI_CMD_SEND_RTD 0x0700 +#define MDDI_CMD_LINK_ACTIVE 0x0900 +#define MDDI_CMD_PERIODIC_REV_ENCAP 0x0A00 + +extern void mddi_host_init(mddi_host_type host); +extern void mddi_host_powerdown(mddi_host_type host); +extern uint16 mddi_get_next_free_llist_item(mddi_host_type host, boolean wait); +extern uint16 mddi_get_reg_read_llist_item(mddi_host_type host, boolean wait); +extern void mddi_queue_forward_packets(uint16 first_llist_idx, + uint16 last_llist_idx, + boolean wait, + mddi_llist_done_cb_type llist_done_cb, + mddi_host_type host); + +extern void mddi_host_write_pix_attr_reg(uint32 value); +extern void mddi_client_lcd_gpio_poll(uint32 poll_reg_val); +extern void mddi_client_lcd_vsync_detected(boolean detected); +extern void mddi_host_disable_hibernation(boolean disable); + +extern mddi_linked_list_type *llist_extern[]; +extern mddi_linked_list_type *llist_dma_extern[]; +extern mddi_linked_list_notify_type *llist_extern_notify[]; +extern struct timer_list mddi_host_timer; + +typedef struct { + uint16 transmitting_start_idx; + uint16 transmitting_end_idx; + uint16 waiting_start_idx; + uint16 waiting_end_idx; + uint16 reg_read_idx; + uint16 next_free_idx; + boolean reg_read_waiting; +} mddi_llist_info_type; + +extern mddi_llist_info_type mddi_llist; + +#define MDDI_GPIO_DEFAULT_POLLING_INTERVAL 200 +typedef struct { + uint32 polling_reg; + uint32 polling_val; + uint32 polling_interval; + boolean polling_enabled; +} mddi_gpio_info_type; + +uint32 mddi_get_client_id(void); +void mddi_mhctl_remove(mddi_host_type host_idx); +void mddi_host_timer_service(unsigned long data); +#endif /* MDDIHOSTI_H */ diff --git a/drivers/staging/msm/mdp.c b/drivers/staging/msm/mdp.c new file mode 100644 index 000000000000..36053afdebe2 --- /dev/null +++ b/drivers/staging/msm/mdp.c @@ -0,0 +1,1113 @@ +/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/clk.h> +#include <mach/hardware.h> +#include <linux/io.h> +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/mutex.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> + +#include "mdp.h" +#include "msm_fb.h" +#ifdef CONFIG_FB_MSM_MDP40 +#include "mdp4.h" +#endif + +static struct clk *mdp_clk; +static struct clk *mdp_pclk; + +struct completion mdp_ppp_comp; +struct semaphore mdp_ppp_mutex; +struct semaphore mdp_pipe_ctrl_mutex; + +unsigned long mdp_timer_duration = (HZ); /* 1 sec */ +/* unsigned long mdp_mdp_timer_duration=0; */ + +boolean mdp_ppp_waiting = FALSE; +uint32 mdp_tv_underflow_cnt; +uint32 mdp_lcdc_underflow_cnt; + +boolean mdp_current_clk_on = FALSE; +boolean mdp_is_in_isr = FALSE; + +/* + * legacy mdp_in_processing is only for DMA2-MDDI + * this applies to DMA2 block only + */ +uint32 mdp_in_processing = FALSE; + +#ifdef CONFIG_FB_MSM_MDP40 +uint32 mdp_intr_mask = MDP4_ANY_INTR_MASK; +#else +uint32 mdp_intr_mask = MDP_ANY_INTR_MASK; +#endif + +MDP_BLOCK_TYPE mdp_debug[MDP_MAX_BLOCK]; + +int32 mdp_block_power_cnt[MDP_MAX_BLOCK]; + +spinlock_t mdp_spin_lock; +struct workqueue_struct *mdp_dma_wq; /*mdp dma wq */ +struct workqueue_struct *mdp_vsync_wq; /*mdp vsync wq */ + +static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */ +static struct delayed_work mdp_pipe_ctrl_worker; + +#ifdef CONFIG_FB_MSM_MDP40 +struct mdp_dma_data dma2_data; +struct mdp_dma_data dma_s_data; +struct mdp_dma_data dma_e_data; +#else +static struct mdp_dma_data dma2_data; +static struct mdp_dma_data dma_s_data; +static struct mdp_dma_data dma_e_data; +#endif +static struct mdp_dma_data dma3_data; + +extern ktime_t mdp_dma2_last_update_time; + +extern uint32 mdp_dma2_update_time_in_usec; +extern int mdp_lcd_rd_cnt_offset_slow; +extern int mdp_lcd_rd_cnt_offset_fast; +extern int mdp_usec_diff_threshold; + +#ifdef CONFIG_FB_MSM_LCDC +extern int mdp_lcdc_pclk_clk_rate; +extern int mdp_lcdc_pad_pclk_clk_rate; +extern int first_pixel_start_x; +extern int first_pixel_start_y; +#endif + +#ifdef MSM_FB_ENABLE_DBGFS +struct dentry *mdp_dir; +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int mdp_suspend(struct platform_device *pdev, pm_message_t state); +#else +#define mdp_suspend NULL +#endif + +struct timeval mdp_dma2_timeval; +struct timeval mdp_ppp_timeval; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct early_suspend early_suspend; +#endif + +#ifndef CONFIG_FB_MSM_MDP22 +DEFINE_MUTEX(mdp_lut_push_sem); +static int mdp_lut_i; +static int mdp_lut_hw_update(struct fb_cmap *cmap) +{ + int i; + u16 *c[3]; + u16 r, g, b; + + c[0] = cmap->green; + c[1] = cmap->blue; + c[2] = cmap->red; + + for (i = 0; i < cmap->len; i++) { + if (copy_from_user(&r, cmap->red++, sizeof(r)) || + copy_from_user(&g, cmap->green++, sizeof(g)) || + copy_from_user(&b, cmap->blue++, sizeof(b))) + return -EFAULT; + +#ifdef CONFIG_FB_MSM_MDP40 + MDP_OUTP(MDP_BASE + 0x94800 + +#else + MDP_OUTP(MDP_BASE + 0x93800 + +#endif + (0x400*mdp_lut_i) + cmap->start*4 + i*4, + ((g & 0xff) | + ((b & 0xff) << 8) | + ((r & 0xff) << 16))); + } + + return 0; +} + +static int mdp_lut_push; +static int mdp_lut_push_i; +static int mdp_lut_update_nonlcdc(struct fb_info *info, struct fb_cmap *cmap) +{ + int ret; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + ret = mdp_lut_hw_update(cmap); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + if (ret) + return ret; + + mutex_lock(&mdp_lut_push_sem); + mdp_lut_push = 1; + mdp_lut_push_i = mdp_lut_i; + mutex_unlock(&mdp_lut_push_sem); + + mdp_lut_i = (mdp_lut_i + 1)%2; + + return 0; +} + +static int mdp_lut_update_lcdc(struct fb_info *info, struct fb_cmap *cmap) +{ + int ret; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + ret = mdp_lut_hw_update(cmap); + + if (ret) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return ret; + } + + MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x17); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_lut_i = (mdp_lut_i + 1)%2; + + return 0; +} + +#define MDP_HIST_MAX_BIN 32 +static __u32 mdp_hist_r[MDP_HIST_MAX_BIN]; +static __u32 mdp_hist_g[MDP_HIST_MAX_BIN]; +static __u32 mdp_hist_b[MDP_HIST_MAX_BIN]; + +#ifdef CONFIG_FB_MSM_MDP40 +struct mdp_histogram mdp_hist; +struct completion mdp_hist_comp; +#else +static struct mdp_histogram mdp_hist; +static struct completion mdp_hist_comp; +#endif + +static int mdp_do_histogram(struct fb_info *info, struct mdp_histogram *hist) +{ + int ret = 0; + + if (!hist->frame_cnt || (hist->bin_cnt == 0) || + (hist->bin_cnt > MDP_HIST_MAX_BIN)) + return -EINVAL; + + INIT_COMPLETION(mdp_hist_comp); + + mdp_hist.bin_cnt = hist->bin_cnt; + mdp_hist.r = (hist->r) ? mdp_hist_r : 0; + mdp_hist.g = (hist->g) ? mdp_hist_g : 0; + mdp_hist.b = (hist->b) ? mdp_hist_b : 0; + +#ifdef CONFIG_FB_MSM_MDP40 + MDP_OUTP(MDP_BASE + 0x95004, hist->frame_cnt); + MDP_OUTP(MDP_BASE + 0x95000, 1); +#else + MDP_OUTP(MDP_BASE + 0x94004, hist->frame_cnt); + MDP_OUTP(MDP_BASE + 0x94000, 1); +#endif + wait_for_completion_killable(&mdp_hist_comp); + + if (hist->r) { + ret = copy_to_user(hist->r, mdp_hist.r, hist->bin_cnt*4); + if (ret) + goto hist_err; + } + if (hist->g) { + ret = copy_to_user(hist->g, mdp_hist.g, hist->bin_cnt*4); + if (ret) + goto hist_err; + } + if (hist->b) { + ret = copy_to_user(hist->b, mdp_hist.b, hist->bin_cnt*4); + if (ret) + goto hist_err; + } + return 0; + +hist_err: + printk(KERN_ERR "%s: invalid hist buffer\n", __func__); + return ret; +} +#endif + +/* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */ + +int mdp_ppp_pipe_wait(void) +{ + int ret = 1; + + /* wait 5 seconds for the operation to complete before declaring + the MDP hung */ + + if (mdp_ppp_waiting == TRUE) { + ret = wait_for_completion_interruptible_timeout(&mdp_ppp_comp, + 5 * HZ); + + if (!ret) + printk(KERN_ERR "%s: Timed out waiting for the MDP.\n", + __func__); + } + + return ret; +} + +static DEFINE_SPINLOCK(mdp_lock); +static int mdp_irq_mask; +static int mdp_irq_enabled; + +void mdp_enable_irq(uint32 term) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&mdp_lock, irq_flags); + if (mdp_irq_mask & term) { + printk(KERN_ERR "MDP IRQ term-0x%x is already set\n", term); + } else { + mdp_irq_mask |= term; + if (mdp_irq_mask && !mdp_irq_enabled) { + mdp_irq_enabled = 1; + enable_irq(INT_MDP); + } + } + spin_unlock_irqrestore(&mdp_lock, irq_flags); +} + +void mdp_disable_irq(uint32 term) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&mdp_lock, irq_flags); + if (!(mdp_irq_mask & term)) { + printk(KERN_ERR "MDP IRQ term-0x%x is not set\n", term); + } else { + mdp_irq_mask &= ~term; + if (!mdp_irq_mask && mdp_irq_enabled) { + mdp_irq_enabled = 0; + disable_irq(INT_MDP); + } + } + spin_unlock_irqrestore(&mdp_lock, irq_flags); +} + +void mdp_disable_irq_nolock(uint32 term) +{ + + if (!(mdp_irq_mask & term)) { + printk(KERN_ERR "MDP IRQ term-0x%x is not set\n", term); + } else { + mdp_irq_mask &= ~term; + if (!mdp_irq_mask && mdp_irq_enabled) { + mdp_irq_enabled = 0; + disable_irq(INT_MDP); + } + } +} + +void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd) +{ + + dmb(); /* memory barrier */ + + /* kick off PPP engine */ + if (term == MDP_PPP_TERM) { + if (mdp_debug[MDP_PPP_BLOCK]) + jiffies_to_timeval(jiffies, &mdp_ppp_timeval); + + /* let's turn on PPP block */ + mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + mdp_enable_irq(term); + INIT_COMPLETION(mdp_ppp_comp); + mdp_ppp_waiting = TRUE; + outpdw(MDP_BASE + 0x30, 0x1000); + wait_for_completion_killable(&mdp_ppp_comp); + mdp_disable_irq(term); + + if (mdp_debug[MDP_PPP_BLOCK]) { + struct timeval now; + + jiffies_to_timeval(jiffies, &now); + mdp_ppp_timeval.tv_usec = + now.tv_usec - mdp_ppp_timeval.tv_usec; + MSM_FB_INFO("MDP-PPP: %d\n", + (int)mdp_ppp_timeval.tv_usec); + } + } else if (term == MDP_DMA2_TERM) { + if (mdp_debug[MDP_DMA2_BLOCK]) { + MSM_FB_INFO("MDP-DMA2: %d\n", + (int)mdp_dma2_timeval.tv_usec); + jiffies_to_timeval(jiffies, &mdp_dma2_timeval); + } + /* DMA update timestamp */ + mdp_dma2_last_update_time = ktime_get_real(); + /* let's turn on DMA2 block */ +#if 0 + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); +#endif +#ifdef CONFIG_FB_MSM_MDP22 + outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x0044, 0x0);/* start DMA */ +#else + if (mdp_lut_push) { + mutex_lock(&mdp_lut_push_sem); + mdp_lut_push = 0; + MDP_OUTP(MDP_BASE + 0x90070, + (mdp_lut_push_i << 10) | 0x17); + mutex_unlock(&mdp_lut_push_sem); + } +#ifdef CONFIG_FB_MSM_MDP40 + outpdw(MDP_BASE + 0x000c, 0x0); /* start DMA */ +#else + outpdw(MDP_BASE + 0x0044, 0x0); /* start DMA */ +#endif +#endif +#ifdef CONFIG_FB_MSM_MDP40 + } else if (term == MDP_DMA_S_TERM) { + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0010, 0x0); /* start DMA */ + } else if (term == MDP_DMA_E_TERM) { + mdp_pipe_ctrl(MDP_DMA_E_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0014, 0x0); /* start DMA */ + } else if (term == MDP_OVERLAY0_TERM) { + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0004, 0); + } else if (term == MDP_OVERLAY1_TERM) { + mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0008, 0); + } +#else + } else if (term == MDP_DMA_S_TERM) { + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0048, 0x0); /* start DMA */ + } +#endif +} + +static void mdp_pipe_ctrl_workqueue_handler(struct work_struct *work) +{ + mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state, + boolean isr) +{ + boolean mdp_all_blocks_off = TRUE; + int i; + unsigned long flag; + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (MDP_BLOCK_POWER_ON == state) { + mdp_block_power_cnt[block]++; + + if (MDP_DMA2_BLOCK == block) + mdp_in_processing = TRUE; + } else { + mdp_block_power_cnt[block]--; + + if (mdp_block_power_cnt[block] < 0) { + /* + * Master has to serve a request to power off MDP always + * It also has a timer to power off. So, in case of + * timer expires first and DMA2 finishes later, + * master has to power off two times + * There shouldn't be multiple power-off request for + * other blocks + */ + if (block != MDP_MASTER_BLOCK) { + MSM_FB_INFO("mdp_block_power_cnt[block=%d] \ + multiple power-off request\n", block); + } + mdp_block_power_cnt[block] = 0; + } + + if (MDP_DMA2_BLOCK == block) + mdp_in_processing = FALSE; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + /* + * If it's in isr, we send our request to workqueue. + * Otherwise, processing happens in the current context + */ + if (isr) { + /* checking all blocks power state */ + for (i = 0; i < MDP_MAX_BLOCK; i++) { + if (mdp_block_power_cnt[i] > 0) + mdp_all_blocks_off = FALSE; + } + + if ((mdp_all_blocks_off) && (mdp_current_clk_on)) { + /* send workqueue to turn off mdp power */ + queue_delayed_work(mdp_pipe_ctrl_wq, + &mdp_pipe_ctrl_worker, + mdp_timer_duration); + } + } else { + down(&mdp_pipe_ctrl_mutex); + /* checking all blocks power state */ + for (i = 0; i < MDP_MAX_BLOCK; i++) { + if (mdp_block_power_cnt[i] > 0) + mdp_all_blocks_off = FALSE; + } + + /* + * find out whether a delayable work item is currently + * pending + */ + + if (delayed_work_pending(&mdp_pipe_ctrl_worker)) { + /* + * try to cancel the current work if it fails to + * stop (which means del_timer can't delete it + * from the list, it's about to expire and run), + * we have to let it run. queue_delayed_work won't + * accept the next job which is same as + * queue_delayed_work(mdp_timer_duration = 0) + */ + cancel_delayed_work(&mdp_pipe_ctrl_worker); + } + + if ((mdp_all_blocks_off) && (mdp_current_clk_on)) { + if (block == MDP_MASTER_BLOCK) { + mdp_current_clk_on = FALSE; + /* turn off MDP clks */ + if (mdp_clk != NULL) { + clk_disable(mdp_clk); + MSM_FB_DEBUG("MDP CLK OFF\n"); + } + if (mdp_pclk != NULL) { + clk_disable(mdp_pclk); + MSM_FB_DEBUG("MDP PCLK OFF\n"); + } + } else { + /* send workqueue to turn off mdp power */ + queue_delayed_work(mdp_pipe_ctrl_wq, + &mdp_pipe_ctrl_worker, + mdp_timer_duration); + } + } else if ((!mdp_all_blocks_off) && (!mdp_current_clk_on)) { + mdp_current_clk_on = TRUE; + /* turn on MDP clks */ + if (mdp_clk != NULL) { + clk_enable(mdp_clk); + MSM_FB_DEBUG("MDP CLK ON\n"); + } + if (mdp_pclk != NULL) { + clk_enable(mdp_pclk); + MSM_FB_DEBUG("MDP PCLK ON\n"); + } + } + up(&mdp_pipe_ctrl_mutex); + } +} + +#ifndef CONFIG_FB_MSM_MDP40 +irqreturn_t mdp_isr(int irq, void *ptr) +{ + uint32 mdp_interrupt = 0; + struct mdp_dma_data *dma; + + mdp_is_in_isr = TRUE; + do { + mdp_interrupt = inp32(MDP_INTR_STATUS); + outp32(MDP_INTR_CLEAR, mdp_interrupt); + + mdp_interrupt &= mdp_intr_mask; + + if (mdp_interrupt & TV_ENC_UNDERRUN) { + mdp_interrupt &= ~(TV_ENC_UNDERRUN); + mdp_tv_underflow_cnt++; + } + + if (!mdp_interrupt) + break; + + /* DMA3 TV-Out Start */ + if (mdp_interrupt & TV_OUT_DMA3_START) { + /* let's disable TV out interrupt */ + mdp_intr_mask &= ~TV_OUT_DMA3_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + + dma = &dma3_data; + if (dma->waiting) { + dma->waiting = FALSE; + complete(&dma->comp); + } + } +#ifndef CONFIG_FB_MSM_MDP22 + if (mdp_interrupt & MDP_HIST_DONE) { + outp32(MDP_BASE + 0x94018, 0x3); + outp32(MDP_INTR_CLEAR, MDP_HIST_DONE); + if (mdp_hist.r) + memcpy(mdp_hist.r, MDP_BASE + 0x94100, + mdp_hist.bin_cnt*4); + if (mdp_hist.g) + memcpy(mdp_hist.g, MDP_BASE + 0x94200, + mdp_hist.bin_cnt*4); + if (mdp_hist.b) + memcpy(mdp_hist.b, MDP_BASE + 0x94300, + mdp_hist.bin_cnt*4); + complete(&mdp_hist_comp); + } + + /* LCDC UnderFlow */ + if (mdp_interrupt & LCDC_UNDERFLOW) { + mdp_lcdc_underflow_cnt++; + } + /* LCDC Frame Start */ + if (mdp_interrupt & LCDC_FRAME_START) { + /* let's disable LCDC interrupt */ + mdp_intr_mask &= ~LCDC_FRAME_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + + dma = &dma2_data; + if (dma->waiting) { + dma->waiting = FALSE; + complete(&dma->comp); + } + } + + /* DMA2 LCD-Out Complete */ + if (mdp_interrupt & MDP_DMA_S_DONE) { + dma = &dma_s_data; + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_OFF, + TRUE); + complete(&dma->comp); + } +#endif + + /* DMA2 LCD-Out Complete */ + if (mdp_interrupt & MDP_DMA_P_DONE) { + struct timeval now; + ktime_t now_k; + + now_k = ktime_get_real(); + mdp_dma2_last_update_time.tv.sec = + now_k.tv.sec - mdp_dma2_last_update_time.tv.sec; + mdp_dma2_last_update_time.tv.nsec = + now_k.tv.nsec - mdp_dma2_last_update_time.tv.nsec; + + if (mdp_debug[MDP_DMA2_BLOCK]) { + jiffies_to_timeval(jiffies, &now); + mdp_dma2_timeval.tv_usec = + now.tv_usec - mdp_dma2_timeval.tv_usec; + } + + dma = &dma2_data; + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, + TRUE); + complete(&dma->comp); + } + /* PPP Complete */ + if (mdp_interrupt & MDP_PPP_DONE) { +#ifdef CONFIG_MDP_PPP_ASYNC_OP + mdp_ppp_djob_done(); +#else + mdp_pipe_ctrl(MDP_PPP_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + if (mdp_ppp_waiting) { + mdp_ppp_waiting = FALSE; + complete(&mdp_ppp_comp); + } +#endif + } + } while (1); + + mdp_is_in_isr = FALSE; + + return IRQ_HANDLED; +} +#endif + +static void mdp_drv_init(void) +{ + int i; + + for (i = 0; i < MDP_MAX_BLOCK; i++) { + mdp_debug[i] = 0; + } + + /* initialize spin lock and workqueue */ + spin_lock_init(&mdp_spin_lock); + mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq"); + mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq"); + mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq"); + INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker, + mdp_pipe_ctrl_workqueue_handler); +#ifdef CONFIG_MDP_PPP_ASYNC_OP + mdp_ppp_dq_init(); +#endif + + /* initialize semaphore */ + init_completion(&mdp_ppp_comp); + init_MUTEX(&mdp_ppp_mutex); + init_MUTEX(&mdp_pipe_ctrl_mutex); + + dma2_data.busy = FALSE; + dma2_data.waiting = FALSE; + init_completion(&dma2_data.comp); + init_MUTEX(&dma2_data.mutex); + mutex_init(&dma2_data.ov_mutex); + + dma3_data.busy = FALSE; + dma3_data.waiting = FALSE; + init_completion(&dma3_data.comp); + init_MUTEX(&dma3_data.mutex); + + dma_s_data.busy = FALSE; + dma_s_data.waiting = FALSE; + init_completion(&dma_s_data.comp); + init_MUTEX(&dma_s_data.mutex); + + dma_e_data.busy = FALSE; + dma_e_data.waiting = FALSE; + init_completion(&dma_e_data.comp); + +#ifndef CONFIG_FB_MSM_MDP22 + init_completion(&mdp_hist_comp); +#endif + + /* initializing mdp power block counter to 0 */ + for (i = 0; i < MDP_MAX_BLOCK; i++) { + mdp_block_power_cnt[i] = 0; + } + +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + char sub_name[] = "mdp"; + + root = msm_fb_get_debugfs_root(); + if (root != NULL) { + mdp_dir = debugfs_create_dir(sub_name, root); + + if (mdp_dir) { + msm_fb_debugfs_file_create(mdp_dir, + "dma2_update_time_in_usec", + (u32 *) &mdp_dma2_update_time_in_usec); + msm_fb_debugfs_file_create(mdp_dir, + "vs_rdcnt_slow", + (u32 *) &mdp_lcd_rd_cnt_offset_slow); + msm_fb_debugfs_file_create(mdp_dir, + "vs_rdcnt_fast", + (u32 *) &mdp_lcd_rd_cnt_offset_fast); + msm_fb_debugfs_file_create(mdp_dir, + "mdp_usec_diff_threshold", + (u32 *) &mdp_usec_diff_threshold); + msm_fb_debugfs_file_create(mdp_dir, + "mdp_current_clk_on", + (u32 *) &mdp_current_clk_on); +#ifdef CONFIG_FB_MSM_LCDC + msm_fb_debugfs_file_create(mdp_dir, + "lcdc_start_x", + (u32 *) &first_pixel_start_x); + msm_fb_debugfs_file_create(mdp_dir, + "lcdc_start_y", + (u32 *) &first_pixel_start_y); + msm_fb_debugfs_file_create(mdp_dir, + "mdp_lcdc_pclk_clk_rate", + (u32 *) &mdp_lcdc_pclk_clk_rate); + msm_fb_debugfs_file_create(mdp_dir, + "mdp_lcdc_pad_pclk_clk_rate", + (u32 *) &mdp_lcdc_pad_pclk_clk_rate); +#endif + } + } + } +#endif +} + +static int mdp_probe(struct platform_device *pdev); +static int mdp_remove(struct platform_device *pdev); + +static struct platform_driver mdp_driver = { + .probe = mdp_probe, + .remove = mdp_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = mdp_suspend, + .resume = NULL, +#endif + .shutdown = NULL, + .driver = { + /* + * Driver name must match the device name added in + * platform.c. + */ + .name = "mdp", + }, +}; + +static int mdp_off(struct platform_device *pdev) +{ + int ret = 0; + +#ifdef MDP_HW_VSYNC + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); +#endif + + ret = panel_next_off(pdev); + +#ifdef MDP_HW_VSYNC + mdp_hw_vsync_clk_disable(mfd); +#endif + + return ret; +} + +static int mdp_on(struct platform_device *pdev) +{ +#ifdef MDP_HW_VSYNC + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); +#endif + + int ret = 0; + +#ifdef MDP_HW_VSYNC + mdp_hw_vsync_clk_enable(mfd); +#endif + + ret = panel_next_on(pdev); + + return ret; +} + +static int mdp_irq_clk_setup(void) +{ + int ret; + +#ifdef CONFIG_FB_MSM_MDP40 + ret = request_irq(INT_MDP, mdp4_isr, IRQF_DISABLED, "MDP", 0); +#else + ret = request_irq(INT_MDP, mdp_isr, IRQF_DISABLED, "MDP", 0); +#endif + if (ret) { + printk(KERN_ERR "mdp request_irq() failed!\n"); + return ret; + } + disable_irq(INT_MDP); + + mdp_clk = clk_get(NULL, "mdp_clk"); + + if (IS_ERR(mdp_clk)) { + ret = PTR_ERR(mdp_clk); + printk(KERN_ERR "can't get mdp_clk error:%d!\n", ret); + free_irq(INT_MDP, 0); + return ret; + } + + mdp_pclk = clk_get(NULL, "mdp_pclk"); + if (IS_ERR(mdp_pclk)) + mdp_pclk = NULL; + + +#ifdef CONFIG_FB_MSM_MDP40 + /* + * mdp_clk should greater than mdp_pclk always + */ + clk_set_rate(mdp_clk, 122880000); /* 122.88 Mhz */ + printk(KERN_INFO "mdp_clk: mdp_clk=%d mdp_pclk=%d\n", + (int)clk_get_rate(mdp_clk), (int)clk_get_rate(mdp_pclk)); +#endif + + return 0; +} + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; +static int mdp_resource_initialized; +static struct msm_panel_common_pdata *mdp_pdata; + +static int mdp_probe(struct platform_device *pdev) +{ + struct platform_device *msm_fb_dev = NULL; + struct msm_fb_data_type *mfd; + struct msm_fb_panel_data *pdata = NULL; + int rc; + resource_size_t size ; +#ifdef CONFIG_FB_MSM_MDP40 + int intf, if_no; +#else + unsigned long flag; +#endif + + if ((pdev->id == 0) && (pdev->num_resources > 0)) { + mdp_pdata = pdev->dev.platform_data; + + size = resource_size(&pdev->resource[0]); + msm_mdp_base = ioremap(pdev->resource[0].start, size); + + MSM_FB_INFO("MDP HW Base phy_Address = 0x%x virt = 0x%x\n", + (int)pdev->resource[0].start, (int)msm_mdp_base); + + if (unlikely(!msm_mdp_base)) + return -ENOMEM; + + printk("irq clk setup\n"); + rc = mdp_irq_clk_setup(); + printk("irq clk setup done\n"); + if (rc) + return rc; + + /* initializing mdp hw */ +#ifdef CONFIG_FB_MSM_MDP40 + mdp4_hw_init(); +#else + mdp_hw_init(); +#endif + + mdp_resource_initialized = 1; + return 0; + } + + if (!mdp_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + msm_fb_dev = platform_device_alloc("msm_fb", pdev->id); + if (!msm_fb_dev) + return -ENOMEM; + + /* link to the latest pdev */ + mfd->pdev = msm_fb_dev; + + /* add panel data */ + if (platform_device_add_data + (msm_fb_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "mdp_probe: platform_device_add_data failed!\n"); + rc = -ENOMEM; + goto mdp_probe_err; + } + /* data chain */ + pdata = msm_fb_dev->dev.platform_data; + pdata->on = mdp_on; + pdata->off = mdp_off; + pdata->next = pdev; + + switch (mfd->panel.type) { + case EXT_MDDI_PANEL: + case MDDI_PANEL: + case EBI2_PANEL: + INIT_WORK(&mfd->dma_update_worker, + mdp_lcd_update_workqueue_handler); + INIT_WORK(&mfd->vsync_resync_worker, + mdp_vsync_resync_workqueue_handler); + mfd->hw_refresh = FALSE; + + if (mfd->panel.type == EXT_MDDI_PANEL) { + /* 15 fps -> 66 msec */ + mfd->refresh_timer_duration = (66 * HZ / 1000); + } else { + /* 24 fps -> 42 msec */ + mfd->refresh_timer_duration = (42 * HZ / 1000); + } + +#ifdef CONFIG_FB_MSM_MDP22 + mfd->dma_fnc = mdp_dma2_update; + mfd->dma = &dma2_data; +#else + if (mfd->panel_info.pdest == DISPLAY_1) { +#ifdef CONFIG_FB_MSM_OVERLAY + mfd->dma_fnc = mdp4_mddi_overlay; +#else + mfd->dma_fnc = mdp_dma2_update; +#endif + mfd->dma = &dma2_data; + mfd->lut_update = mdp_lut_update_nonlcdc; + mfd->do_histogram = mdp_do_histogram; + } else { + mfd->dma_fnc = mdp_dma_s_update; + mfd->dma = &dma_s_data; + } +#endif + if (mdp_pdata) + mfd->vsync_gpio = mdp_pdata->gpio; + else + mfd->vsync_gpio = -1; + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == EBI2_PANEL) + intf = EBI2_INTF; + else + intf = MDDI_INTF; + + if (mfd->panel_info.pdest == DISPLAY_1) + if_no = PRIMARY_INTF_SEL; + else + if_no = SECONDARY_INTF_SEL; + + mdp4_display_intf_sel(if_no, intf); +#endif + mdp_config_vsync(mfd); + break; + + case HDMI_PANEL: + case LCDC_PANEL: + pdata->on = mdp_lcdc_on; + pdata->off = mdp_lcdc_off; + mfd->hw_refresh = TRUE; + mfd->cursor_update = mdp_hw_cursor_update; +#ifndef CONFIG_FB_MSM_MDP22 + mfd->lut_update = mdp_lut_update_lcdc; + mfd->do_histogram = mdp_do_histogram; +#endif +#ifdef CONFIG_FB_MSM_OVERLAY + mfd->dma_fnc = mdp4_lcdc_overlay; +#else + mfd->dma_fnc = mdp_lcdc_update; +#endif + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == HDMI_PANEL) { + mfd->dma = &dma_e_data; + mdp4_display_intf_sel(EXTERNAL_INTF_SEL, LCDC_RGB_INTF); + } else { + mfd->dma = &dma2_data; + mdp4_display_intf_sel(PRIMARY_INTF_SEL, LCDC_RGB_INTF); + } +#else + mfd->dma = &dma2_data; + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_intr_mask &= ~MDP_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); +#endif + break; + + case TV_PANEL: + pdata->on = mdp_dma3_on; + pdata->off = mdp_dma3_off; + mfd->hw_refresh = TRUE; + mfd->dma_fnc = mdp_dma3_update; + mfd->dma = &dma3_data; + break; + + default: + printk(KERN_ERR "mdp_probe: unknown device type!\n"); + rc = -ENODEV; + goto mdp_probe_err; + } + + /* set driver data */ + platform_set_drvdata(msm_fb_dev, mfd); + + rc = platform_device_add(msm_fb_dev); + if (rc) { + goto mdp_probe_err; + } + + pdev_list[pdev_list_cnt++] = pdev; + return 0; + + mdp_probe_err: + platform_device_put(msm_fb_dev); + return rc; +} + +static void mdp_suspend_sub(void) +{ + /* cancel pipe ctrl worker */ + cancel_delayed_work(&mdp_pipe_ctrl_worker); + + /* for workder can't be cancelled... */ + flush_workqueue(mdp_pipe_ctrl_wq); + + /* let's wait for PPP completion */ + while (mdp_block_power_cnt[MDP_PPP_BLOCK] > 0) ; + + /* try to power down */ + mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int mdp_suspend(struct platform_device *pdev, pm_message_t state) +{ + mdp_suspend_sub(); + return 0; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mdp_early_suspend(struct early_suspend *h) +{ + mdp_suspend_sub(); +} +#endif + +static int mdp_remove(struct platform_device *pdev) +{ + iounmap(msm_mdp_base); + return 0; +} + +static int mdp_register_driver(void) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1; + early_suspend.suspend = mdp_early_suspend; + register_early_suspend(&early_suspend); +#endif + + return platform_driver_register(&mdp_driver); +} + +static int __init mdp_driver_init(void) +{ + int ret; + + mdp_drv_init(); + + ret = mdp_register_driver(); + if (ret) { + printk(KERN_ERR "mdp_register_driver() failed!\n"); + return ret; + } + +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_FB_MSM_MDP40) + mdp4_debugfs_init(); +#endif + + return 0; + +} + +module_init(mdp_driver_init); diff --git a/drivers/staging/msm/mdp.h b/drivers/staging/msm/mdp.h new file mode 100644 index 000000000000..0a5d6ac386ac --- /dev/null +++ b/drivers/staging/msm/mdp.h @@ -0,0 +1,695 @@ +/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * + */ + +#ifndef MDP_H +#define MDP_H + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/hrtimer.h> +#include "msm_mdp.h" + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> + +#include "msm_fb_panel.h" + +#ifdef CONFIG_MDP_PPP_ASYNC_OP +#include "mdp_ppp_dq.h" +#endif + +#ifdef BIT +#undef BIT +#endif + +#define BIT(x) (1<<(x)) + +#define MDPOP_NOP 0 +#define MDPOP_LR BIT(0) /* left to right flip */ +#define MDPOP_UD BIT(1) /* up and down flip */ +#define MDPOP_ROT90 BIT(2) /* rotate image to 90 degree */ +#define MDPOP_ROT180 (MDPOP_UD|MDPOP_LR) +#define MDPOP_ROT270 (MDPOP_ROT90|MDPOP_UD|MDPOP_LR) +#define MDPOP_ASCALE BIT(7) +#define MDPOP_ALPHAB BIT(8) /* enable alpha blending */ +#define MDPOP_TRANSP BIT(9) /* enable transparency */ +#define MDPOP_DITHER BIT(10) /* enable dither */ +#define MDPOP_SHARPENING BIT(11) /* enable sharpening */ +#define MDPOP_BLUR BIT(12) /* enable blur */ +#define MDPOP_FG_PM_ALPHA BIT(13) + +struct mdp_table_entry { + uint32_t reg; + uint32_t val; +}; + +extern struct mdp_ccs mdp_ccs_yuv2rgb ; +extern struct mdp_ccs mdp_ccs_rgb2yuv ; + +/* + * MDP Image Structure + */ +typedef struct mdpImg_ { + uint32 imgType; /* Image type */ + uint32 *bmy_addr; /* bitmap or y addr */ + uint32 *cbcr_addr; /* cbcr addr */ + uint32 width; /* image width */ + uint32 mdpOp; /* image opertion (rotation,flip up/down, alpha/tp) */ + uint32 tpVal; /* transparency color */ + uint32 alpha; /* alpha percentage 0%(0x0) ~ 100%(0x100) */ + int sp_value; /* sharpening strength */ +} MDPIMG; + +#ifdef CONFIG_MDP_PPP_ASYNC_OP +#define MDP_OUTP(addr, data) mdp_ppp_outdw((uint32_t)(addr), \ + (uint32_t)(data)) +#else +#define MDP_OUTP(addr, data) outpdw((addr), (data)) +#endif + +#define MDP_KTIME2USEC(kt) (kt.tv.sec*1000000 + kt.tv.nsec/1000) + +#define MDP_BASE msm_mdp_base + +typedef enum { + MDP_BC_SCALE_POINT2_POINT4, + MDP_BC_SCALE_POINT4_POINT6, + MDP_BC_SCALE_POINT6_POINT8, + MDP_BC_SCALE_POINT8_1, + MDP_BC_SCALE_UP, + MDP_PR_SCALE_POINT2_POINT4, + MDP_PR_SCALE_POINT4_POINT6, + MDP_PR_SCALE_POINT6_POINT8, + MDP_PR_SCALE_POINT8_1, + MDP_PR_SCALE_UP, + MDP_SCALE_BLUR, + MDP_INIT_SCALE +} MDP_SCALE_MODE; + +typedef enum { + MDP_BLOCK_POWER_OFF, + MDP_BLOCK_POWER_ON +} MDP_BLOCK_POWER_STATE; + +typedef enum { + MDP_MASTER_BLOCK, + MDP_CMD_BLOCK, + MDP_PPP_BLOCK, + MDP_DMA2_BLOCK, + MDP_DMA3_BLOCK, + MDP_DMA_S_BLOCK, + MDP_DMA_E_BLOCK, + MDP_OVERLAY0_BLOCK, + MDP_OVERLAY1_BLOCK, + MDP_MAX_BLOCK +} MDP_BLOCK_TYPE; + +/* Let's keep Q Factor power of 2 for optimization */ +#define MDP_SCALE_Q_FACTOR 512 + +#ifdef CONFIG_FB_MSM_MDP31 +#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*8) +#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/8) +#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*8) +#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/8) +#else +#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4) +#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4) +#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4) +#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4) +#endif + +/* SHIM Q Factor */ +#define PHI_Q_FACTOR 29 +#define PQF_PLUS_5 (PHI_Q_FACTOR + 5) /* due to 32 phases */ +#define PQF_PLUS_4 (PHI_Q_FACTOR + 4) +#define PQF_PLUS_2 (PHI_Q_FACTOR + 2) /* to get 4.0 */ +#define PQF_MINUS_2 (PHI_Q_FACTOR - 2) /* to get 0.25 */ +#define PQF_PLUS_5_PLUS_2 (PQF_PLUS_5 + 2) +#define PQF_PLUS_5_MINUS_2 (PQF_PLUS_5 - 2) + +#define MDP_CONVTP(tpVal) (((tpVal&0xF800)<<8)|((tpVal&0x7E0)<<5)|((tpVal&0x1F)<<3)) + +#define MDPOP_ROTATION (MDPOP_ROT90|MDPOP_LR|MDPOP_UD) +#define MDP_CHKBIT(val, bit) ((bit) == ((val) & (bit))) + +/* overlay interface API defines */ +typedef enum { + MORE_IBUF, + FINAL_IBUF, + COMPLETE_IBUF +} MDP_IBUF_STATE; + +struct mdp_dirty_region { + __u32 xoffset; /* source origin in the x-axis */ + __u32 yoffset; /* source origin in the y-axis */ + __u32 width; /* number of pixels in the x-axis */ + __u32 height; /* number of pixels in the y-axis */ +}; + +/* + * MDP extended data types + */ +typedef struct mdp_roi_s { + uint32 x; + uint32 y; + uint32 width; + uint32 height; + int32 lcd_x; + int32 lcd_y; + uint32 dst_width; + uint32 dst_height; +} MDP_ROI; + +typedef struct mdp_ibuf_s { + uint8 *buf; + uint32 bpp; + uint32 ibuf_type; + uint32 ibuf_width; + uint32 ibuf_height; + + MDP_ROI roi; + MDPIMG mdpImg; + + int32 dma_x; + int32 dma_y; + uint32 dma_w; + uint32 dma_h; + + uint32 vsync_enable; + uint32 visible_swapped; +} MDPIBUF; + +struct mdp_dma_data { + boolean busy; + boolean waiting; + struct mutex ov_mutex; + struct semaphore mutex; + struct completion comp; +}; + +#define MDP_CMD_DEBUG_ACCESS_BASE (MDP_BASE+0x10000) + +#define MDP_DMA2_TERM 0x1 +#define MDP_DMA3_TERM 0x2 +#define MDP_PPP_TERM 0x4 +#define MDP_DMA_S_TERM 0x8 +#ifdef CONFIG_FB_MSM_MDP40 +#define MDP_DMA_E_TERM 0x10 +#define MDP_OVERLAY0_TERM 0x20 +#define MDP_OVERLAY1_TERM 0x40 +#endif + +#define ACTIVE_START_X_EN BIT(31) +#define ACTIVE_START_Y_EN BIT(31) +#define ACTIVE_HIGH 0 +#define ACTIVE_LOW 1 +#define MDP_DMA_S_DONE BIT(2) +#define LCDC_FRAME_START BIT(15) +#define LCDC_UNDERFLOW BIT(16) + +#ifdef CONFIG_FB_MSM_MDP22 +#define MDP_DMA_P_DONE BIT(2) +#else +#define MDP_DMA_P_DONE BIT(14) +#endif + +#define MDP_PPP_DONE BIT(0) +#define TV_OUT_DMA3_DONE BIT(6) +#define TV_ENC_UNDERRUN BIT(7) +#define TV_OUT_DMA3_START BIT(13) +#define MDP_HIST_DONE BIT(20) + +#ifdef CONFIG_FB_MSM_MDP22 +#define MDP_ANY_INTR_MASK (MDP_PPP_DONE| \ + MDP_DMA_P_DONE| \ + TV_ENC_UNDERRUN) +#else +#define MDP_ANY_INTR_MASK (MDP_PPP_DONE| \ + MDP_DMA_P_DONE| \ + MDP_DMA_S_DONE| \ + LCDC_UNDERFLOW| \ + MDP_HIST_DONE| \ + TV_ENC_UNDERRUN) +#endif + +#define MDP_TOP_LUMA 16 +#define MDP_TOP_CHROMA 0 +#define MDP_BOTTOM_LUMA 19 +#define MDP_BOTTOM_CHROMA 3 +#define MDP_LEFT_LUMA 22 +#define MDP_LEFT_CHROMA 6 +#define MDP_RIGHT_LUMA 25 +#define MDP_RIGHT_CHROMA 9 + +#define CLR_G 0x0 +#define CLR_B 0x1 +#define CLR_R 0x2 +#define CLR_ALPHA 0x3 + +#define CLR_Y CLR_G +#define CLR_CB CLR_B +#define CLR_CR CLR_R + +/* from lsb to msb */ +#define MDP_GET_PACK_PATTERN(a,x,y,z,bit) (((a)<<(bit*3))|((x)<<(bit*2))|((y)<<bit)|(z)) + +/* + * 0x0000 0x0004 0x0008 MDP sync config + */ +#ifdef CONFIG_FB_MSM_MDP22 +#define MDP_SYNCFG_HGT_LOC 22 +#define MDP_SYNCFG_VSYNC_EXT_EN BIT(21) +#define MDP_SYNCFG_VSYNC_INT_EN BIT(20) +#else +#define MDP_SYNCFG_HGT_LOC 21 +#define MDP_SYNCFG_VSYNC_EXT_EN BIT(20) +#define MDP_SYNCFG_VSYNC_INT_EN BIT(19) +#define MDP_HW_VSYNC +#endif + +/* + * 0x0018 MDP VSYNC THREASH + */ +#define MDP_PRIM_BELOW_LOC 0 +#define MDP_PRIM_ABOVE_LOC 8 + +/* + * MDP_PRIMARY_VSYNC_OUT_CTRL + * 0x0080,84,88 internal vsync pulse config + */ +#define VSYNC_PULSE_EN BIT(31) +#define VSYNC_PULSE_INV BIT(30) + +/* + * 0x008c MDP VSYNC CONTROL + */ +#define DISP0_VSYNC_MAP_VSYNC0 0 +#define DISP0_VSYNC_MAP_VSYNC1 BIT(0) +#define DISP0_VSYNC_MAP_VSYNC2 BIT(0)|BIT(1) + +#define DISP1_VSYNC_MAP_VSYNC0 0 +#define DISP1_VSYNC_MAP_VSYNC1 BIT(2) +#define DISP1_VSYNC_MAP_VSYNC2 BIT(2)|BIT(3) + +#define PRIMARY_LCD_SYNC_EN BIT(4) +#define PRIMARY_LCD_SYNC_DISABLE 0 + +#define SECONDARY_LCD_SYNC_EN BIT(5) +#define SECONDARY_LCD_SYNC_DISABLE 0 + +#define EXTERNAL_LCD_SYNC_EN BIT(6) +#define EXTERNAL_LCD_SYNC_DISABLE 0 + +/* + * 0x101f0 MDP VSYNC Threshold + */ +#define VSYNC_THRESHOLD_ABOVE_LOC 0 +#define VSYNC_THRESHOLD_BELOW_LOC 16 +#define VSYNC_ANTI_TEAR_EN BIT(31) + +/* + * 0x10004 command config + */ +#define MDP_CMD_DBGBUS_EN BIT(0) + +/* + * 0x10124 or 0x101d4PPP source config + */ +#define PPP_SRC_C0G_8BITS (BIT(1)|BIT(0)) +#define PPP_SRC_C1B_8BITS (BIT(3)|BIT(2)) +#define PPP_SRC_C2R_8BITS (BIT(5)|BIT(4)) +#define PPP_SRC_C3A_8BITS (BIT(7)|BIT(6)) + +#define PPP_SRC_C0G_6BITS BIT(1) +#define PPP_SRC_C1B_6BITS BIT(3) +#define PPP_SRC_C2R_6BITS BIT(5) + +#define PPP_SRC_C0G_5BITS BIT(0) +#define PPP_SRC_C1B_5BITS BIT(2) +#define PPP_SRC_C2R_5BITS BIT(4) + +#define PPP_SRC_C3_ALPHA_EN BIT(8) + +#define PPP_SRC_BPP_INTERLVD_1BYTES 0 +#define PPP_SRC_BPP_INTERLVD_2BYTES BIT(9) +#define PPP_SRC_BPP_INTERLVD_3BYTES BIT(10) +#define PPP_SRC_BPP_INTERLVD_4BYTES (BIT(10)|BIT(9)) + +#define PPP_SRC_BPP_ROI_ODD_X BIT(11) +#define PPP_SRC_BPP_ROI_ODD_Y BIT(12) +#define PPP_SRC_INTERLVD_2COMPONENTS BIT(13) +#define PPP_SRC_INTERLVD_3COMPONENTS BIT(14) +#define PPP_SRC_INTERLVD_4COMPONENTS (BIT(14)|BIT(13)) + +/* + * RGB666 unpack format + * TIGHT means R6+G6+B6 together + * LOOSE means R6+2 +G6+2+ B6+2 (with MSB) + * or 2+R6 +2+G6 +2+B6 (with LSB) + */ +#define PPP_SRC_UNPACK_TIGHT BIT(17) +#define PPP_SRC_UNPACK_LOOSE 0 +#define PPP_SRC_UNPACK_ALIGN_LSB 0 +#define PPP_SRC_UNPACK_ALIGN_MSB BIT(18) + +#define PPP_SRC_FETCH_PLANES_INTERLVD 0 +#define PPP_SRC_FETCH_PLANES_PSEUDOPLNR BIT(20) + +#define PPP_SRC_WMV9_MODE BIT(21) /* window media version 9 */ + +/* + * 0x10138 PPP operation config + */ +#define PPP_OP_SCALE_X_ON BIT(0) +#define PPP_OP_SCALE_Y_ON BIT(1) + +#define PPP_OP_CONVERT_RGB2YCBCR 0 +#define PPP_OP_CONVERT_YCBCR2RGB BIT(2) +#define PPP_OP_CONVERT_ON BIT(3) + +#define PPP_OP_CONVERT_MATRIX_PRIMARY 0 +#define PPP_OP_CONVERT_MATRIX_SECONDARY BIT(4) + +#define PPP_OP_LUT_C0_ON BIT(5) +#define PPP_OP_LUT_C1_ON BIT(6) +#define PPP_OP_LUT_C2_ON BIT(7) + +/* rotate or blend enable */ +#define PPP_OP_ROT_ON BIT(8) + +#define PPP_OP_ROT_90 BIT(9) +#define PPP_OP_FLIP_LR BIT(10) +#define PPP_OP_FLIP_UD BIT(11) + +#define PPP_OP_BLEND_ON BIT(12) + +#define PPP_OP_BLEND_SRCPIXEL_ALPHA 0 +#define PPP_OP_BLEND_DSTPIXEL_ALPHA BIT(13) +#define PPP_OP_BLEND_CONSTANT_ALPHA BIT(14) +#define PPP_OP_BLEND_SRCPIXEL_TRANSP (BIT(13)|BIT(14)) + +#define PPP_OP_BLEND_ALPHA_BLEND_NORMAL 0 +#define PPP_OP_BLEND_ALPHA_BLEND_REVERSE BIT(15) + +#define PPP_OP_DITHER_EN BIT(16) + +#define PPP_OP_COLOR_SPACE_RGB 0 +#define PPP_OP_COLOR_SPACE_YCBCR BIT(17) + +#define PPP_OP_SRC_CHROMA_RGB 0 +#define PPP_OP_SRC_CHROMA_H2V1 BIT(18) +#define PPP_OP_SRC_CHROMA_H1V2 BIT(19) +#define PPP_OP_SRC_CHROMA_420 (BIT(18)|BIT(19)) +#define PPP_OP_SRC_CHROMA_COSITE 0 +#define PPP_OP_SRC_CHROMA_OFFSITE BIT(20) + +#define PPP_OP_DST_CHROMA_RGB 0 +#define PPP_OP_DST_CHROMA_H2V1 BIT(21) +#define PPP_OP_DST_CHROMA_H1V2 BIT(22) +#define PPP_OP_DST_CHROMA_420 (BIT(21)|BIT(22)) +#define PPP_OP_DST_CHROMA_COSITE 0 +#define PPP_OP_DST_CHROMA_OFFSITE BIT(23) + +#define PPP_BLEND_CALPHA_TRNASP BIT(24) + +#define PPP_OP_BG_CHROMA_RGB 0 +#define PPP_OP_BG_CHROMA_H2V1 BIT(25) +#define PPP_OP_BG_CHROMA_H1V2 BIT(26) +#define PPP_OP_BG_CHROMA_420 BIT(25)|BIT(26) +#define PPP_OP_BG_CHROMA_SITE_COSITE 0 +#define PPP_OP_BG_CHROMA_SITE_OFFSITE BIT(27) +#define PPP_OP_DEINT_EN BIT(29) + +#define PPP_BLEND_BG_USE_ALPHA_SEL (1 << 0) +#define PPP_BLEND_BG_ALPHA_REVERSE (1 << 3) +#define PPP_BLEND_BG_SRCPIXEL_ALPHA (0 << 1) +#define PPP_BLEND_BG_DSTPIXEL_ALPHA (1 << 1) +#define PPP_BLEND_BG_CONSTANT_ALPHA (2 << 1) +#define PPP_BLEND_BG_CONST_ALPHA_VAL(x) ((x) << 24) + +#define PPP_OP_DST_RGB 0 +#define PPP_OP_DST_YCBCR BIT(30) +/* + * 0x10150 PPP destination config + */ +#define PPP_DST_C0G_8BIT (BIT(0)|BIT(1)) +#define PPP_DST_C1B_8BIT (BIT(3)|BIT(2)) +#define PPP_DST_C2R_8BIT (BIT(5)|BIT(4)) +#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6)) + +#define PPP_DST_C0G_6BIT BIT(1) +#define PPP_DST_C1B_6BIT BIT(3) +#define PPP_DST_C2R_6BIT BIT(5) + +#define PPP_DST_C0G_5BIT BIT(0) +#define PPP_DST_C1B_5BIT BIT(2) +#define PPP_DST_C2R_5BIT BIT(4) + +#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6)) +#define PPP_DST_C3ALPHA_EN BIT(8) + +#define PPP_DST_PACKET_CNT_INTERLVD_2ELEM BIT(9) +#define PPP_DST_PACKET_CNT_INTERLVD_3ELEM BIT(10) +#define PPP_DST_PACKET_CNT_INTERLVD_4ELEM (BIT(10)|BIT(9)) +#define PPP_DST_PACKET_CNT_INTERLVD_6ELEM (BIT(11)|BIT(9)) + +#define PPP_DST_PACK_LOOSE 0 +#define PPP_DST_PACK_TIGHT BIT(13) +#define PPP_DST_PACK_ALIGN_LSB 0 +#define PPP_DST_PACK_ALIGN_MSB BIT(14) + +#define PPP_DST_OUT_SEL_AXI 0 +#define PPP_DST_OUT_SEL_MDDI BIT(15) + +#define PPP_DST_BPP_2BYTES BIT(16) +#define PPP_DST_BPP_3BYTES BIT(17) +#define PPP_DST_BPP_4BYTES (BIT(17)|BIT(16)) + +#define PPP_DST_PLANE_INTERLVD 0 +#define PPP_DST_PLANE_PLANAR BIT(18) +#define PPP_DST_PLANE_PSEUDOPLN BIT(19) + +#define PPP_DST_TO_TV BIT(20) + +#define PPP_DST_MDDI_PRIMARY 0 +#define PPP_DST_MDDI_SECONDARY BIT(21) +#define PPP_DST_MDDI_EXTERNAL BIT(22) + +/* + * 0x10180 DMA config + */ +#define DMA_DSTC0G_8BITS (BIT(1)|BIT(0)) +#define DMA_DSTC1B_8BITS (BIT(3)|BIT(2)) +#define DMA_DSTC2R_8BITS (BIT(5)|BIT(4)) + +#define DMA_DSTC0G_6BITS BIT(1) +#define DMA_DSTC1B_6BITS BIT(3) +#define DMA_DSTC2R_6BITS BIT(5) + +#define DMA_DSTC0G_5BITS BIT(0) +#define DMA_DSTC1B_5BITS BIT(2) +#define DMA_DSTC2R_5BITS BIT(4) + +#define DMA_PACK_TIGHT BIT(6) +#define DMA_PACK_LOOSE 0 +#define DMA_PACK_ALIGN_LSB 0 +/* + * use DMA_PACK_ALIGN_MSB if the upper 6 bits from 8 bits output + * from LCDC block maps into 6 pins out to the panel + */ +#define DMA_PACK_ALIGN_MSB BIT(7) +#define DMA_PACK_PATTERN_RGB \ + (MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 2)<<8) +#define DMA_PACK_PATTERN_BGR \ + (MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 2)<<8) +#define DMA_OUT_SEL_AHB 0 +#define DMA_OUT_SEL_LCDC BIT(20) +#define DMA_IBUF_FORMAT_RGB888 0 +#define DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888 BIT(26) + +#ifdef CONFIG_FB_MSM_MDP22 +#define DMA_OUT_SEL_MDDI BIT(14) +#define DMA_AHBM_LCD_SEL_PRIMARY 0 +#define DMA_AHBM_LCD_SEL_SECONDARY BIT(15) +#define DMA_IBUF_C3ALPHA_EN BIT(16) +#define DMA_DITHER_EN BIT(17) +#define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY 0 +#define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY BIT(18) +#define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL BIT(19) +#define DMA_IBUF_FORMAT_RGB565 BIT(20) +#define DMA_IBUF_FORMAT_RGB888_OR_ARGB8888 0 +#define DMA_IBUF_NONCONTIGUOUS BIT(21) +#else +#define DMA_OUT_SEL_MDDI BIT(19) +#define DMA_AHBM_LCD_SEL_PRIMARY 0 +#define DMA_AHBM_LCD_SEL_SECONDARY 0 +#define DMA_IBUF_C3ALPHA_EN 0 +#define DMA_DITHER_EN BIT(24) +#define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY 0 +#define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY 0 +#define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL 0 +#define DMA_IBUF_FORMAT_RGB565 BIT(25) +#define DMA_IBUF_NONCONTIGUOUS 0 +#endif + +/* + * MDDI Register + */ +#define MDDI_VDO_PACKET_DESC 0x5666 + +#ifdef CONFIG_FB_MSM_MDP40 +#define MDP_INTR_ENABLE (msm_mdp_base + 0x0050) +#define MDP_INTR_STATUS (msm_mdp_base + 0x0054) +#define MDP_INTR_CLEAR (msm_mdp_base + 0x0058) +#define MDP_EBI2_LCD0 (msm_mdp_base + 0x0060) +#define MDP_EBI2_LCD1 (msm_mdp_base + 0x0064) +#define MDP_EBI2_PORTMAP_MODE (msm_mdp_base + 0x0070) + +#define MDP_DMA_P_HIST_INTR_STATUS (msm_mdp_base + 0x95014) +#define MDP_DMA_P_HIST_INTR_CLEAR (msm_mdp_base + 0x95018) +#define MDP_DMA_P_HIST_INTR_ENABLE (msm_mdp_base + 0x9501C) +#else +#define MDP_INTR_ENABLE (msm_mdp_base + 0x0020) +#define MDP_INTR_STATUS (msm_mdp_base + 0x0024) +#define MDP_INTR_CLEAR (msm_mdp_base + 0x0028) +#define MDP_EBI2_LCD0 (msm_mdp_base + 0x003c) +#define MDP_EBI2_LCD1 (msm_mdp_base + 0x0040) +#define MDP_EBI2_PORTMAP_MODE (msm_mdp_base + 0x005c) +#endif + +#define MDP_FULL_BYPASS_WORD43 (msm_mdp_base + 0x101ac) + +#define MDP_CSC_PFMVn(n) (msm_mdp_base + 0x40400 + 4 * (n)) +#define MDP_CSC_PRMVn(n) (msm_mdp_base + 0x40440 + 4 * (n)) +#define MDP_CSC_PRE_BV1n(n) (msm_mdp_base + 0x40500 + 4 * (n)) +#define MDP_CSC_PRE_BV2n(n) (msm_mdp_base + 0x40540 + 4 * (n)) +#define MDP_CSC_POST_BV1n(n) (msm_mdp_base + 0x40580 + 4 * (n)) +#define MDP_CSC_POST_BV2n(n) (msm_mdp_base + 0x405c0 + 4 * (n)) + +#ifdef CONFIG_FB_MSM_MDP31 +#define MDP_CSC_PRE_LV1n(n) (msm_mdp_base + 0x40600 + 4 * (n)) +#define MDP_CSC_PRE_LV2n(n) (msm_mdp_base + 0x40640 + 4 * (n)) +#define MDP_CSC_POST_LV1n(n) (msm_mdp_base + 0x40680 + 4 * (n)) +#define MDP_CSC_POST_LV2n(n) (msm_mdp_base + 0x406c0 + 4 * (n)) +#define MDP_PPP_SCALE_COEFF_LSBn(n) (msm_mdp_base + 0x50400 + 8 * (n)) +#define MDP_PPP_SCALE_COEFF_MSBn(n) (msm_mdp_base + 0x50404 + 8 * (n)) + +#define SCALE_D0_SET 0 +#define SCALE_D1_SET BIT(0) +#define SCALE_D2_SET BIT(1) +#define SCALE_U1_SET (BIT(0)|BIT(1)) + +#else +#define MDP_CSC_PRE_LV1n(n) (msm_mdp_base + 0x40580 + 4 * (n)) +#endif + +#define MDP_CURSOR_WIDTH 64 +#define MDP_CURSOR_HEIGHT 64 +#define MDP_CURSOR_SIZE (MDP_CURSOR_WIDTH*MDP_CURSOR_WIDTH*4) + +#define MDP_DMA_P_LUT_C0_EN BIT(0) +#define MDP_DMA_P_LUT_C1_EN BIT(1) +#define MDP_DMA_P_LUT_C2_EN BIT(2) +#define MDP_DMA_P_LUT_POST BIT(4) + +void mdp_hw_init(void); +int mdp_ppp_pipe_wait(void); +void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd); +void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state, + boolean isr); +void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty, + boolean sync); +void mdp_dma_pan_update(struct fb_info *info); +void mdp_refresh_screen(unsigned long data); +int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req, + struct file **pp_src, struct file **pp_dest); +void mdp_lcd_update_workqueue_handler(struct work_struct *work); +void mdp_vsync_resync_workqueue_handler(struct work_struct *work); +void mdp_dma2_update(struct msm_fb_data_type *mfd); +void mdp_config_vsync(struct msm_fb_data_type *); +uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd); +enum hrtimer_restart mdp_dma2_vsync_hrtimer_handler(struct hrtimer *ht); +void mdp_set_scale(MDPIBUF *iBuf, + uint32 dst_roi_width, + uint32 dst_roi_height, + boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr); +void mdp_init_scale_table(void); +void mdp_adjust_start_addr(uint8 **src0, + uint8 **src1, + int v_slice, + int h_slice, + int x, + int y, + uint32 width, + uint32 height, int bpp, MDPIBUF *iBuf, int layer); +void mdp_set_blend_attr(MDPIBUF *iBuf, + uint32 *alpha, + uint32 *tpVal, + uint32 perPixelAlpha, uint32 *pppop_reg_ptr); + +int mdp_dma3_on(struct platform_device *pdev); +int mdp_dma3_off(struct platform_device *pdev); +void mdp_dma3_update(struct msm_fb_data_type *mfd); + +int mdp_lcdc_on(struct platform_device *pdev); +int mdp_lcdc_off(struct platform_device *pdev); +void mdp_lcdc_update(struct msm_fb_data_type *mfd); +int mdp_hw_cursor_update(struct fb_info *info, struct fb_cursor *cursor); +void mdp_enable_irq(uint32 term); +void mdp_disable_irq(uint32 term); +void mdp_disable_irq_nolock(uint32 term); +uint32_t mdp_get_bytes_per_pixel(uint32_t format); + +#ifdef MDP_HW_VSYNC +void mdp_hw_vsync_clk_enable(struct msm_fb_data_type *mfd); +void mdp_hw_vsync_clk_disable(struct msm_fb_data_type *mfd); +#endif + +void mdp_dma_s_update(struct msm_fb_data_type *mfd); + +/* Added to support flipping */ +void mdp_set_offset_info(struct fb_info *info, uint32 address, uint32 interval); + +int get_gem_img(struct mdp_img *img, unsigned long *start, + unsigned long *len); +int get_img(struct mdp_img *img, struct fb_info *info, + unsigned long *start, unsigned long *len, + struct file **pp_file); + + +/*int get_img(struct msmfb_data *img, struct fb_info *info, + unsigned long *start, unsigned long *len, struct file **pp_file);*/ +#endif /* MDP_H */ diff --git a/drivers/staging/msm/mdp4.h b/drivers/staging/msm/mdp4.h new file mode 100644 index 000000000000..26ec8f12cf64 --- /dev/null +++ b/drivers/staging/msm/mdp4.h @@ -0,0 +1,352 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * + */ + +#ifndef MDP4_H +#define MDP4_H + +extern struct mdp_dma_data dma2_data; +extern struct mdp_dma_data dma_s_data; +extern struct mdp_dma_data dma_e_data; +extern struct mdp_histogram mdp_hist; +extern struct completion mdp_hist_comp; +extern boolean mdp_is_in_isr; +extern uint32 mdp_intr_mask; +extern spinlock_t mdp_spin_lock; + + +#define MDP4_NONBLOCKING /* enable non blocking ioctl */ + +#define MDP4_OVERLAYPROC0_BASE 0x10000 +#define MDP4_OVERLAYPROC1_BASE 0x18000 + +#define MDP4_VIDEO_BASE 0x20000 +#define MDP4_VIDEO_OFF 0x10000 + +#define MDP4_RGB_BASE 0x40000 +#define MDP4_RGB_OFF 0x10000 + +enum { /* display */ + PRIMARY_INTF_SEL, + SECONDARY_INTF_SEL, + EXTERNAL_INTF_SEL +}; + +enum { + LCDC_RGB_INTF, + DTV_INTF = LCDC_RGB_INTF, + MDDI_LCDC_INTF, + MDDI_INTF, + EBI2_INTF +}; + +enum { + MDDI_PRIMARY_SET, + MDDI_SECONDARY_SET, + MDDI_EXTERNAL_SET +}; + +enum { + EBI2_LCD0, + EBI2_LCD1 +}; + +enum { + OVERLAY_MODE_NONE, + OVERLAY_MODE_BLT +}; + +enum { + OVERLAY_REFRESH_ON_DEMAND, + OVERLAY_REFRESH_VSYNC, + OVERLAY_REFRESH_VSYNC_HALF, + OVERLAY_REFRESH_VSYNC_QUARTER +}; + +enum { + OVERLAY_FRAMEBUF, + OVERLAY_DIRECTOUT +}; + +/* system interrupts */ +#define INTR_OVERLAY0_DONE BIT(0) +#define INTR_OVERLAY1_DONE BIT(1) +#define INTR_DMA_S_DONE BIT(2) +#define INTR_DMA_E_DONE BIT(3) +#define INTR_DMA_P_DONE BIT(4) +#define INTR_VG1_HISTOGRAM BIT(5) +#define INTR_VG2_HISTOGRAM BIT(6) +#define INTR_PRIMARY_VSYNC BIT(7) +#define INTR_PRIMARY_INTF_UDERRUN BIT(8) +#define INTR_EXTERNAL_VSYNC BIT(9) +#define INTR_EXTERNAL_INTF_UDERRUN BIT(10) +#define INTR_DMA_P_HISTOGRAM BIT(17) + +/* histogram interrupts */ +#define INTR_HIST_DONE BIT(0) +#define INTR_HIST_RESET_SEQ_DONE BIT(1) + + +#ifdef CONFIG_FB_MSM_OVERLAY +#define MDP4_ANY_INTR_MASK (INTR_OVERLAY0_DONE) +#else +#define MDP4_ANY_INTR_MASK (INTR_DMA_P_DONE) +#endif + +enum { + OVERLAY_PIPE_RGB1, + OVERLAY_PIPE_RGB2, +}; + +enum { + OVERLAY_PIPE_VG1, /* video/graphic */ + OVERLAY_PIPE_VG2 +}; + +enum { + OVERLAY_TYPE_RGB, + OVERLAY_TYPE_VG /* video/graphic */ +}; + +enum { + MDP4_MIXER0, + MDP4_MIXER1 +}; + +#define MDP4_MAX_MIXER 2 + +enum { + OVERLAY_PLANE_INTERLEAVED, + OVERLAY_PLANE_PLANAR, + OVERLAY_PLANE_PSEUDO_PLANAR +}; + +enum { + MDP4_MIXER_STAGE_UNUNSED, /* pipe not used */ + MDP4_MIXER_STAGE_BASE, + MDP4_MIXER_STAGE0, /* zorder 0 */ + MDP4_MIXER_STAGE1, /* zorder 1 */ + MDP4_MIXER_STAGE2 /* zorder 2 */ +}; + +#define MDP4_MAX_STAGE 4 + +enum { + MDP4_FRAME_FORMAT_LINEAR, + MDP4_FRAME_FORMAT_ARGB_TILE, + MDP4_FRAME_FORMAT_VIDEO_SUPERTILE +}; + +enum { + MDP4_CHROMA_RGB, + MDP4_CHROMA_H2V1, + MDP4_CHROMA_H1V2, + MDP4_CHROMA_420 +}; + +#define MDP4_BLEND_BG_TRANSP_EN BIT(9) +#define MDP4_BLEND_FG_TRANSP_EN BIT(8) +#define MDP4_BLEND_BG_MOD_ALPHA BIT(7) +#define MDP4_BLEND_BG_INV_ALPHA BIT(6) +#define MDP4_BLEND_BG_ALPHA_FG_CONST (0 << 4) +#define MDP4_BLEND_BG_ALPHA_BG_CONST (1 << 4) +#define MDP4_BLEND_BG_ALPHA_FG_PIXEL (2 << 4) +#define MDP4_BLEND_BG_ALPHA_BG_PIXEL (3 << 4) +#define MDP4_BLEND_FG_MOD_ALPHA BIT(3) +#define MDP4_BLEND_FG_INV_ALPHA BIT(2) +#define MDP4_BLEND_FG_ALPHA_FG_CONST (0 << 0) +#define MDP4_BLEND_FG_ALPHA_BG_CONST (1 << 0) +#define MDP4_BLEND_FG_ALPHA_FG_PIXEL (2 << 0) +#define MDP4_BLEND_FG_ALPHA_BG_PIXEL (3 << 0) + +#define MDP4_FORMAT_SOLID_FILL BIT(22) +#define MDP4_FORMAT_UNPACK_ALIGN_MSB BIT(18) +#define MDP4_FORMAT_UNPACK_TIGHT BIT(17) +#define MDP4_FORMAT_90_ROTATED BIT(12) +#define MDP4_FORMAT_ALPHA_ENABLE BIT(8) + +#define MDP4_OP_DEINT_ODD_REF BIT(19) +#define MDP4_OP_IGC_LUT_EN BIT(16) +#define MDP4_OP_DITHER_EN BIT(15) +#define MDP4_OP_FLIP_UD BIT(14) +#define MDP4_OP_FLIP_LR BIT(13) +#define MDP4_OP_CSC_EN BIT(11) +#define MDP4_OP_SRC_DATA_YCBCR BIT(9) +#define MDP4_OP_SCALEY_FIR (0 << 4) +#define MDP4_OP_SCALEY_MN_PHASE (1 << 4) +#define MDP4_OP_SCALEY_PIXEL_RPT (2 << 4) +#define MDP4_OP_SCALEX_FIR (0 << 2) +#define MDP4_OP_SCALEX_MN_PHASE (1 << 2) +#define MDP4_OP_SCALEX_PIXEL_RPT (2 << 2) +#define MDP4_OP_SCALEY_EN BIT(1) +#define MDP4_OP_SCALEX_EN BIT(0) + +#define MDP4_PIPE_PER_MIXER 2 + +#define MDP4_MAX_PLANE 4 + +#define MDP4_MAX_VIDEO_PIPE 2 +#define MDP4_MAX_RGB_PIPE 2 +#define MDP4_MAX_OVERLAY_PIPE 16 + + +struct mdp4_overlay_pipe { + uint32 pipe_type; /* rgb, video/graphic */ + uint32 pipe_num; + uint32 pipe_ndx; + uint32 mixer_num; /* which mixer used */ + uint32 mixer_stage; /* which stage of mixer used */ + uint32 src_format; + uint32 src_width; /* source img width */ + uint32 src_height; /* source img height */ + uint32 src_w; /* roi */ + uint32 src_h; /* roi */ + uint32 src_x; /* roi */ + uint32 src_y; /* roi */ + uint32 dst_w; /* roi */ + uint32 dst_h; /* roi */ + uint32 dst_x; /* roi */ + uint32 dst_y; /* roi */ + uint32 op_mode; + uint32 transp; + uint32 blend_op; + uint32 phasex_step; + uint32 phasey_step; + uint32 alpha; + uint32 is_fg; /* control alpha & color key */ + uint32 srcp0_addr; /* interleave, luma */ + uint32 srcp0_ystride; + uint32 srcp1_addr; /* pseudoplanar, chroma plane */ + uint32 srcp1_ystride; + uint32 srcp2_addr; /* planar color 2*/ + uint32 srcp2_ystride; + uint32 srcp3_addr; /* alpha/color 3 */ + uint32 srcp3_ystride; + uint32 fetch_plane; + uint32 frame_format; /* video */ + uint32 chroma_site; /* video */ + uint32 chroma_sample; /* video */ + uint32 solid_fill; + uint32 vc1_reduce; /* video */ + uint32 fatch_planes; /* video */ + uint32 unpack_align_msb;/* 0 to LSB, 1 to MSB */ + uint32 unpack_tight;/* 0 for loose, 1 for tight */ + uint32 unpack_count;/* 0 = 1 component, 1 = 2 component ... */ + uint32 rotated_90; /* has been rotated 90 degree */ + uint32 bpp; /* byte per pixel */ + uint32 alpha_enable;/* source has alpha */ + /* + * number of bits for source component, + * 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits + */ + uint32 a_bit; /* component 3, alpha */ + uint32 r_bit; /* component 2, R_Cr */ + uint32 b_bit; /* component 1, B_Cb */ + uint32 g_bit; /* component 0, G_lumz */ + /* + * unpack pattern + * A = C3, R = C2, B = C1, G = C0 + */ + uint32 element3; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */ + uint32 element2; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */ + uint32 element1; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */ + uint32 element0; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */ + struct completion comp; + struct mdp_overlay req_data; +}; + +void mdp4_sw_reset(unsigned long bits); +void mdp4_display_intf_sel(int output, unsigned long intf); +void mdp4_overlay_cfg(int layer, int blt_mode, int refresh, int direct_out); +void mdp4_ebi2_lcd_setup(int lcd, unsigned long base, int ystride); +void mdp4_mddi_setup(int which, unsigned long id); +unsigned long mdp4_display_status(void); +void mdp4_enable_clk_irq(void); +void mdp4_disable_clk_irq(void); +void mdp4_dma_p_update(struct msm_fb_data_type *mfd); +void mdp4_dma_s_update(struct msm_fb_data_type *mfd); +void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state, + boolean isr); +void mdp4_pipe_kickoff(uint32 pipe, struct msm_fb_data_type *mfd); +int mdp4_lcdc_on(struct platform_device *pdev); +int mdp4_lcdc_off(struct platform_device *pdev); +void mdp4_lcdc_update(struct msm_fb_data_type *mfd); +void mdp4_intr_clear_set(ulong clear, ulong set); +void mdp4_dma_p_cfg(void); +void mdp4_hw_init(void); +void mdp4_isr_read(int); +void mdp4_clear_lcdc(void); +void mdp4_mixer_blend_init(int mixer_num); +void mdp4_vg_qseed_init(int vg_num); +void mdp4_vg_csc_mv_setup(int vp_num); +void mdp4_vg_csc_pre_bv_setup(int vp_num); +void mdp4_vg_csc_post_bv_setup(int vp_num); +void mdp4_vg_csc_pre_lv_setup(int vp_num); +void mdp4_vg_csc_post_lv_setup(int vp_num); +irqreturn_t mdp4_isr(int irq, void *ptr); +void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe); +uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe); +uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe); +uint32 mdp4_overlay_op_mode(struct mdp4_overlay_pipe *pipe); +void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd); +void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe); +void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all); +void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe); +void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe); +void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe); +int mdp4_mixer_stage_can_run(struct mdp4_overlay_pipe *pipe); +void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe); +void mdp4_mddi_overlay(struct msm_fb_data_type *mfd); +int mdp4_overlay_format2type(uint32 format); +int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe); +int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req); +int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req); +int mdp4_overlay_unset(struct fb_info *info, int ndx); +int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req, + struct file **pp_src_file); +struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void); +void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe); +void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc); +void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe); +int mdp4_overlay_active(int mixer); +void mdp4_overlay0_done_lcdc(void); +void mdp4_overlay0_done_mddi(void); +void mdp4_mddi_overlay_restore(void); +void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); +void mdp4_rgb_igc_lut_setup(int num); +void mdp4_vg_igc_lut_setup(int num); +void mdp4_mixer_gc_lut_setup(int mixer_num); + +#ifdef CONFIG_DEBUG_FS +int mdp4_debugfs_init(void); +#endif + +int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req, + struct file **pp_src_file, struct file **pp_dst_file); + +#endif /* MDP_H */ diff --git a/drivers/staging/msm/mdp4_debugfs.c b/drivers/staging/msm/mdp4_debugfs.c new file mode 100644 index 000000000000..844d46775ecd --- /dev/null +++ b/drivers/staging/msm/mdp4_debugfs.c @@ -0,0 +1,181 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/clk.h> +#include <mach/hardware.h> +#include <linux/io.h> +#include <linux/debugfs.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + + +#define MDP4_DEBUG_BUF 128 + + +static char mdp4_debug_buf[MDP4_DEBUG_BUF]; +static ulong mdp4_debug_offset; +static ulong mdp4_base_addr; + +static int mdp4_offset_set(void *data, u64 val) +{ + mdp4_debug_offset = (int)val; + return 0; +} + +static int mdp4_offset_get(void *data, u64 *val) +{ + *val = (u64)mdp4_debug_offset; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE( + mdp4_offset_fops, + mdp4_offset_get, + mdp4_offset_set, + "%llx\n"); + + +static int mdp4_debugfs_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + return 0; +} + +static int mdp4_debugfs_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t mdp4_debugfs_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + int cnt; + unsigned int data; + + printk(KERN_INFO "%s: offset=%d count=%d *ppos=%d\n", + __func__, (int)mdp4_debug_offset, (int)count, (int)*ppos); + + if (count > sizeof(mdp4_debug_buf)) + return -EFAULT; + + if (copy_from_user(mdp4_debug_buf, buff, count)) + return -EFAULT; + + + mdp4_debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(mdp4_debug_buf, "%x", &data); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + + writel(&data, mdp4_base_addr + mdp4_debug_offset); + + return 0; +} + +static ssize_t mdp4_debugfs_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int len = 0; + unsigned int data; + + printk(KERN_INFO "%s: offset=%d count=%d *ppos=%d\n", + __func__, (int)mdp4_debug_offset, (int)count, (int)*ppos); + + if (*ppos) + return 0; /* the end */ + + data = readl(mdp4_base_addr + mdp4_debug_offset); + + len = snprintf(mdp4_debug_buf, 4, "%x\n", data); + + if (len > 0) { + if (len > count) + len = count; + if (copy_to_user(buff, mdp4_debug_buf, len)) + return -EFAULT; + } + + printk(KERN_INFO "%s: len=%d\n", __func__, len); + + if (len < 0) + return 0; + + *ppos += len; /* increase offset */ + + return len; +} + +static const struct file_operations mdp4_debugfs_fops = { + .open = mdp4_debugfs_open, + .release = mdp4_debugfs_release, + .read = mdp4_debugfs_read, + .write = mdp4_debugfs_write, +}; + +int mdp4_debugfs_init(void) +{ + struct dentry *dent = debugfs_create_dir("mdp4", NULL); + + if (IS_ERR(dent)) { + printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n", + __FILE__, __LINE__, PTR_ERR(dent)); + return -1; + } + + if (debugfs_create_file("offset", 0644, dent, 0, &mdp4_offset_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: offset fail\n", + __FILE__, __LINE__); + return -1; + } + + if (debugfs_create_file("regs", 0644, dent, 0, &mdp4_debugfs_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: regs fail\n", + __FILE__, __LINE__); + return -1; + } + + mdp4_debug_offset = 0; + mdp4_base_addr = (ulong) msm_mdp_base; /* defined at msm_fb_def.h */ + + return 0; +} diff --git a/drivers/staging/msm/mdp4_overlay.c b/drivers/staging/msm/mdp4_overlay.c new file mode 100644 index 000000000000..304bb8297635 --- /dev/null +++ b/drivers/staging/msm/mdp4_overlay.c @@ -0,0 +1,1259 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/clk.h> +#include <mach/hardware.h> +#include <linux/io.h> +#include <linux/debugfs.h> +#include <linux/fb.h> +#include <msm_mdp.h> +#include <linux/file.h> +#include "android_pmem.h" +#include <linux/major.h> +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <linux/mutex.h> + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + + +struct mdp4_overlay_ctrl { + struct mdp4_overlay_pipe plist[MDP4_MAX_OVERLAY_PIPE]; + struct mdp4_overlay_pipe *stage[MDP4_MAX_MIXER][MDP4_MAX_STAGE]; +} mdp4_overlay_db; + +static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db; + + +void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc) +{ + uint32 dma2_cfg_reg; + + dma2_cfg_reg = DMA_DITHER_EN; + + if (mfd->fb_imgType == MDP_BGR_565) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; + + + if (mfd->panel_info.bpp == 18) { + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else if (mfd->panel_info.bpp == 16) { + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } else { + dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 16BPP */ + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + } + + if (lcdc) + dma2_cfg_reg |= DMA_PACK_ALIGN_MSB; + + /* dma2 config register */ + MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg); + +} + +void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe) +{ + + /* dma_p source */ + MDP_OUTP(MDP_BASE + 0x90004, + (pipe->src_height << 16 | pipe->src_width)); + MDP_OUTP(MDP_BASE + 0x90008, pipe->srcp0_addr); + MDP_OUTP(MDP_BASE + 0x9000c, pipe->srcp0_ystride); + + /* dma_p dest */ + MDP_OUTP(MDP_BASE + 0x90010, (pipe->dst_y << 16 | pipe->dst_x)); +} + +#define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000 +#define MDP4_VG_PHASE_STEP_SHIFT 29 + +static int mdp4_leading_0(uint32 num) +{ + uint32 bit = 0x80000000; + int i; + + for (i = 0; i < 32; i++) { + if (bit & num) + return i; + bit >>= 1; + } + + return i; +} + +static uint32 mdp4_scale_phase_step(int f_num, uint32 src, uint32 dst) +{ + uint32 val; + int n; + + n = mdp4_leading_0(src); + if (n > f_num) + n = f_num; + val = src << n; /* maximum to reduce lose of resolution */ + val /= dst; + if (n < f_num) { + n = f_num - n; + val <<= n; + } + + return val; +} + +static void mdp4_scale_setup(struct mdp4_overlay_pipe *pipe) +{ + + pipe->phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; + pipe->phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; + + if (pipe->dst_h && pipe->src_h != pipe->dst_h) { + if (pipe->dst_h >= pipe->src_h * 8) /* too much */ + return; + pipe->op_mode |= MDP4_OP_SCALEY_EN; + + if (pipe->pipe_type == OVERLAY_TYPE_VG) { + if (pipe->dst_h <= (pipe->src_h / 4)) + pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE; + else + pipe->op_mode |= MDP4_OP_SCALEY_FIR; + } + + pipe->phasey_step = mdp4_scale_phase_step(29, + pipe->src_h, pipe->dst_h); + } + + if (pipe->dst_w && pipe->src_w != pipe->dst_w) { + if (pipe->dst_w >= pipe->src_w * 8) /* too much */ + return; + pipe->op_mode |= MDP4_OP_SCALEX_EN; + + if (pipe->pipe_type == OVERLAY_TYPE_VG) { + if (pipe->dst_w <= (pipe->src_w / 4)) + pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE; + else + pipe->op_mode |= MDP4_OP_SCALEY_FIR; + } + + pipe->phasex_step = mdp4_scale_phase_step(29, + pipe->src_w, pipe->dst_w); + } +} + +void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe) +{ + char *rgb_base; + uint32 src_size, src_xy, dst_size, dst_xy; + uint32 format, pattern; + + rgb_base = MDP_BASE + MDP4_RGB_BASE; + rgb_base += (MDP4_RGB_OFF * pipe->pipe_num); + + src_size = ((pipe->src_h << 16) | pipe->src_w); + src_xy = ((pipe->src_y << 16) | pipe->src_x); + dst_size = ((pipe->dst_h << 16) | pipe->dst_w); + dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); + + format = mdp4_overlay_format(pipe); + pattern = mdp4_overlay_unpack_pattern(pipe); + + pipe->op_mode |= MDP4_OP_IGC_LUT_EN; + + mdp4_scale_setup(pipe); + + outpdw(rgb_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ + outpdw(rgb_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ + outpdw(rgb_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ + outpdw(rgb_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ + + outpdw(rgb_base + 0x0010, pipe->srcp0_addr); + outpdw(rgb_base + 0x0040, pipe->srcp0_ystride); + + outpdw(rgb_base + 0x0050, format);/* MDP_RGB_SRC_FORMAT */ + outpdw(rgb_base + 0x0054, pattern);/* MDP_RGB_SRC_UNPACK_PATTERN */ + outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ + outpdw(rgb_base + 0x005c, pipe->phasex_step); + outpdw(rgb_base + 0x0060, pipe->phasey_step); + + /* 16 bytes-burst x 3 req <= 48 bytes */ + outpdw(rgb_base + 0x1004, 0xc2); /* MDP_RGB_FETCH_CFG */ +} + +void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe) +{ + char *vg_base; + uint32 frame_size, src_size, src_xy, dst_size, dst_xy; + uint32 format, pattern; + + vg_base = MDP_BASE + MDP4_VIDEO_BASE; + vg_base += (MDP4_VIDEO_OFF * pipe->pipe_num); + + frame_size = ((pipe->src_height << 16) | pipe->src_width); + src_size = ((pipe->src_h << 16) | pipe->src_w); + src_xy = ((pipe->src_y << 16) | pipe->src_x); + dst_size = ((pipe->dst_h << 16) | pipe->dst_w); + dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); + + format = mdp4_overlay_format(pipe); + pattern = mdp4_overlay_unpack_pattern(pipe); + + pipe->op_mode |= (MDP4_OP_CSC_EN | MDP4_OP_SRC_DATA_YCBCR | + MDP4_OP_IGC_LUT_EN); + + mdp4_scale_setup(pipe); + + outpdw(vg_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ + outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ + outpdw(vg_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ + outpdw(vg_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ + outpdw(vg_base + 0x0048, frame_size); /* TILE frame size */ + + /* luma component plane */ + outpdw(vg_base + 0x0010, pipe->srcp0_addr); + + /* chroma component plane */ + outpdw(vg_base + 0x0014, pipe->srcp1_addr); + + outpdw(vg_base + 0x0040, + pipe->srcp1_ystride << 16 | pipe->srcp0_ystride); + + outpdw(vg_base + 0x0050, format); /* MDP_RGB_SRC_FORMAT */ + outpdw(vg_base + 0x0054, pattern); /* MDP_RGB_SRC_UNPACK_PATTERN */ + outpdw(vg_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ + outpdw(vg_base + 0x005c, pipe->phasex_step); + outpdw(vg_base + 0x0060, pipe->phasey_step); + + if (pipe->op_mode & MDP4_OP_DITHER_EN) { + outpdw(vg_base + 0x0068, + pipe->r_bit << 4 | pipe->b_bit << 2 | pipe->g_bit); + } + + /* 16 bytes-burst x 3 req <= 48 bytes */ + outpdw(vg_base + 0x1004, 0xc2); /* MDP_VG_FETCH_CFG */ +} + +int mdp4_overlay_format2type(uint32 format) +{ + switch (format) { + case MDP_RGB_565: + case MDP_RGB_888: + case MDP_BGR_565: + case MDP_ARGB_8888: + case MDP_RGBA_8888: + case MDP_BGRA_8888: + return OVERLAY_TYPE_RGB; + case MDP_YCRYCB_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_TILE: + case MDP_Y_CRCB_H2V2_TILE: + return OVERLAY_TYPE_VG; + default: + return -ERANGE; + } + +} + +#define C3_ALPHA 3 /* alpha */ +#define C2_R_Cr 2 /* R/Cr */ +#define C1_B_Cb 1 /* B/Cb */ +#define C0_G_Y 0 /* G/luma */ + +int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe) +{ + switch (pipe->src_format) { + case MDP_RGB_565: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 1; /* R, 5 bits */ + pipe->b_bit = 1; /* B, 5 bits */ + pipe->g_bit = 2; /* G, 6 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_RGB_888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 3; /* 3 bpp */ + break; + case MDP_BGR_565: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 1; /* R, 5 bits */ + pipe->b_bit = 1; /* B, 5 bits */ + pipe->g_bit = 2; /* G, 6 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_ARGB_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C3_ALPHA; /* alpha */ + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_RGBA_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C2_R_Cr; /* R */ + pipe->element2 = C0_G_Y; /* G */ + pipe->element1 = C1_B_Cb; /* B */ + pipe->element0 = C3_ALPHA; /* alpha */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_BGRA_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C1_B_Cb; /* B */ + pipe->element2 = C0_G_Y; /* G */ + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C3_ALPHA; /* alpha */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_YCRYCB_H2V1: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C0_G_Y; /* G */ + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 2; /* 2 bpp */ + pipe->chroma_sample = MDP4_CHROMA_H2V1; + break; + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 1; /* 2 */ + pipe->element3 = C0_G_Y; /* not used */ + pipe->element2 = C0_G_Y; /* not used */ + if (pipe->src_format == MDP_Y_CRCB_H2V1) { + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->chroma_sample = MDP4_CHROMA_H2V1; + } else if (pipe->src_format == MDP_Y_CBCR_H2V1) { + pipe->element1 = C1_B_Cb; /* B */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->chroma_sample = MDP4_CHROMA_H2V1; + } else if (pipe->src_format == MDP_Y_CRCB_H2V2) { + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->chroma_sample = MDP4_CHROMA_420; + } else if (pipe->src_format == MDP_Y_CBCR_H2V2) { + pipe->element1 = C1_B_Cb; /* B */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->chroma_sample = MDP4_CHROMA_420; + } + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_Y_CBCR_H2V2_TILE: + case MDP_Y_CRCB_H2V2_TILE: + pipe->frame_format = MDP4_FRAME_FORMAT_VIDEO_SUPERTILE; + pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 1; /* 2 */ + pipe->element3 = C0_G_Y; /* not used */ + pipe->element2 = C0_G_Y; /* not used */ + if (pipe->src_format == MDP_Y_CRCB_H2V2_TILE) { + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->chroma_sample = MDP4_CHROMA_420; + } else if (pipe->src_format == MDP_Y_CBCR_H2V2_TILE) { + pipe->element1 = C1_B_Cb; /* B */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->chroma_sample = MDP4_CHROMA_420; + } + pipe->bpp = 2; /* 2 bpp */ + break; + default: + /* not likely */ + return -ERANGE; + } + + return 0; +} + +/* + * color_key_convert: output with 12 bits color key + */ +static uint32 color_key_convert(int start, int num, uint32 color) +{ + + uint32 data; + + data = (color >> start) & ((1 << num) - 1); + + if (num == 5) + data = (data << 7) + (data << 2) + (data >> 3); + else if (num == 6) + data = (data << 6) + data; + else /* 8 bits */ + data = (data << 4) + (data >> 4); + + return data; + +} + +void transp_color_key(int format, uint32 transp, + uint32 *c0, uint32 *c1, uint32 *c2) +{ + int b_start, g_start, r_start; + int b_num, g_num, r_num; + + switch (format) { + case MDP_RGB_565: + b_start = 0; + g_start = 5; + r_start = 11; + r_num = 5; + g_num = 6; + b_num = 5; + break; + case MDP_RGB_888: + case MDP_XRGB_8888: + case MDP_ARGB_8888: + b_start = 0; + g_start = 8; + r_start = 16; + r_num = 8; + g_num = 8; + b_num = 8; + break; + case MDP_BGR_565: + b_start = 11; + g_start = 5; + r_start = 0; + r_num = 5; + g_num = 6; + b_num = 5; + break; + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V1: + b_start = 8; + g_start = 16; + r_start = 0; + r_num = 8; + g_num = 8; + b_num = 8; + break; + case MDP_Y_CRCB_H2V2: + case MDP_Y_CRCB_H2V1: + b_start = 0; + g_start = 16; + r_start = 8; + r_num = 8; + g_num = 8; + b_num = 8; + break; + default: + b_start = 0; + g_start = 8; + r_start = 16; + r_num = 8; + g_num = 8; + b_num = 8; + break; + } + + *c0 = color_key_convert(g_start, g_num, transp); + *c1 = color_key_convert(b_start, b_num, transp); + *c2 = color_key_convert(r_start, r_num, transp); +} + +uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe) +{ + uint32 format; + + format = 0; + + if (pipe->solid_fill) + format |= MDP4_FORMAT_SOLID_FILL; + + if (pipe->unpack_align_msb) + format |= MDP4_FORMAT_UNPACK_ALIGN_MSB; + + if (pipe->unpack_tight) + format |= MDP4_FORMAT_UNPACK_TIGHT; + + if (pipe->alpha_enable) + format |= MDP4_FORMAT_ALPHA_ENABLE; + + format |= (pipe->unpack_count << 13); + format |= ((pipe->bpp - 1) << 9); + format |= (pipe->a_bit << 6); + format |= (pipe->r_bit << 4); + format |= (pipe->b_bit << 2); + format |= pipe->g_bit; + + format |= (pipe->frame_format << 29); + + if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { + /* video/graphic */ + format |= (pipe->fetch_plane << 19); + format |= (pipe->chroma_site << 28); + format |= (pipe->chroma_sample << 26); + } + + return format; +} + +uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe) +{ + return (pipe->element3 << 24) | (pipe->element2 << 16) | + (pipe->element1 << 8) | pipe->element0; +} + +void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe) +{ + uint32 data; + char *overlay_base; + + if (pipe->mixer_num == MDP4_MIXER1) + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + /* MDP_OVERLAYPROC_CFG */ + outpdw(overlay_base + 0x0004, 0x01); /* directout */ + data = pipe->src_height; + data <<= 16; + data |= pipe->src_width; + outpdw(overlay_base + 0x0008, data); /* ROI, height + width */ + outpdw(overlay_base + 0x000c, pipe->srcp0_addr); + outpdw(overlay_base + 0x0010, pipe->srcp0_ystride); + outpdw(overlay_base + 0x0014, 0x4); /* GC_LUT_EN, 888 */ +} + +int mdp4_overlay_active(int mixer) +{ + uint32 data, mask, i; + int p1, p2; + + data = inpdw(MDP_BASE + 0x10100); + p1 = 0; + p2 = 0; + for (i = 0; i < 8; i++) { + mask = data & 0x0f; + if (mask) { + if (mask <= 4) + p1++; + else + p2++; + } + data >>= 4; + } + + if (mixer) + return p2; + else + return p1; +} + +void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe) +{ + uint32 data, mask, snum, stage, mixer; + + stage = pipe->mixer_stage; + mixer = pipe->mixer_num; + + /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */ + data = inpdw(MDP_BASE + 0x10100); + + if (mixer == MDP4_MIXER1) + stage += 8; + + if (pipe->pipe_type == OVERLAY_TYPE_VG) {/* VG1 and VG2 */ + snum = 0; + snum += (4 * pipe->pipe_num); + } else { + snum = 8; + snum += (4 * pipe->pipe_num); /* RGB1 and RGB2 */ + } + + mask = 0x0f; + mask <<= snum; + stage <<= snum; + data &= ~mask; /* clear old bits */ + + data |= stage; + + outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */ + + data = inpdw(MDP_BASE + 0x10100); + + ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = pipe; /* keep it */ +} + +void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe) +{ + uint32 data, mask, snum, stage, mixer; + + stage = pipe->mixer_stage; + mixer = pipe->mixer_num; + + if (pipe != ctrl->stage[mixer][stage]) /* not runing */ + return; + + /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */ + data = inpdw(MDP_BASE + 0x10100); + + if (mixer == MDP4_MIXER1) + stage += 8; + + if (pipe->pipe_type == OVERLAY_TYPE_VG) {/* VG1 and VG2 */ + snum = 0; + snum += (4 * pipe->pipe_num); + } else { + snum = 8; + snum += (4 * pipe->pipe_num); /* RGB1 and RGB2 */ + } + + mask = 0x0f; + mask <<= snum; + data &= ~mask; /* clear old bits */ + + outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */ + + data = inpdw(MDP_BASE + 0x10100); + + ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL; /* clear it */ +} + +void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe) +{ + unsigned char *overlay_base; + uint32 c0, c1, c2, blend_op; + int off; + + if (pipe->mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + /* stage 0 to stage 2 */ + off = 0x20 * (pipe->mixer_stage - MDP4_MIXER_STAGE0); + + blend_op = 0; + if (pipe->alpha_enable) /* ARGB */ + blend_op = MDP4_BLEND_FG_ALPHA_FG_PIXEL | + MDP4_BLEND_BG_ALPHA_FG_PIXEL; + else + blend_op = (MDP4_BLEND_BG_ALPHA_BG_CONST | + MDP4_BLEND_FG_ALPHA_FG_CONST); + + + if (pipe->alpha_enable == 0) { /* not ARGB */ + if (pipe->is_fg) { + outpdw(overlay_base + off + 0x108, pipe->alpha); + outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha); + } else { + outpdw(overlay_base + off + 0x108, 0xff - pipe->alpha); + outpdw(overlay_base + off + 0x10c, pipe->alpha); + } + } + + if (pipe->transp != MDP_TRANSP_NOP) { + transp_color_key(pipe->src_format, pipe->transp, &c0, &c1, &c2); + if (pipe->is_fg) { + blend_op |= MDP4_BLEND_FG_TRANSP_EN; /* Fg blocked */ + /* lower limit */ + if (c0 > 0x10) + c0 -= 0x10; + if (c1 > 0x10) + c1 -= 0x10; + if (c2 > 0x10) + c2 -= 0x10; + outpdw(overlay_base + off + 0x110, + (c1 << 16 | c0));/* low */ + outpdw(overlay_base + off + 0x114, c2);/* low */ + /* upper limit */ + if ((c0 + 0x20) < 0x0fff) + c0 += 0x20; + else + c0 = 0x0fff; + if ((c1 + 0x20) < 0x0fff) + c1 += 0x20; + else + c1 = 0x0fff; + if ((c2 + 0x20) < 0x0fff) + c2 += 0x20; + else + c2 = 0x0fff; + outpdw(overlay_base + off + 0x118, + (c1 << 16 | c0));/* high */ + outpdw(overlay_base + off + 0x11c, c2);/* high */ + } else { + blend_op |= MDP4_BLEND_BG_TRANSP_EN; /* bg blocked */ + /* lower limit */ + if (c0 > 0x10) + c0 -= 0x10; + if (c1 > 0x10) + c1 -= 0x10; + if (c2 > 0x10) + c2 -= 0x10; + outpdw(overlay_base + 0x180, + (c1 << 16 | c0));/* low */ + outpdw(overlay_base + 0x184, c2);/* low */ + /* upper limit */ + if ((c0 + 0x20) < 0x0fff) + c0 += 0x20; + else + c0 = 0x0fff; + if ((c1 + 0x20) < 0x0fff) + c1 += 0x20; + else + c1 = 0x0fff; + if ((c2 + 0x20) < 0x0fff) + c2 += 0x20; + else + c2 = 0x0fff; + outpdw(overlay_base + 0x188, + (c1 << 16 | c0));/* high */ + outpdw(overlay_base + 0x18c, c2);/* high */ + } + } + outpdw(overlay_base + off + 0x104, blend_op); +} + +void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all) +{ + uint32 bits = 0; + + if (pipe->mixer_num == MDP4_MIXER1) + bits |= 0x02; + else + bits |= 0x01; + + if (all) { + if (pipe->pipe_type == OVERLAY_TYPE_RGB) { + if (pipe->pipe_num == OVERLAY_PIPE_RGB2) + bits |= 0x20; + else + bits |= 0x10; + } else { + if (pipe->pipe_num == OVERLAY_PIPE_VG2) + bits |= 0x08; + else + bits |= 0x04; + } + } + + outpdw(MDP_BASE + 0x18000, bits); /* MDP_OVERLAY_REG_FLUSH */ + + while (inpdw(MDP_BASE + 0x18000) & bits) /* self clear when complete */ + ; +} + +struct mdp4_overlay_pipe *mdp4_overlay_ndx2pipe(int ndx) +{ + struct mdp4_overlay_pipe *pipe; + + if (ndx == 0 || ndx >= MDP4_MAX_OVERLAY_PIPE) + return NULL; + + pipe = &ctrl->plist[ndx - 1]; /* ndx start from 1 */ + + if (pipe->pipe_ndx == 0) + return NULL; + + return pipe; +} + +struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void) +{ + int i; + struct mdp4_overlay_pipe *pipe; + + pipe = &ctrl->plist[0]; + for (i = 0; i < MDP4_MAX_OVERLAY_PIPE; i++) { + if (pipe->pipe_ndx == 0) { + pipe->pipe_ndx = i + 1; /* start from 1 */ + init_completion(&pipe->comp); + printk(KERN_INFO "mdp4_overlay_pipe_alloc: pipe=%x ndx=%d\n", + (int)pipe, pipe->pipe_ndx); + return pipe; + } + pipe++; + } + + return NULL; +} + + +void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe) +{ + printk(KERN_INFO "mdp4_overlay_pipe_free: pipe=%x ndx=%d\n", + (int)pipe, pipe->pipe_ndx); + memset(pipe, 0, sizeof(*pipe)); +} + +static int get_pipe_num(int ptype, int stage) +{ + if (ptype == OVERLAY_TYPE_RGB) { + if (stage == MDP4_MIXER_STAGE_BASE) + return OVERLAY_PIPE_RGB1; + else + return OVERLAY_PIPE_RGB2; + } else { + if (stage == MDP4_MIXER_STAGE0) + return OVERLAY_PIPE_VG1; + else + return OVERLAY_PIPE_VG2; + } +} + +int mdp4_overlay_req_check(uint32 id, uint32 z_order, uint32 mixer) +{ + struct mdp4_overlay_pipe *pipe; + + pipe = ctrl->stage[mixer][z_order]; + + if (pipe == NULL) + return 0; + + if (pipe->pipe_ndx == id) /* same req, recycle */ + return 0; + + return -EPERM; +} + +static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer, + struct mdp4_overlay_pipe **ppipe) +{ + struct mdp4_overlay_pipe *pipe; + int ret, ptype; + + if (mixer >= MDP4_MAX_MIXER) { + printk(KERN_ERR "mpd_overlay_req2pipe: mixer out of range!\n"); + return -ERANGE; + } + + if (req->z_order < 0 || req->z_order > 2) { + printk(KERN_ERR "mpd_overlay_req2pipe: z_order=%d out of range!\n", + req->z_order); + return -ERANGE; + } + + if (req->src_rect.h == 0 || req->src_rect.w == 0) { + printk(KERN_ERR "mpd_overlay_req2pipe: src img of zero size!\n"); + return -EINVAL; + } + + ret = mdp4_overlay_req_check(req->id, req->z_order, mixer); + if (ret < 0) + return ret; + + ptype = mdp4_overlay_format2type(req->src.format); + if (ptype < 0) + return ptype; + + if (req->id == MSMFB_NEW_REQUEST) /* new request */ + pipe = mdp4_overlay_pipe_alloc(); + else + pipe = mdp4_overlay_ndx2pipe(req->id); + + if (pipe == NULL) + return -ENOMEM; + + pipe->src_format = req->src.format; + ret = mdp4_overlay_format2pipe(pipe); + + if (ret < 0) + return ret; + + /* + * base layer == 1, reserved for frame buffer + * zorder 0 == stage 0 == 2 + * zorder 1 == stage 1 == 3 + * zorder 2 == stage 2 == 4 + */ + if (req->id == MSMFB_NEW_REQUEST) { /* new request */ + pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0; + pipe->pipe_type = ptype; + pipe->pipe_num = get_pipe_num(ptype, pipe->mixer_stage); + printk(KERN_INFO "mpd4_overlay_req2pipe: zorder=%d pipe_num=%d\n", + req->z_order, pipe->pipe_num); + } + + pipe->src_width = req->src.width & 0x07ff; /* source img width */ + pipe->src_height = req->src.height & 0x07ff; /* source img height */ + pipe->src_h = req->src_rect.h & 0x07ff; + pipe->src_w = req->src_rect.w & 0x07ff; + pipe->src_y = req->src_rect.y & 0x07ff; + pipe->src_x = req->src_rect.x & 0x07ff; + pipe->dst_h = req->dst_rect.h & 0x07ff; + pipe->dst_w = req->dst_rect.w & 0x07ff; + pipe->dst_y = req->dst_rect.y & 0x07ff; + pipe->dst_x = req->dst_rect.x & 0x07ff; + + if (req->flags & MDP_FLIP_LR) + pipe->op_mode |= MDP4_OP_FLIP_LR; + + if (req->flags & MDP_FLIP_UD) + pipe->op_mode |= MDP4_OP_FLIP_UD; + + if (req->flags & MDP_DITHER) + pipe->op_mode |= MDP4_OP_DITHER_EN; + + if (req->flags & MDP_DEINTERLACE) + pipe->op_mode |= MDP4_OP_DEINT_ODD_REF; + + pipe->is_fg = req->is_fg;/* control alpha and color key */ + + pipe->alpha = req->alpha & 0x0ff; + + pipe->transp = req->transp_mask; + + *ppipe = pipe; + + return 0; +} + +int get_img(struct msmfb_data *img, struct fb_info *info, + unsigned long *start, unsigned long *len, struct file **pp_file) +{ + int put_needed, ret = 0; + struct file *file; +#ifdef CONFIG_ANDROID_PMEM + unsigned long vstart; +#endif + +#ifdef CONFIG_ANDROID_PMEM + if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file)) + return 0; +#endif + file = fget_light(img->memory_id, &put_needed); + if (file == NULL) + return -1; + + if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { + *start = info->fix.smem_start; + *len = info->fix.smem_len; + *pp_file = file; + } else { + ret = -1; + fput_light(file, put_needed); + } + return ret; +} +int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req) +{ + struct mdp4_overlay_pipe *pipe; + + pipe = mdp4_overlay_ndx2pipe(req->id); + if (pipe == NULL) + return -ENODEV; + + *req = pipe->req_data; + + return 0; +} + +int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int ret, mixer; + struct mdp4_overlay_pipe *pipe; + int lcdc; + + if (mfd == NULL) + return -ENODEV; + + if (req->src.format == MDP_FB_FORMAT) + req->src.format = mfd->fb_imgType; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + mixer = info->node; /* minor number of char device */ + + ret = mdp4_overlay_req2pipe(req, mixer, &pipe); + if (ret < 0) { + mutex_unlock(&mfd->dma->ov_mutex); + return ret; + } + + lcdc = inpdw(MDP_BASE + 0xc0000); + + if (lcdc == 0) { /* mddi */ + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + } + + /* return id back to user */ + req->id = pipe->pipe_ndx; /* pipe_ndx start from 1 */ + pipe->req_data = *req; /* keep original req */ + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} + +int mdp4_overlay_unset(struct fb_info *info, int ndx) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct mdp4_overlay_pipe *pipe; + int lcdc; + + if (mfd == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + pipe = mdp4_overlay_ndx2pipe(ndx); + + if (pipe == NULL) { + mutex_unlock(&mfd->dma->ov_mutex); + return -ENODEV; + } + + lcdc = inpdw(MDP_BASE + 0xc0000); + + mdp4_mixer_stage_down(pipe); + + if (lcdc == 0) { /* mddi */ + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } + + if (lcdc) /* LCDC mode */ + mdp4_overlay_reg_flush(pipe, 0); + + mdp4_overlay_pipe_free(pipe); + + if (lcdc == 0) { /* mddi */ + mdp4_mddi_overlay_restore(); + } + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} + +struct tile_desc { + uint32 width; /* tile's width */ + uint32 height; /* tile's height */ + uint32 row_tile_w; /* tiles per row's width */ + uint32 row_tile_h; /* tiles per row's height */ +}; + +void tile_samsung(struct tile_desc *tp) +{ + /* + * each row of samsung tile consists of two tiles in height + * and two tiles in width which means width should align to + * 64 x 2 bytes and height should align to 32 x 2 bytes. + * video decoder generate two tiles in width and one tile + * in height which ends up height align to 32 X 1 bytes. + */ + tp->width = 64; /* 64 bytes */ + tp->row_tile_w = 2; /* 2 tiles per row's width */ + tp->height = 32; /* 32 bytes */ + tp->row_tile_h = 1; /* 1 tiles per row's height */ +} + +uint32 tile_mem_size(struct mdp4_overlay_pipe *pipe, struct tile_desc *tp) +{ + uint32 tile_w, tile_h; + uint32 row_num_w, row_num_h; + + + tile_w = tp->width * tp->row_tile_w; + tile_h = tp->height * tp->row_tile_h; + + row_num_w = (pipe->src_width + tile_w - 1) / tile_w; + row_num_h = (pipe->src_height + tile_h - 1) / tile_h; + + return row_num_w * row_num_h * tile_w * tile_h; +} + +int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req, + struct file **pp_src_file) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msmfb_data *img; + struct mdp4_overlay_pipe *pipe; + ulong start, addr; + ulong len = 0; + struct file *p_src_file = 0; + int lcdc; + + if (mfd == NULL) + return -ENODEV; + + pipe = mdp4_overlay_ndx2pipe(req->id); + if (pipe == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + img = &req->data; + get_img(img, info, &start, &len, &p_src_file); + if (len == 0) { + mutex_unlock(&mfd->dma->ov_mutex); + printk(KERN_ERR "mdp_overlay_play: could not retrieve" + " image from memory\n"); + return -1; + } + *pp_src_file = p_src_file; + + addr = start + img->offset; + pipe->srcp0_addr = addr; + pipe->srcp0_ystride = pipe->src_width * pipe->bpp; + + if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { + if (pipe->frame_format == MDP4_FRAME_FORMAT_VIDEO_SUPERTILE) { + struct tile_desc tile; + + tile_samsung(&tile); + pipe->srcp1_addr = addr + tile_mem_size(pipe, &tile); + } else + pipe->srcp1_addr = addr + + pipe->src_width * pipe->src_height; + + pipe->srcp0_ystride = pipe->src_width; + pipe->srcp1_ystride = pipe->src_width; + } + + lcdc = inpdw(MDP_BASE + 0xc0000); + lcdc &= 0x01; /* LCDC mode */ + + if (pipe->pipe_type == OVERLAY_TYPE_VG) + mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */ + else + mdp4_overlay_rgb_setup(pipe); /* rgb pipe */ + + mdp4_mixer_blend_setup(pipe); + mdp4_mixer_stage_up(pipe); + + if (lcdc) { /* LCDC mode */ + mdp4_overlay_reg_flush(pipe, 1); + } + + if (lcdc) { /* LCDC mode */ + if (pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) { /* done */ + mutex_unlock(&mfd->dma->ov_mutex); + return 0; + } + } + + if (lcdc == 0) { /* MDDI mode */ +#ifdef MDP4_NONBLOCKING + if (mfd->panel_power_on) +#else + if (!mfd->dma->busy && mfd->panel_power_on) +#endif + mdp4_mddi_overlay_kickoff(mfd, pipe); + } + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} diff --git a/drivers/staging/msm/mdp4_overlay_lcdc.c b/drivers/staging/msm/mdp4_overlay_lcdc.c new file mode 100644 index 000000000000..a6ab8ec83f55 --- /dev/null +++ b/drivers/staging/msm/mdp4_overlay_lcdc.c @@ -0,0 +1,313 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/hrtimer.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/spinlock.h> + +#include <linux/fb.h> + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +#ifdef CONFIG_FB_MSM_MDP40 +#define LCDC_BASE 0xC0000 +#else +#define LCDC_BASE 0xE0000 +#endif + +int first_pixel_start_x; +int first_pixel_start_y; + +static struct mdp4_overlay_pipe *lcdc_pipe; + +int mdp_lcdc_on(struct platform_device *pdev) +{ + int lcdc_width; + int lcdc_height; + int lcdc_bpp; + int lcdc_border_clr; + int lcdc_underflow_clr; + int lcdc_hsync_skew; + + int hsync_period; + int hsync_ctrl; + int vsync_period; + int display_hctl; + int display_v_start; + int display_v_end; + int active_hctl; + int active_h_start; + int active_h_end; + int active_v_start; + int active_v_end; + int ctrl_polarity; + int h_back_porch; + int h_front_porch; + int v_back_porch; + int v_front_porch; + int hsync_pulse_width; + int vsync_pulse_width; + int hsync_polarity; + int vsync_polarity; + int data_en_polarity; + int hsync_start_x; + int hsync_end_x; + uint8 *buf; + int bpp, ptype; + uint32 format; + struct fb_info *fbi; + struct fb_var_screeninfo *var; + struct msm_fb_data_type *mfd; + struct mdp4_overlay_pipe *pipe; + int ret; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + fbi = mfd->fbi; + var = &fbi->var; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf += fbi->var.xoffset * bpp + + fbi->var.yoffset * fbi->fix.line_length; + + if (bpp == 2) + format = MDP_RGB_565; + else if (bpp == 3) + format = MDP_RGB_888; + else + format = MDP_ARGB_8888; + + + if (lcdc_pipe == NULL) { + ptype = mdp4_overlay_format2type(format); + pipe = mdp4_overlay_pipe_alloc(); + pipe->pipe_type = ptype; + /* use RGB1 pipe */ + pipe->pipe_num = OVERLAY_PIPE_RGB1; + pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + pipe->mixer_num = MDP4_MIXER0; + pipe->src_format = format; + mdp4_overlay_format2pipe(pipe); + + lcdc_pipe = pipe; /* keep it */ + } else { + pipe = lcdc_pipe; + } + + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->src_y = 0; + pipe->src_x = 0; + pipe->srcp0_addr = (uint32) buf; + pipe->srcp0_ystride = fbi->fix.line_length; + + mdp4_overlay_dmap_xy(pipe); + mdp4_overlay_dmap_cfg(mfd, 1); + + mdp4_overlay_rgb_setup(pipe); + + mdp4_mixer_stage_up(pipe); + + mdp4_overlayproc_cfg(pipe); + + /* + * LCDC timing setting + */ + h_back_porch = var->left_margin; + h_front_porch = var->right_margin; + v_back_porch = var->upper_margin; + v_front_porch = var->lower_margin; + hsync_pulse_width = var->hsync_len; + vsync_pulse_width = var->vsync_len; + lcdc_border_clr = mfd->panel_info.lcdc.border_clr; + lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr; + lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew; + + lcdc_width = mfd->panel_info.xres; + lcdc_height = mfd->panel_info.yres; + lcdc_bpp = mfd->panel_info.bpp; + + hsync_period = + hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch; + hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; + hsync_start_x = hsync_pulse_width + h_back_porch; + hsync_end_x = hsync_period - h_front_porch - 1; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + + vsync_period = + (vsync_pulse_width + v_back_porch + lcdc_height + + v_front_porch) * hsync_period; + display_v_start = + (vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew; + display_v_end = + vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1; + + if (lcdc_width != var->xres) { + active_h_start = hsync_start_x + first_pixel_start_x; + active_h_end = active_h_start + var->xres - 1; + active_hctl = + ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; + } else { + active_hctl = 0; + } + + if (lcdc_height != var->yres) { + active_v_start = + display_v_start + first_pixel_start_y * hsync_period; + active_v_end = active_v_start + (var->yres) * hsync_period - 1; + active_v_start |= ACTIVE_START_Y_EN; + } else { + active_v_start = 0; + active_v_end = 0; + } + + +#ifdef CONFIG_FB_MSM_MDP40 + hsync_polarity = 1; + vsync_polarity = 1; + lcdc_underflow_clr |= 0x80000000; /* enable recovery */ +#else + hsync_polarity = 0; + vsync_polarity = 0; +#endif + data_en_polarity = 0; + + ctrl_polarity = + (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); + + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x4, hsync_ctrl); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x8, vsync_period); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0xc, vsync_pulse_width * hsync_period); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x10, display_hctl); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x14, display_v_start); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x18, display_v_end); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x28, lcdc_border_clr); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x2c, lcdc_underflow_clr); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x30, lcdc_hsync_skew); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x38, ctrl_polarity); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x1c, active_hctl); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x20, active_v_start); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end); + + ret = panel_next_on(pdev); + if (ret == 0) { + /* enable LCDC block */ + MDP_OUTP(MDP_BASE + LCDC_BASE, 1); + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + } + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return ret; +} + +int mdp_lcdc_off(struct platform_device *pdev) +{ + int ret = 0; + struct mdp4_overlay_pipe *pipe; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + LCDC_BASE, 0); + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + ret = panel_next_off(pdev); + + /* delay to make sure the last frame finishes */ + mdelay(100); + + /* dis-engage rgb0 from mixer */ + pipe = lcdc_pipe; + mdp4_mixer_stage_down(pipe); + + return ret; +} + +/* + * mdp4_overlay0_done_lcdc: called from isr + */ +void mdp4_overlay0_done_lcdc() +{ + complete(&lcdc_pipe->comp); +} + +void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi = mfd->fbi; + uint8 *buf; + int bpp; + unsigned long flag; + struct mdp4_overlay_pipe *pipe; + + if (!mfd->panel_power_on) + return; + + /* no need to power on cmd block since it's lcdc mode */ + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf += fbi->var.xoffset * bpp + + fbi->var.yoffset * fbi->fix.line_length; + + mutex_lock(&mfd->dma->ov_mutex); + + pipe = lcdc_pipe; + pipe->srcp0_addr = (uint32) buf; + mdp4_overlay_rgb_setup(pipe); + mdp4_overlay_reg_flush(pipe, 1); /* rgb1 and mixer0 */ + + /* enable irq */ + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(MDP_OVERLAY0_TERM); + INIT_COMPLETION(lcdc_pipe->comp); + mfd->dma->waiting = TRUE; + outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE); + mdp_intr_mask |= INTR_OVERLAY0_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + wait_for_completion_killable(&lcdc_pipe->comp); + mdp_disable_irq(MDP_OVERLAY0_TERM); + + mutex_unlock(&mfd->dma->ov_mutex); +} diff --git a/drivers/staging/msm/mdp4_overlay_mddi.c b/drivers/staging/msm/mdp4_overlay_mddi.c new file mode 100644 index 000000000000..be1b2874185b --- /dev/null +++ b/drivers/staging/msm/mdp4_overlay_mddi.c @@ -0,0 +1,254 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/hrtimer.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/spinlock.h> + +#include <linux/fb.h> + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +static struct mdp4_overlay_pipe *mddi_pipe; +static struct mdp4_overlay_pipe *pending_pipe; +static struct msm_fb_data_type *mddi_mfd; + +#define WHOLESCREEN + +void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd) +{ + MDPIBUF *iBuf = &mfd->ibuf; + uint8 *src; + int bpp, ptype; + uint32 format; + uint32 mddi_ld_param; + uint16 mddi_vdo_packet_reg; + struct mdp4_overlay_pipe *pipe; + + if (mfd->key != MFD_KEY) + return; + + mddi_mfd = mfd; /* keep it */ + + bpp = iBuf->bpp; + + if (bpp == 2) + format = MDP_RGB_565; + else if (bpp == 3) + format = MDP_RGB_888; + else + format = MDP_ARGB_8888; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + if (mddi_pipe == NULL) { + ptype = mdp4_overlay_format2type(format); + pipe = mdp4_overlay_pipe_alloc(); + pipe->pipe_type = ptype; + /* use RGB1 pipe */ + pipe->pipe_num = OVERLAY_PIPE_RGB1; + pipe->mixer_num = MDP4_MIXER0; + pipe->src_format = format; + mdp4_overlay_format2pipe(pipe); + + mddi_pipe = pipe; /* keep it */ + + mddi_ld_param = 0; + mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt; + + if (mfd->panel_info.type == MDDI_PANEL) { + if (mfd->panel_info.pdest == DISPLAY_1) + mddi_ld_param = 0; + else + mddi_ld_param = 1; + } else { + mddi_ld_param = 2; + } + + MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param); + MDP_OUTP(MDP_BASE + 0x00094, + (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); + } else { + pipe = mddi_pipe; + } + + + src = (uint8 *) iBuf->buf; + +#ifdef WHOLESCREEN + { + struct fb_info *fbi; + + fbi = mfd->fbi; + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_h = fbi->var.yres; + pipe->dst_w = fbi->var.xres; + pipe->dst_y = 0; + pipe->dst_x = 0; + pipe->srcp0_addr = (uint32)src; + pipe->srcp0_ystride = fbi->var.xres_virtual * bpp; + } + +#else + if (mdp4_overlay_active(MDP4_MIXER0)) { + struct fb_info *fbi; + + fbi = mfd->fbi; + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_h = fbi->var.yres; + pipe->dst_w = fbi->var.xres; + pipe->dst_y = 0; + pipe->dst_x = 0; + pipe->srcp0_addr = (uint32) src; + pipe->srcp0_ystride = fbi->var.xres_virtual * bpp; + } else { + /* starting input address */ + src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * bpp; + + pipe->src_height = iBuf->dma_h; + pipe->src_width = iBuf->dma_w; + pipe->src_h = iBuf->dma_h; + pipe->src_w = iBuf->dma_w; + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_h = iBuf->dma_h; + pipe->dst_w = iBuf->dma_w; + pipe->dst_y = iBuf->dma_y; + pipe->dst_x = iBuf->dma_x; + pipe->srcp0_addr = (uint32) src; + pipe->srcp0_ystride = iBuf->ibuf_width * bpp; + } +#endif + + pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + + mdp4_overlay_rgb_setup(pipe); + + mdp4_mixer_stage_up(pipe); + + mdp4_overlayproc_cfg(pipe); + + mdp4_overlay_dmap_xy(pipe); + + mdp4_overlay_dmap_cfg(mfd, 0); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + +} + +/* + * mdp4_overlay0_done_mddi: called from isr + */ +void mdp4_overlay0_done_mddi() +{ + if (pending_pipe) + complete(&pending_pipe->comp); +} + +void mdp4_mddi_overlay_restore(void) +{ + /* mutex holded by caller */ + mdp4_overlay_update_lcd(mddi_mfd); + mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe); +} + +void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ +#ifdef MDP4_NONBLOCKING + unsigned long flag; + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (mfd->dma->busy == TRUE) { + INIT_COMPLETION(pipe->comp); + pending_pipe = pipe; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (pending_pipe != NULL) { + /* wait until DMA finishes the current job */ + wait_for_completion_killable(&pipe->comp); + pending_pipe = NULL; + } + down(&mfd->sem); + mdp_enable_irq(MDP_OVERLAY0_TERM); + mfd->dma->busy = TRUE; + /* start OVERLAY pipe */ + mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd); + up(&mfd->sem); +#else + down(&mfd->sem); + mdp_enable_irq(MDP_OVERLAY0_TERM); + mfd->dma->busy = TRUE; + INIT_COMPLETION(pipe->comp); + pending_pipe = pipe; + + /* start OVERLAY pipe */ + mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd); + up(&mfd->sem); + + /* wait until DMA finishes the current job */ + wait_for_completion_killable(&pipe->comp); + mdp_disable_irq(MDP_OVERLAY0_TERM); +#endif + +} + +void mdp4_mddi_overlay(struct msm_fb_data_type *mfd) +{ + mutex_lock(&mfd->dma->ov_mutex); + + if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) { + mdp4_overlay_update_lcd(mfd); + + mdp4_mddi_overlay_kickoff(mfd, mddi_pipe); + + /* signal if pan function is waiting for the update completion */ + if (mfd->pan_waiting) { + mfd->pan_waiting = FALSE; + complete(&mfd->pan_comp); + } + } + + mutex_unlock(&mfd->dma->ov_mutex); +} diff --git a/drivers/staging/msm/mdp4_util.c b/drivers/staging/msm/mdp4_util.c new file mode 100644 index 000000000000..fd97f5205992 --- /dev/null +++ b/drivers/staging/msm/mdp4_util.c @@ -0,0 +1,1686 @@ + +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/clk.h> +#include <mach/hardware.h> +#include <linux/io.h> +#include <linux/debugfs.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +void mdp4_sw_reset(ulong bits) +{ + bits &= 0x1f; /* 5 bits */ + outpdw(MDP_BASE + 0x001c, bits); /* MDP_SW_RESET */ + + while (inpdw(MDP_BASE + 0x001c) & bits) /* self clear when complete */ + ; + MSM_FB_INFO("mdp4_sw_reset: 0x%x\n", (int)bits); +} + +void mdp4_overlay_cfg(int overlayer, int blt_mode, int refresh, int direct_out) +{ + ulong bits = 0; + + if (blt_mode) + bits |= (1 << 3); + refresh &= 0x03; /* 2 bites */ + bits |= (refresh << 1); + direct_out &= 0x01; + bits |= direct_out; + + if (overlayer == MDP4_MIXER0) + outpdw(MDP_BASE + 0x10004, bits); /* MDP_OVERLAY0_CFG */ + else + outpdw(MDP_BASE + 0x18004, bits); /* MDP_OVERLAY1_CFG */ + + MSM_FB_INFO("mdp4_overlay_cfg: 0x%x\n", (int)inpdw(MDP_BASE + 0x10004)); +} + +void mdp4_display_intf_sel(int output, ulong intf) +{ + ulong bits, mask; + + bits = inpdw(MDP_BASE + 0x0038); /* MDP_DISP_INTF_SEL */ + + mask = 0x03; /* 2 bits */ + intf &= 0x03; /* 2 bits */ + + switch (output) { + case EXTERNAL_INTF_SEL: + intf <<= 4; + mask <<= 4; + break; + case SECONDARY_INTF_SEL: + intf &= 0x02; /* only MDDI and EBI2 support */ + intf <<= 2; + mask <<= 2; + break; + default: + break; + } + + + bits &= ~mask; + bits |= intf; + + outpdw(MDP_BASE + 0x0038, bits); /* MDP_DISP_INTF_SEL */ + + MSM_FB_INFO("mdp4_display_intf_sel: 0x%x\n", (int)inpdw(MDP_BASE + 0x0038)); +} + +unsigned long mdp4_display_status(void) +{ + return inpdw(MDP_BASE + 0x0018) & 0x3ff; /* MDP_DISPLAY_STATUS */ +} + +void mdp4_ebi2_lcd_setup(int lcd, ulong base, int ystride) +{ + /* always use memory map */ + ystride &= 0x01fff; /* 13 bits */ + if (lcd == EBI2_LCD0) { + outpdw(MDP_BASE + 0x0060, base);/* MDP_EBI2_LCD0 */ + outpdw(MDP_BASE + 0x0068, ystride);/* MDP_EBI2_LCD0_YSTRIDE */ + } else { + outpdw(MDP_BASE + 0x0064, base);/* MDP_EBI2_LCD1 */ + outpdw(MDP_BASE + 0x006c, ystride);/* MDP_EBI2_LCD1_YSTRIDE */ + } +} + +void mdp4_mddi_setup(int mddi, unsigned long id) +{ + ulong bits; + + if (mddi == MDDI_EXTERNAL_SET) + bits = 0x02; + else if (mddi == MDDI_SECONDARY_SET) + bits = 0x01; + else + bits = 0; /* PRIMARY_SET */ + + id <<= 16; + + bits |= id; + + outpdw(MDP_BASE + 0x0090, bits); /* MDP_MDDI_PARAM_WR_SEL */ +} + +int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req, + struct file **pp_src_file, struct file **pp_dst_file) +{ + + /* not implemented yet */ + return -1; +} + +void mdp4_hw_init(void) +{ + ulong bits; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + +#ifdef MDP4_ERROR + /* + * Issue software reset on DMA_P will casue DMA_P dma engine stall + * on LCDC mode. However DMA_P does not stall at MDDI mode. + * This need further investigation. + */ + mdp4_sw_reset(0x17); +#endif + + mdp4_clear_lcdc(); + + mdp4_mixer_blend_init(0); + mdp4_mixer_blend_init(1); + mdp4_vg_qseed_init(0); + mdp4_vg_qseed_init(1); + mdp4_vg_csc_mv_setup(0); + mdp4_vg_csc_mv_setup(1); + mdp4_vg_csc_pre_bv_setup(0); + mdp4_vg_csc_pre_bv_setup(1); + mdp4_vg_csc_post_bv_setup(0); + mdp4_vg_csc_post_bv_setup(1); + mdp4_vg_csc_pre_lv_setup(0); + mdp4_vg_csc_pre_lv_setup(1); + mdp4_vg_csc_post_lv_setup(0); + mdp4_vg_csc_post_lv_setup(1); + + mdp4_mixer_gc_lut_setup(0); + mdp4_mixer_gc_lut_setup(1); + + mdp4_vg_igc_lut_setup(0); + mdp4_vg_igc_lut_setup(1); + + mdp4_rgb_igc_lut_setup(0); + mdp4_rgb_igc_lut_setup(1); + + outp32(MDP_EBI2_PORTMAP_MODE, 0x3); + + /* system interrupts */ + + bits = mdp_intr_mask; + outpdw(MDP_BASE + 0x0050, bits);/* enable specififed interrupts */ + + /* histogram */ + MDP_OUTP(MDP_BASE + 0x95010, 1); /* auto clear HIST */ + + /* enable histogram interrupts */ + outpdw(MDP_BASE + 0x9501c, INTR_HIST_DONE); + + /* For the max read pending cmd config below, if the MDP clock */ + /* is less than the AXI clock, then we must use 3 pending */ + /* pending requests. Otherwise, we should use 8 pending requests. */ + /* In the future we should do this detection automatically. */ + + /* max read pending cmd config */ + outpdw(MDP_BASE + 0x004c, 0x02222); /* 3 pending requests */ + + /* dma_p fetch config */ + outpdw(MDP_BASE + 0x91004, 0x27); /* burst size of 8 */ + +#ifndef CONFIG_FB_MSM_OVERLAY + /* both REFRESH_MODE and DIRECT_OUT are ignored at BLT mode */ + mdp4_overlay_cfg(MDP4_MIXER0, OVERLAY_MODE_BLT, 0, 0); + mdp4_overlay_cfg(MDP4_MIXER1, OVERLAY_MODE_BLT, 0, 0); +#endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + + +void mdp4_clear_lcdc(void) +{ + uint32 bits; + + bits = inpdw(MDP_BASE + 0xc0000); + if (bits & 0x01) /* enabled already */ + return; + + outpdw(MDP_BASE + 0xc0004, 0); /* vsync ctrl out */ + outpdw(MDP_BASE + 0xc0008, 0); /* vsync period */ + outpdw(MDP_BASE + 0xc000c, 0); /* vsync pusle width */ + outpdw(MDP_BASE + 0xc0010, 0); /* lcdc display HCTL */ + outpdw(MDP_BASE + 0xc0014, 0); /* lcdc display v start */ + outpdw(MDP_BASE + 0xc0018, 0); /* lcdc display v end */ + outpdw(MDP_BASE + 0xc001c, 0); /* lcdc active hctl */ + outpdw(MDP_BASE + 0xc0020, 0); /* lcdc active v start */ + outpdw(MDP_BASE + 0xc0024, 0); /* lcdc active v end */ + outpdw(MDP_BASE + 0xc0028, 0); /* lcdc board color */ + outpdw(MDP_BASE + 0xc002c, 0); /* lcdc underflow ctrl */ + outpdw(MDP_BASE + 0xc0030, 0); /* lcdc hsync skew */ + outpdw(MDP_BASE + 0xc0034, 0); /* lcdc test ctl */ + outpdw(MDP_BASE + 0xc0038, 0); /* lcdc ctl polarity */ +} + +static struct mdp_dma_data overlay1_data; +static int intr_dma_p; +static int intr_dma_s; +static int intr_dma_e; +static int intr_overlay0; +static int intr_overlay1; + +irqreturn_t mdp4_isr(int irq, void *ptr) +{ + uint32 isr, mask, lcdc; + struct mdp_dma_data *dma; + + mdp_is_in_isr = TRUE; + + while (1) { + isr = inpdw(MDP_INTR_STATUS); + if (isr == 0) + break; + + mask = inpdw(MDP_INTR_ENABLE); + outpdw(MDP_INTR_CLEAR, isr); + + isr &= mask; + + if (unlikely(isr == 0)) + break; + + if (isr & INTR_DMA_P_DONE) { + intr_dma_p++; + lcdc = inpdw(MDP_BASE + 0xc0000); + dma = &dma2_data; + if (lcdc & 0x01) { /* LCDC enable */ + /* disable LCDC interrupt */ + mdp_intr_mask &= ~INTR_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + } else { + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA2_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + } + complete(&dma->comp); + } + if (isr & INTR_DMA_S_DONE) { + intr_dma_s++; + dma = &dma_s_data; + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + complete(&dma->comp); + } + if (isr & INTR_DMA_E_DONE) { + intr_dma_e++; + dma = &dma_e_data; + mdp_intr_mask &= ~INTR_DMA_E_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->busy = FALSE; + + if (dma->waiting) { + dma->waiting = FALSE; + complete(&dma->comp); + } + } + if (isr & INTR_OVERLAY0_DONE) { + intr_overlay0++; + lcdc = inpdw(MDP_BASE + 0xc0000); + dma = &dma2_data; + if (lcdc & 0x01) { /* LCDC enable */ + /* disable LCDC interrupt */ + mdp_intr_mask &= ~INTR_OVERLAY0_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + mdp4_overlay0_done_lcdc(); + } else { /* MDDI */ + dma->busy = FALSE; +#ifdef MDP4_NONBLOCKING + mdp_disable_irq_nolock(MDP_OVERLAY0_TERM); +#endif + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + mdp4_overlay0_done_mddi(); + } + } + if (isr & INTR_OVERLAY1_DONE) { + intr_overlay1++; + dma = &overlay1_data; + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + complete(&dma->comp); + } + if (isr & INTR_DMA_P_HISTOGRAM) { + isr = inpdw(MDP_DMA_P_HIST_INTR_STATUS); + mask = inpdw(MDP_DMA_P_HIST_INTR_ENABLE); + outpdw(MDP_DMA_P_HIST_INTR_CLEAR, isr); + isr &= mask; + if (isr & INTR_HIST_DONE) { + if (mdp_hist.r) + memcpy(mdp_hist.r, MDP_BASE + 0x95100, + mdp_hist.bin_cnt*4); + if (mdp_hist.g) + memcpy(mdp_hist.g, MDP_BASE + 0x95200, + mdp_hist.bin_cnt*4); + if (mdp_hist.b) + memcpy(mdp_hist.b, MDP_BASE + 0x95300, + mdp_hist.bin_cnt*4); + complete(&mdp_hist_comp); + } + } + } + + mdp_is_in_isr = FALSE; + + return IRQ_HANDLED; +} + + +/* + * QSEED tables + */ + +static uint32 vg_qseed_table0[] = { + 0x5556aaff, 0x00000000, 0x00000000, 0x00000000 +}; + +static uint32 vg_qseed_table1[] = { + 0x76543210, 0xfedcba98 +}; + +static uint32 vg_qseed_table2[] = { + 0x02000000, 0x00000000, 0x02060ff2, 0x00000008, + 0x02090fe4, 0x00000013, 0x020a0fd9, 0x0ffc0021, + 0x02080fce, 0x0ffa0030, 0x02030fc5, 0x0ff60042, + 0x01fd0fbe, 0x0ff10054, 0x01f50fb6, 0x0fed0068, + 0x01e90fb1, 0x0fe60080, 0x01dc0fae, 0x0fe10095, + 0x01ca0fae, 0x0fda00ae, 0x01b70fad, 0x0fd600c6, + 0x01a40fad, 0x0fcf00e0, 0x018f0faf, 0x0fc800fa, + 0x01780fb1, 0x0fc30114, 0x015f0fb5, 0x0fbf012d, + 0x01490fb7, 0x0fb70149, 0x012d0fbf, 0x0fb5015f, + 0x01140fc3, 0x0fb10178, 0x00fa0fc8, 0x0faf018f, + 0x00e00fcf, 0x0fad01a4, 0x00c60fd6, 0x0fad01b7, + 0x00ae0fda, 0x0fae01ca, 0x00950fe1, 0x0fae01dc, + 0x00800fe6, 0x0fb101e9, 0x00680fed, 0x0fb601f5, + 0x00540ff1, 0x0fbe01fd, 0x00420ff6, 0x0fc50203, + 0x00300ffa, 0x0fce0208, 0x00210ffc, 0x0fd9020a, + 0x00130000, 0x0fe40209, 0x00080000, 0x0ff20206, + 0x02000000, 0x00000000, 0x02040ff2, 0x0000000a, + 0x02040fe4, 0x00000018, 0x02010fda, 0x0ffc0029, + 0x01fc0fcf, 0x0ffa003b, 0x01f30fc7, 0x0ff60050, + 0x01e90fc0, 0x0ff20065, 0x01dc0fba, 0x0fee007c, + 0x01cc0fb6, 0x0fe80096, 0x01ba0fb4, 0x0fe400ae, + 0x01a70fb4, 0x0fdd00c8, 0x018f0fb5, 0x0fda00e2, + 0x017a0fb5, 0x0fd400fd, 0x01630fb8, 0x0fce0117, + 0x014c0fba, 0x0fca0130, 0x01320fbf, 0x0fc70148, + 0x011b0fc1, 0x0fc10163, 0x01010fc8, 0x0fc00177, + 0x00e90fcd, 0x0fbd018d, 0x00d10fd1, 0x0fbc01a2, + 0x00ba0fd7, 0x0fbb01b4, 0x00a30fdd, 0x0fbc01c4, + 0x008e0fe1, 0x0fbd01d4, 0x00790fe7, 0x0fbe01e2, + 0x00670feb, 0x0fc001ee, 0x00540ff1, 0x0fc501f6, + 0x00430ff4, 0x0fcb01fe, 0x00340ff8, 0x0fd10203, + 0x00260ffb, 0x0fd80207, 0x001a0ffd, 0x0fe10208, + 0x000f0000, 0x0fea0207, 0x00060000, 0x0ff50205, + 0x02000000, 0x00000000, 0x02020ff2, 0x0000000c, + 0x02000fe4, 0x0000001c, 0x01fa0fda, 0x0ffc0030, + 0x01f10fd0, 0x0ffa0045, 0x01e50fc8, 0x0ff6005d, + 0x01d60fc3, 0x0ff30074, 0x01c60fbd, 0x0fef008e, + 0x01b30fba, 0x0fe900aa, 0x019e0fb9, 0x0fe500c4, + 0x01870fba, 0x0fe000df, 0x016f0fbb, 0x0fdd00f9, + 0x01580fbc, 0x0fd80114, 0x01400fbf, 0x0fd3012e, + 0x01280fc2, 0x0fd00146, 0x010f0fc6, 0x0fce015d, + 0x00f90fc9, 0x0fc90175, 0x00e00fcf, 0x0fc90188, + 0x00ca0fd4, 0x0fc6019c, 0x00b40fd8, 0x0fc601ae, + 0x009f0fdd, 0x0fc501bf, 0x008b0fe3, 0x0fc601cc, + 0x00780fe6, 0x0fc701db, 0x00660feb, 0x0fc801e7, + 0x00560fef, 0x0fcb01f0, 0x00460ff3, 0x0fcf01f8, + 0x00380ff6, 0x0fd401fe, 0x002c0ff9, 0x0fd90202, + 0x00200ffc, 0x0fdf0205, 0x00160ffe, 0x0fe60206, + 0x000c0000, 0x0fed0207, 0x00050000, 0x0ff70204, + 0x02000000, 0x00000000, 0x01fe0ff3, 0x0000000f, + 0x01f60fe5, 0x00000025, 0x01ea0fdb, 0x0ffd003e, + 0x01db0fd2, 0x0ffb0058, 0x01c80fcc, 0x0ff70075, + 0x01b50fc7, 0x0ff40090, 0x01a00fc3, 0x0ff000ad, + 0x01880fc1, 0x0feb00cc, 0x01700fc1, 0x0fe800e7, + 0x01550fc3, 0x0fe40104, 0x013b0fc5, 0x0fe2011e, + 0x01240fc6, 0x0fde0138, 0x010c0fca, 0x0fda0150, + 0x00f40fcd, 0x0fd90166, 0x00dd0fd1, 0x0fd7017b, + 0x00c80fd4, 0x0fd40190, 0x00b20fd9, 0x0fd401a1, + 0x009f0fdd, 0x0fd301b1, 0x008c0fe1, 0x0fd301c0, + 0x007b0fe5, 0x0fd301cd, 0x006a0fea, 0x0fd401d8, + 0x005c0fec, 0x0fd501e3, 0x004d0ff0, 0x0fd601ed, + 0x00410ff3, 0x0fd801f4, 0x00340ff7, 0x0fdb01fa, + 0x002a0ff9, 0x0fdf01fe, 0x00200ffb, 0x0fe30202, + 0x00180ffd, 0x0fe70204, 0x00100ffe, 0x0fed0205, + 0x00090000, 0x0ff20205, 0x00040000, 0x0ff90203, + 0x02000000, 0x00000000, 0x02050ff5, 0x00000006, + 0x02070fea, 0x0000000f, 0x02080fe1, 0x0ffd001a, + 0x02070fd8, 0x0ffb0026, 0x02030fd1, 0x0ff80034, + 0x01fe0fcb, 0x0ff40043, 0x01f60fc5, 0x0ff10054, + 0x01ee0fc0, 0x0feb0067, 0x01e20fbe, 0x0fe70079, + 0x01d40fbd, 0x0fe1008e, 0x01c40fbc, 0x0fdd00a3, + 0x01b40fbb, 0x0fd700ba, 0x01a20fbc, 0x0fd100d1, + 0x018d0fbd, 0x0fcd00e9, 0x01770fc0, 0x0fc80101, + 0x01630fc1, 0x0fc1011b, 0x01480fc7, 0x0fbf0132, + 0x01300fca, 0x0fba014c, 0x01170fce, 0x0fb80163, + 0x00fd0fd4, 0x0fb5017a, 0x00e20fda, 0x0fb5018f, + 0x00c80fdd, 0x0fb401a7, 0x00ae0fe4, 0x0fb401ba, + 0x00960fe8, 0x0fb601cc, 0x007c0fee, 0x0fba01dc, + 0x00650ff2, 0x0fc001e9, 0x00500ff6, 0x0fc701f3, + 0x003b0ffa, 0x0fcf01fc, 0x00290ffc, 0x0fda0201, + 0x00180000, 0x0fe40204, 0x000a0000, 0x0ff20204, + 0x02000000, 0x00000000, 0x02030ff5, 0x00000008, + 0x02030fea, 0x00000013, 0x02020fe1, 0x0ffd0020, + 0x01fc0fd9, 0x0ffc002f, 0x01f60fd2, 0x0ff80040, + 0x01ed0fcd, 0x0ff50051, 0x01e30fc7, 0x0ff10065, + 0x01d70fc3, 0x0fec007a, 0x01c60fc2, 0x0fe9008f, + 0x01b60fc1, 0x0fe300a6, 0x01a20fc1, 0x0fe000bd, + 0x018f0fc1, 0x0fdb00d5, 0x017b0fc2, 0x0fd500ee, + 0x01640fc4, 0x0fd20106, 0x014d0fc8, 0x0fce011d, + 0x01370fc9, 0x0fc90137, 0x011d0fce, 0x0fc8014d, + 0x01060fd2, 0x0fc40164, 0x00ee0fd5, 0x0fc2017b, + 0x00d50fdb, 0x0fc1018f, 0x00bd0fe0, 0x0fc101a2, + 0x00a60fe3, 0x0fc101b6, 0x008f0fe9, 0x0fc201c6, + 0x007a0fec, 0x0fc301d7, 0x00650ff1, 0x0fc701e3, + 0x00510ff5, 0x0fcd01ed, 0x00400ff8, 0x0fd201f6, + 0x002f0ffc, 0x0fd901fc, 0x00200ffd, 0x0fe10202, + 0x00130000, 0x0fea0203, 0x00080000, 0x0ff50203, + 0x02000000, 0x00000000, 0x02020ff5, 0x00000009, + 0x01ff0fea, 0x00000017, 0x01fb0fe2, 0x0ffd0026, + 0x01f30fda, 0x0ffc0037, 0x01ea0fd3, 0x0ff8004b, + 0x01df0fce, 0x0ff5005e, 0x01d10fc9, 0x0ff20074, + 0x01c10fc6, 0x0fed008c, 0x01ae0fc5, 0x0fea00a3, + 0x019b0fc5, 0x0fe500bb, 0x01850fc6, 0x0fe200d3, + 0x01700fc6, 0x0fde00ec, 0x015a0fc8, 0x0fd90105, + 0x01430fca, 0x0fd6011d, 0x012b0fcd, 0x0fd30135, + 0x01150fcf, 0x0fcf014d, 0x00fc0fd4, 0x0fce0162, + 0x00e50fd8, 0x0fcc0177, 0x00cf0fdb, 0x0fca018c, + 0x00b80fe0, 0x0fc9019f, 0x00a20fe5, 0x0fca01af, + 0x008e0fe8, 0x0fcb01bf, 0x00790fec, 0x0fcb01d0, + 0x00670fef, 0x0fcd01dd, 0x00550ff4, 0x0fd001e7, + 0x00440ff7, 0x0fd501f0, 0x00350ffa, 0x0fda01f7, + 0x00270ffc, 0x0fdf01fe, 0x001b0ffe, 0x0fe70200, + 0x00100000, 0x0fee0202, 0x00060000, 0x0ff70203, + 0x02000000, 0x00000000, 0x01ff0ff5, 0x0000000c, + 0x01f80fea, 0x0000001e, 0x01ef0fe2, 0x0ffd0032, + 0x01e20fdb, 0x0ffc0047, 0x01d30fd5, 0x0ff9005f, + 0x01c20fd1, 0x0ff60077, 0x01b00fcd, 0x0ff30090, + 0x019b0fcb, 0x0fef00ab, 0x01850fcb, 0x0fec00c4, + 0x016e0fcc, 0x0fe800de, 0x01550fcd, 0x0fe600f8, + 0x013f0fce, 0x0fe20111, 0x01280fd0, 0x0fdf0129, + 0x01110fd2, 0x0fdd0140, 0x00f90fd6, 0x0fdb0156, + 0x00e40fd8, 0x0fd8016c, 0x00cd0fdd, 0x0fd8017e, + 0x00b80fe0, 0x0fd60192, 0x00a40fe3, 0x0fd601a3, + 0x00910fe7, 0x0fd501b3, 0x007f0feb, 0x0fd601c0, + 0x006e0fed, 0x0fd701ce, 0x005d0ff1, 0x0fd701db, + 0x004f0ff3, 0x0fd901e5, 0x00400ff7, 0x0fdc01ed, + 0x00330ff9, 0x0fe001f4, 0x00280ffb, 0x0fe301fa, + 0x001d0ffd, 0x0fe801fe, 0x00140ffe, 0x0fed0201, + 0x000c0000, 0x0ff20202, 0x00050000, 0x0ff90202, + 0x02000000, 0x00000000, 0x02040ff7, 0x00000005, + 0x02070fed, 0x0000000c, 0x02060fe6, 0x0ffe0016, + 0x02050fdf, 0x0ffc0020, 0x02020fd9, 0x0ff9002c, + 0x01fe0fd4, 0x0ff60038, 0x01f80fcf, 0x0ff30046, + 0x01f00fcb, 0x0fef0056, 0x01e70fc8, 0x0feb0066, + 0x01db0fc7, 0x0fe60078, 0x01cc0fc6, 0x0fe3008b, + 0x01bf0fc5, 0x0fdd009f, 0x01ae0fc6, 0x0fd800b4, + 0x019c0fc6, 0x0fd400ca, 0x01880fc9, 0x0fcf00e0, + 0x01750fc9, 0x0fc900f9, 0x015d0fce, 0x0fc6010f, + 0x01460fd0, 0x0fc20128, 0x012e0fd3, 0x0fbf0140, + 0x01140fd8, 0x0fbc0158, 0x00f90fdd, 0x0fbb016f, + 0x00df0fe0, 0x0fba0187, 0x00c40fe5, 0x0fb9019e, + 0x00aa0fe9, 0x0fba01b3, 0x008e0fef, 0x0fbd01c6, + 0x00740ff3, 0x0fc301d6, 0x005d0ff6, 0x0fc801e5, + 0x00450ffa, 0x0fd001f1, 0x00300ffc, 0x0fda01fa, + 0x001c0000, 0x0fe40200, 0x000c0000, 0x0ff20202, + 0x02000000, 0x00000000, 0x02030ff7, 0x00000006, + 0x02020fee, 0x00000010, 0x02000fe7, 0x0ffe001b, + 0x01fe0fdf, 0x0ffc0027, 0x01f70fda, 0x0ffa0035, + 0x01f00fd5, 0x0ff70044, 0x01e70fd0, 0x0ff40055, + 0x01dd0fcd, 0x0fef0067, 0x01d00fcb, 0x0fec0079, + 0x01bf0fcb, 0x0fe8008e, 0x01af0fca, 0x0fe500a2, + 0x019f0fc9, 0x0fe000b8, 0x018c0fca, 0x0fdb00cf, + 0x01770fcc, 0x0fd800e5, 0x01620fce, 0x0fd400fc, + 0x014d0fcf, 0x0fcf0115, 0x01350fd3, 0x0fcd012b, + 0x011d0fd6, 0x0fca0143, 0x01050fd9, 0x0fc8015a, + 0x00ec0fde, 0x0fc60170, 0x00d30fe2, 0x0fc60185, + 0x00bb0fe5, 0x0fc5019b, 0x00a30fea, 0x0fc501ae, + 0x008c0fed, 0x0fc601c1, 0x00740ff2, 0x0fc901d1, + 0x005e0ff5, 0x0fce01df, 0x004b0ff8, 0x0fd301ea, + 0x00370ffc, 0x0fda01f3, 0x00260ffd, 0x0fe201fb, + 0x00170000, 0x0fea01ff, 0x00090000, 0x0ff50202, + 0x02000000, 0x00000000, 0x02010ff7, 0x00000008, + 0x01ff0fee, 0x00000013, 0x01fb0fe7, 0x0ffe0020, + 0x01f60fe0, 0x0ffc002e, 0x01ed0fda, 0x0ffa003f, + 0x01e40fd6, 0x0ff7004f, 0x01d80fd2, 0x0ff40062, + 0x01ca0fcf, 0x0ff00077, 0x01bb0fcd, 0x0fed008b, + 0x01a90fcd, 0x0fe900a1, 0x01960fcd, 0x0fe600b7, + 0x01830fcd, 0x0fe200ce, 0x016d0fcf, 0x0fde00e6, + 0x01580fd0, 0x0fdb00fd, 0x01410fd3, 0x0fd80114, + 0x012c0fd4, 0x0fd4012c, 0x01140fd8, 0x0fd30141, + 0x00fd0fdb, 0x0fd00158, 0x00e60fde, 0x0fcf016d, + 0x00ce0fe2, 0x0fcd0183, 0x00b70fe6, 0x0fcd0196, + 0x00a10fe9, 0x0fcd01a9, 0x008b0fed, 0x0fcd01bb, + 0x00770ff0, 0x0fcf01ca, 0x00620ff4, 0x0fd201d8, + 0x004f0ff7, 0x0fd601e4, 0x003f0ffa, 0x0fda01ed, + 0x002e0ffc, 0x0fe001f6, 0x00200ffe, 0x0fe701fb, + 0x00130000, 0x0fee01ff, 0x00080000, 0x0ff70201, + 0x02000000, 0x00000000, 0x01ff0ff7, 0x0000000a, + 0x01f90fee, 0x00000019, 0x01f10fe7, 0x0ffe002a, + 0x01e60fe1, 0x0ffd003c, 0x01d90fdc, 0x0ffa0051, + 0x01cc0fd8, 0x0ff70065, 0x01bb0fd5, 0x0ff5007b, + 0x01a80fd3, 0x0ff10094, 0x01950fd2, 0x0fef00aa, + 0x01800fd2, 0x0feb00c3, 0x016a0fd3, 0x0fe900da, + 0x01540fd3, 0x0fe600f3, 0x013f0fd5, 0x0fe2010a, + 0x01280fd7, 0x0fe00121, 0x01100fda, 0x0fde0138, + 0x00fb0fdb, 0x0fdb014f, 0x00e40fdf, 0x0fdb0162, + 0x00ce0fe2, 0x0fd90177, 0x00b90fe4, 0x0fd8018b, + 0x00a50fe8, 0x0fd8019b, 0x00910fec, 0x0fd801ab, + 0x007e0fee, 0x0fd801bc, 0x006c0ff2, 0x0fd901c9, + 0x005c0ff4, 0x0fda01d6, 0x004b0ff7, 0x0fdd01e1, + 0x003c0ff9, 0x0fe001eb, 0x002f0ffb, 0x0fe401f2, + 0x00230ffd, 0x0fe801f8, 0x00180ffe, 0x0fed01fd, + 0x000e0000, 0x0ff20200, 0x00060000, 0x0ff90201, + 0x02000000, 0x00000000, 0x02030ff9, 0x00000004, + 0x02050ff2, 0x00000009, 0x02050fed, 0x0ffe0010, + 0x02040fe7, 0x0ffd0018, 0x02020fe3, 0x0ffb0020, + 0x01fe0fdf, 0x0ff9002a, 0x01fa0fdb, 0x0ff70034, + 0x01f40fd8, 0x0ff30041, 0x01ed0fd6, 0x0ff0004d, + 0x01e30fd5, 0x0fec005c, 0x01d80fd4, 0x0fea006a, + 0x01cd0fd3, 0x0fe5007b, 0x01c00fd3, 0x0fe1008c, + 0x01b10fd3, 0x0fdd009f, 0x01a10fd4, 0x0fd900b2, + 0x01900fd4, 0x0fd400c8, 0x017b0fd7, 0x0fd100dd, + 0x01660fd9, 0x0fcd00f4, 0x01500fda, 0x0fca010c, + 0x01380fde, 0x0fc60124, 0x011e0fe2, 0x0fc5013b, + 0x01040fe4, 0x0fc30155, 0x00e70fe8, 0x0fc10170, + 0x00cc0feb, 0x0fc10188, 0x00ad0ff0, 0x0fc301a0, + 0x00900ff4, 0x0fc701b5, 0x00750ff7, 0x0fcc01c8, + 0x00580ffb, 0x0fd201db, 0x003e0ffd, 0x0fdb01ea, + 0x00250000, 0x0fe501f6, 0x000f0000, 0x0ff301fe, + 0x02000000, 0x00000000, 0x02020ff9, 0x00000005, + 0x02020ff2, 0x0000000c, 0x02010fed, 0x0ffe0014, + 0x01fe0fe8, 0x0ffd001d, 0x01fa0fe3, 0x0ffb0028, + 0x01f40fe0, 0x0ff90033, 0x01ed0fdc, 0x0ff70040, + 0x01e50fd9, 0x0ff3004f, 0x01db0fd7, 0x0ff1005d, + 0x01ce0fd7, 0x0fed006e, 0x01c00fd6, 0x0feb007f, + 0x01b30fd5, 0x0fe70091, 0x01a30fd6, 0x0fe300a4, + 0x01920fd6, 0x0fe000b8, 0x017e0fd8, 0x0fdd00cd, + 0x016c0fd8, 0x0fd800e4, 0x01560fdb, 0x0fd600f9, + 0x01400fdd, 0x0fd20111, 0x01290fdf, 0x0fd00128, + 0x01110fe2, 0x0fce013f, 0x00f80fe6, 0x0fcd0155, + 0x00de0fe8, 0x0fcc016e, 0x00c40fec, 0x0fcb0185, + 0x00ab0fef, 0x0fcb019b, 0x00900ff3, 0x0fcd01b0, + 0x00770ff6, 0x0fd101c2, 0x005f0ff9, 0x0fd501d3, + 0x00470ffc, 0x0fdb01e2, 0x00320ffd, 0x0fe201ef, + 0x001e0000, 0x0fea01f8, 0x000c0000, 0x0ff501ff, + 0x02000000, 0x00000000, 0x02010ff9, 0x00000006, + 0x02000ff2, 0x0000000e, 0x01fd0fed, 0x0ffe0018, + 0x01f80fe8, 0x0ffd0023, 0x01f20fe4, 0x0ffb002f, + 0x01eb0fe0, 0x0ff9003c, 0x01e10fdd, 0x0ff7004b, + 0x01d60fda, 0x0ff4005c, 0x01c90fd9, 0x0ff2006c, + 0x01bc0fd8, 0x0fee007e, 0x01ab0fd8, 0x0fec0091, + 0x019b0fd8, 0x0fe800a5, 0x018b0fd8, 0x0fe400b9, + 0x01770fd9, 0x0fe200ce, 0x01620fdb, 0x0fdf00e4, + 0x014f0fdb, 0x0fdb00fb, 0x01380fde, 0x0fda0110, + 0x01210fe0, 0x0fd70128, 0x010a0fe2, 0x0fd5013f, + 0x00f30fe6, 0x0fd30154, 0x00da0fe9, 0x0fd3016a, + 0x00c30feb, 0x0fd20180, 0x00aa0fef, 0x0fd20195, + 0x00940ff1, 0x0fd301a8, 0x007b0ff5, 0x0fd501bb, + 0x00650ff7, 0x0fd801cc, 0x00510ffa, 0x0fdc01d9, + 0x003c0ffd, 0x0fe101e6, 0x002a0ffe, 0x0fe701f1, + 0x00190000, 0x0fee01f9, 0x000a0000, 0x0ff701ff, + 0x02000000, 0x00000000, 0x01ff0ff9, 0x00000008, + 0x01fb0ff2, 0x00000013, 0x01f50fed, 0x0ffe0020, + 0x01ed0fe8, 0x0ffd002e, 0x01e30fe4, 0x0ffb003e, + 0x01d80fe1, 0x0ff9004e, 0x01cb0fde, 0x0ff70060, + 0x01bc0fdc, 0x0ff40074, 0x01ac0fdb, 0x0ff20087, + 0x019a0fdb, 0x0fef009c, 0x01870fdb, 0x0fed00b1, + 0x01740fdb, 0x0fea00c7, 0x01600fdc, 0x0fe700dd, + 0x014b0fdd, 0x0fe500f3, 0x01350fdf, 0x0fe30109, + 0x01200fe0, 0x0fe00120, 0x01090fe3, 0x0fdf0135, + 0x00f30fe5, 0x0fdd014b, 0x00dd0fe7, 0x0fdc0160, + 0x00c70fea, 0x0fdb0174, 0x00b10fed, 0x0fdb0187, + 0x009c0fef, 0x0fdb019a, 0x00870ff2, 0x0fdb01ac, + 0x00740ff4, 0x0fdc01bc, 0x00600ff7, 0x0fde01cb, + 0x004e0ff9, 0x0fe101d8, 0x003e0ffb, 0x0fe401e3, + 0x002e0ffd, 0x0fe801ed, 0x00200ffe, 0x0fed01f5, + 0x00130000, 0x0ff201fb, 0x00080000, 0x0ff901ff, + 0x02000000, 0x00000000, 0x02060ff2, 0x00000008, + 0x02090fe4, 0x00000013, 0x020a0fd9, 0x0ffc0021, + 0x02080fce, 0x0ffa0030, 0x02030fc5, 0x0ff60042, + 0x01fd0fbe, 0x0ff10054, 0x01f50fb6, 0x0fed0068, + 0x01e90fb1, 0x0fe60080, 0x01dc0fae, 0x0fe10095, + 0x01ca0fae, 0x0fda00ae, 0x01b70fad, 0x0fd600c6, + 0x01a40fad, 0x0fcf00e0, 0x018f0faf, 0x0fc800fa, + 0x01780fb1, 0x0fc30114, 0x015f0fb5, 0x0fbf012d, + 0x01490fb7, 0x0fb70149, 0x012d0fbf, 0x0fb5015f, + 0x01140fc3, 0x0fb10178, 0x00fa0fc8, 0x0faf018f, + 0x00e00fcf, 0x0fad01a4, 0x00c60fd6, 0x0fad01b7, + 0x00ae0fda, 0x0fae01ca, 0x00950fe1, 0x0fae01dc, + 0x00800fe6, 0x0fb101e9, 0x00680fed, 0x0fb601f5, + 0x00540ff1, 0x0fbe01fd, 0x00420ff6, 0x0fc50203, + 0x00300ffa, 0x0fce0208, 0x00210ffc, 0x0fd9020a, + 0x00130000, 0x0fe40209, 0x00080000, 0x0ff20206, + 0x02000000, 0x00000000, 0x02040ff2, 0x0000000a, + 0x02040fe4, 0x00000018, 0x02010fda, 0x0ffc0029, + 0x01fc0fcf, 0x0ffa003b, 0x01f30fc7, 0x0ff60050, + 0x01e90fc0, 0x0ff20065, 0x01dc0fba, 0x0fee007c, + 0x01cc0fb6, 0x0fe80096, 0x01ba0fb4, 0x0fe400ae, + 0x01a70fb4, 0x0fdd00c8, 0x018f0fb5, 0x0fda00e2, + 0x017a0fb5, 0x0fd400fd, 0x01630fb8, 0x0fce0117, + 0x014c0fba, 0x0fca0130, 0x01320fbf, 0x0fc70148, + 0x011b0fc1, 0x0fc10163, 0x01010fc8, 0x0fc00177, + 0x00e90fcd, 0x0fbd018d, 0x00d10fd1, 0x0fbc01a2, + 0x00ba0fd7, 0x0fbb01b4, 0x00a30fdd, 0x0fbc01c4, + 0x008e0fe1, 0x0fbd01d4, 0x00790fe7, 0x0fbe01e2, + 0x00670feb, 0x0fc001ee, 0x00540ff1, 0x0fc501f6, + 0x00430ff4, 0x0fcb01fe, 0x00340ff8, 0x0fd10203, + 0x00260ffb, 0x0fd80207, 0x001a0ffd, 0x0fe10208, + 0x000f0000, 0x0fea0207, 0x00060000, 0x0ff50205, + 0x02000000, 0x00000000, 0x02020ff2, 0x0000000c, + 0x02000fe4, 0x0000001c, 0x01fa0fda, 0x0ffc0030, + 0x01f10fd0, 0x0ffa0045, 0x01e50fc8, 0x0ff6005d, + 0x01d60fc3, 0x0ff30074, 0x01c60fbd, 0x0fef008e, + 0x01b30fba, 0x0fe900aa, 0x019e0fb9, 0x0fe500c4, + 0x01870fba, 0x0fe000df, 0x016f0fbb, 0x0fdd00f9, + 0x01580fbc, 0x0fd80114, 0x01400fbf, 0x0fd3012e, + 0x01280fc2, 0x0fd00146, 0x010f0fc6, 0x0fce015d, + 0x00f90fc9, 0x0fc90175, 0x00e00fcf, 0x0fc90188, + 0x00ca0fd4, 0x0fc6019c, 0x00b40fd8, 0x0fc601ae, + 0x009f0fdd, 0x0fc501bf, 0x008b0fe3, 0x0fc601cc, + 0x00780fe6, 0x0fc701db, 0x00660feb, 0x0fc801e7, + 0x00560fef, 0x0fcb01f0, 0x00460ff3, 0x0fcf01f8, + 0x00380ff6, 0x0fd401fe, 0x002c0ff9, 0x0fd90202, + 0x00200ffc, 0x0fdf0205, 0x00160ffe, 0x0fe60206, + 0x000c0000, 0x0fed0207, 0x00050000, 0x0ff70204, + 0x02000000, 0x00000000, 0x01fe0ff3, 0x0000000f, + 0x01f60fe5, 0x00000025, 0x01ea0fdb, 0x0ffd003e, + 0x01db0fd2, 0x0ffb0058, 0x01c80fcc, 0x0ff70075, + 0x01b50fc7, 0x0ff40090, 0x01a00fc3, 0x0ff000ad, + 0x01880fc1, 0x0feb00cc, 0x01700fc1, 0x0fe800e7, + 0x01550fc3, 0x0fe40104, 0x013b0fc5, 0x0fe2011e, + 0x01240fc6, 0x0fde0138, 0x010c0fca, 0x0fda0150, + 0x00f40fcd, 0x0fd90166, 0x00dd0fd1, 0x0fd7017b, + 0x00c80fd4, 0x0fd40190, 0x00b20fd9, 0x0fd401a1, + 0x009f0fdd, 0x0fd301b1, 0x008c0fe1, 0x0fd301c0, + 0x007b0fe5, 0x0fd301cd, 0x006a0fea, 0x0fd401d8, + 0x005c0fec, 0x0fd501e3, 0x004d0ff0, 0x0fd601ed, + 0x00410ff3, 0x0fd801f4, 0x00340ff7, 0x0fdb01fa, + 0x002a0ff9, 0x0fdf01fe, 0x00200ffb, 0x0fe30202, + 0x00180ffd, 0x0fe70204, 0x00100ffe, 0x0fed0205, + 0x00090000, 0x0ff20205, 0x00040000, 0x0ff90203, + 0x02000000, 0x00000000, 0x02050ff5, 0x00000006, + 0x02070fea, 0x0000000f, 0x02080fe1, 0x0ffd001a, + 0x02070fd8, 0x0ffb0026, 0x02030fd1, 0x0ff80034, + 0x01fe0fcb, 0x0ff40043, 0x01f60fc5, 0x0ff10054, + 0x01ee0fc0, 0x0feb0067, 0x01e20fbe, 0x0fe70079, + 0x01d40fbd, 0x0fe1008e, 0x01c40fbc, 0x0fdd00a3, + 0x01b40fbb, 0x0fd700ba, 0x01a20fbc, 0x0fd100d1, + 0x018d0fbd, 0x0fcd00e9, 0x01770fc0, 0x0fc80101, + 0x01630fc1, 0x0fc1011b, 0x01480fc7, 0x0fbf0132, + 0x01300fca, 0x0fba014c, 0x01170fce, 0x0fb80163, + 0x00fd0fd4, 0x0fb5017a, 0x00e20fda, 0x0fb5018f, + 0x00c80fdd, 0x0fb401a7, 0x00ae0fe4, 0x0fb401ba, + 0x00960fe8, 0x0fb601cc, 0x007c0fee, 0x0fba01dc, + 0x00650ff2, 0x0fc001e9, 0x00500ff6, 0x0fc701f3, + 0x003b0ffa, 0x0fcf01fc, 0x00290ffc, 0x0fda0201, + 0x00180000, 0x0fe40204, 0x000a0000, 0x0ff20204, + 0x02000000, 0x00000000, 0x02030ff5, 0x00000008, + 0x02030fea, 0x00000013, 0x02020fe1, 0x0ffd0020, + 0x01fc0fd9, 0x0ffc002f, 0x01f60fd2, 0x0ff80040, + 0x01ed0fcd, 0x0ff50051, 0x01e30fc7, 0x0ff10065, + 0x01d70fc3, 0x0fec007a, 0x01c60fc2, 0x0fe9008f, + 0x01b60fc1, 0x0fe300a6, 0x01a20fc1, 0x0fe000bd, + 0x018f0fc1, 0x0fdb00d5, 0x017b0fc2, 0x0fd500ee, + 0x01640fc4, 0x0fd20106, 0x014d0fc8, 0x0fce011d, + 0x01370fc9, 0x0fc90137, 0x011d0fce, 0x0fc8014d, + 0x01060fd2, 0x0fc40164, 0x00ee0fd5, 0x0fc2017b, + 0x00d50fdb, 0x0fc1018f, 0x00bd0fe0, 0x0fc101a2, + 0x00a60fe3, 0x0fc101b6, 0x008f0fe9, 0x0fc201c6, + 0x007a0fec, 0x0fc301d7, 0x00650ff1, 0x0fc701e3, + 0x00510ff5, 0x0fcd01ed, 0x00400ff8, 0x0fd201f6, + 0x002f0ffc, 0x0fd901fc, 0x00200ffd, 0x0fe10202, + 0x00130000, 0x0fea0203, 0x00080000, 0x0ff50203, + 0x02000000, 0x00000000, 0x02020ff5, 0x00000009, + 0x01ff0fea, 0x00000017, 0x01fb0fe2, 0x0ffd0026, + 0x01f30fda, 0x0ffc0037, 0x01ea0fd3, 0x0ff8004b, + 0x01df0fce, 0x0ff5005e, 0x01d10fc9, 0x0ff20074, + 0x01c10fc6, 0x0fed008c, 0x01ae0fc5, 0x0fea00a3, + 0x019b0fc5, 0x0fe500bb, 0x01850fc6, 0x0fe200d3, + 0x01700fc6, 0x0fde00ec, 0x015a0fc8, 0x0fd90105, + 0x01430fca, 0x0fd6011d, 0x012b0fcd, 0x0fd30135, + 0x01150fcf, 0x0fcf014d, 0x00fc0fd4, 0x0fce0162, + 0x00e50fd8, 0x0fcc0177, 0x00cf0fdb, 0x0fca018c, + 0x00b80fe0, 0x0fc9019f, 0x00a20fe5, 0x0fca01af, + 0x008e0fe8, 0x0fcb01bf, 0x00790fec, 0x0fcb01d0, + 0x00670fef, 0x0fcd01dd, 0x00550ff4, 0x0fd001e7, + 0x00440ff7, 0x0fd501f0, 0x00350ffa, 0x0fda01f7, + 0x00270ffc, 0x0fdf01fe, 0x001b0ffe, 0x0fe70200, + 0x00100000, 0x0fee0202, 0x00060000, 0x0ff70203, + 0x02000000, 0x00000000, 0x01ff0ff5, 0x0000000c, + 0x01f80fea, 0x0000001e, 0x01ef0fe2, 0x0ffd0032, + 0x01e20fdb, 0x0ffc0047, 0x01d30fd5, 0x0ff9005f, + 0x01c20fd1, 0x0ff60077, 0x01b00fcd, 0x0ff30090, + 0x019b0fcb, 0x0fef00ab, 0x01850fcb, 0x0fec00c4, + 0x016e0fcc, 0x0fe800de, 0x01550fcd, 0x0fe600f8, + 0x013f0fce, 0x0fe20111, 0x01280fd0, 0x0fdf0129, + 0x01110fd2, 0x0fdd0140, 0x00f90fd6, 0x0fdb0156, + 0x00e40fd8, 0x0fd8016c, 0x00cd0fdd, 0x0fd8017e, + 0x00b80fe0, 0x0fd60192, 0x00a40fe3, 0x0fd601a3, + 0x00910fe7, 0x0fd501b3, 0x007f0feb, 0x0fd601c0, + 0x006e0fed, 0x0fd701ce, 0x005d0ff1, 0x0fd701db, + 0x004f0ff3, 0x0fd901e5, 0x00400ff7, 0x0fdc01ed, + 0x00330ff9, 0x0fe001f4, 0x00280ffb, 0x0fe301fa, + 0x001d0ffd, 0x0fe801fe, 0x00140ffe, 0x0fed0201, + 0x000c0000, 0x0ff20202, 0x00050000, 0x0ff90202, + 0x02000000, 0x00000000, 0x02040ff7, 0x00000005, + 0x02070fed, 0x0000000c, 0x02060fe6, 0x0ffe0016, + 0x02050fdf, 0x0ffc0020, 0x02020fd9, 0x0ff9002c, + 0x01fe0fd4, 0x0ff60038, 0x01f80fcf, 0x0ff30046, + 0x01f00fcb, 0x0fef0056, 0x01e70fc8, 0x0feb0066, + 0x01db0fc7, 0x0fe60078, 0x01cc0fc6, 0x0fe3008b, + 0x01bf0fc5, 0x0fdd009f, 0x01ae0fc6, 0x0fd800b4, + 0x019c0fc6, 0x0fd400ca, 0x01880fc9, 0x0fcf00e0, + 0x01750fc9, 0x0fc900f9, 0x015d0fce, 0x0fc6010f, + 0x01460fd0, 0x0fc20128, 0x012e0fd3, 0x0fbf0140, + 0x01140fd8, 0x0fbc0158, 0x00f90fdd, 0x0fbb016f, + 0x00df0fe0, 0x0fba0187, 0x00c40fe5, 0x0fb9019e, + 0x00aa0fe9, 0x0fba01b3, 0x008e0fef, 0x0fbd01c6, + 0x00740ff3, 0x0fc301d6, 0x005d0ff6, 0x0fc801e5, + 0x00450ffa, 0x0fd001f1, 0x00300ffc, 0x0fda01fa, + 0x001c0000, 0x0fe40200, 0x000c0000, 0x0ff20202, + 0x02000000, 0x00000000, 0x02030ff7, 0x00000006, + 0x02020fee, 0x00000010, 0x02000fe7, 0x0ffe001b, + 0x01fe0fdf, 0x0ffc0027, 0x01f70fda, 0x0ffa0035, + 0x01f00fd5, 0x0ff70044, 0x01e70fd0, 0x0ff40055, + 0x01dd0fcd, 0x0fef0067, 0x01d00fcb, 0x0fec0079, + 0x01bf0fcb, 0x0fe8008e, 0x01af0fca, 0x0fe500a2, + 0x019f0fc9, 0x0fe000b8, 0x018c0fca, 0x0fdb00cf, + 0x01770fcc, 0x0fd800e5, 0x01620fce, 0x0fd400fc, + 0x014d0fcf, 0x0fcf0115, 0x01350fd3, 0x0fcd012b, + 0x011d0fd6, 0x0fca0143, 0x01050fd9, 0x0fc8015a, + 0x00ec0fde, 0x0fc60170, 0x00d30fe2, 0x0fc60185, + 0x00bb0fe5, 0x0fc5019b, 0x00a30fea, 0x0fc501ae, + 0x008c0fed, 0x0fc601c1, 0x00740ff2, 0x0fc901d1, + 0x005e0ff5, 0x0fce01df, 0x004b0ff8, 0x0fd301ea, + 0x00370ffc, 0x0fda01f3, 0x00260ffd, 0x0fe201fb, + 0x00170000, 0x0fea01ff, 0x00090000, 0x0ff50202, + 0x02000000, 0x00000000, 0x02010ff7, 0x00000008, + 0x01ff0fee, 0x00000013, 0x01fb0fe7, 0x0ffe0020, + 0x01f60fe0, 0x0ffc002e, 0x01ed0fda, 0x0ffa003f, + 0x01e40fd6, 0x0ff7004f, 0x01d80fd2, 0x0ff40062, + 0x01ca0fcf, 0x0ff00077, 0x01bb0fcd, 0x0fed008b, + 0x01a90fcd, 0x0fe900a1, 0x01960fcd, 0x0fe600b7, + 0x01830fcd, 0x0fe200ce, 0x016d0fcf, 0x0fde00e6, + 0x01580fd0, 0x0fdb00fd, 0x01410fd3, 0x0fd80114, + 0x012c0fd4, 0x0fd4012c, 0x01140fd8, 0x0fd30141, + 0x00fd0fdb, 0x0fd00158, 0x00e60fde, 0x0fcf016d, + 0x00ce0fe2, 0x0fcd0183, 0x00b70fe6, 0x0fcd0196, + 0x00a10fe9, 0x0fcd01a9, 0x008b0fed, 0x0fcd01bb, + 0x00770ff0, 0x0fcf01ca, 0x00620ff4, 0x0fd201d8, + 0x004f0ff7, 0x0fd601e4, 0x003f0ffa, 0x0fda01ed, + 0x002e0ffc, 0x0fe001f6, 0x00200ffe, 0x0fe701fb, + 0x00130000, 0x0fee01ff, 0x00080000, 0x0ff70201, + 0x02000000, 0x00000000, 0x01ff0ff7, 0x0000000a, + 0x01f90fee, 0x00000019, 0x01f10fe7, 0x0ffe002a, + 0x01e60fe1, 0x0ffd003c, 0x01d90fdc, 0x0ffa0051, + 0x01cc0fd8, 0x0ff70065, 0x01bb0fd5, 0x0ff5007b, + 0x01a80fd3, 0x0ff10094, 0x01950fd2, 0x0fef00aa, + 0x01800fd2, 0x0feb00c3, 0x016a0fd3, 0x0fe900da, + 0x01540fd3, 0x0fe600f3, 0x013f0fd5, 0x0fe2010a, + 0x01280fd7, 0x0fe00121, 0x01100fda, 0x0fde0138, + 0x00fb0fdb, 0x0fdb014f, 0x00e40fdf, 0x0fdb0162, + 0x00ce0fe2, 0x0fd90177, 0x00b90fe4, 0x0fd8018b, + 0x00a50fe8, 0x0fd8019b, 0x00910fec, 0x0fd801ab, + 0x007e0fee, 0x0fd801bc, 0x006c0ff2, 0x0fd901c9, + 0x005c0ff4, 0x0fda01d6, 0x004b0ff7, 0x0fdd01e1, + 0x003c0ff9, 0x0fe001eb, 0x002f0ffb, 0x0fe401f2, + 0x00230ffd, 0x0fe801f8, 0x00180ffe, 0x0fed01fd, + 0x000e0000, 0x0ff20200, 0x00060000, 0x0ff90201, + 0x02000000, 0x00000000, 0x02030ff9, 0x00000004, + 0x02050ff2, 0x00000009, 0x02050fed, 0x0ffe0010, + 0x02040fe7, 0x0ffd0018, 0x02020fe3, 0x0ffb0020, + 0x01fe0fdf, 0x0ff9002a, 0x01fa0fdb, 0x0ff70034, + 0x01f40fd8, 0x0ff30041, 0x01ed0fd6, 0x0ff0004d, + 0x01e30fd5, 0x0fec005c, 0x01d80fd4, 0x0fea006a, + 0x01cd0fd3, 0x0fe5007b, 0x01c00fd3, 0x0fe1008c, + 0x01b10fd3, 0x0fdd009f, 0x01a10fd4, 0x0fd900b2, + 0x01900fd4, 0x0fd400c8, 0x017b0fd7, 0x0fd100dd, + 0x01660fd9, 0x0fcd00f4, 0x01500fda, 0x0fca010c, + 0x01380fde, 0x0fc60124, 0x011e0fe2, 0x0fc5013b, + 0x01040fe4, 0x0fc30155, 0x00e70fe8, 0x0fc10170, + 0x00cc0feb, 0x0fc10188, 0x00ad0ff0, 0x0fc301a0, + 0x00900ff4, 0x0fc701b5, 0x00750ff7, 0x0fcc01c8, + 0x00580ffb, 0x0fd201db, 0x003e0ffd, 0x0fdb01ea, + 0x00250000, 0x0fe501f6, 0x000f0000, 0x0ff301fe, + 0x02000000, 0x00000000, 0x02020ff9, 0x00000005, + 0x02020ff2, 0x0000000c, 0x02010fed, 0x0ffe0014, + 0x01fe0fe8, 0x0ffd001d, 0x01fa0fe3, 0x0ffb0028, + 0x01f40fe0, 0x0ff90033, 0x01ed0fdc, 0x0ff70040, + 0x01e50fd9, 0x0ff3004f, 0x01db0fd7, 0x0ff1005d, + 0x01ce0fd7, 0x0fed006e, 0x01c00fd6, 0x0feb007f, + 0x01b30fd5, 0x0fe70091, 0x01a30fd6, 0x0fe300a4, + 0x01920fd6, 0x0fe000b8, 0x017e0fd8, 0x0fdd00cd, + 0x016c0fd8, 0x0fd800e4, 0x01560fdb, 0x0fd600f9, + 0x01400fdd, 0x0fd20111, 0x01290fdf, 0x0fd00128, + 0x01110fe2, 0x0fce013f, 0x00f80fe6, 0x0fcd0155, + 0x00de0fe8, 0x0fcc016e, 0x00c40fec, 0x0fcb0185, + 0x00ab0fef, 0x0fcb019b, 0x00900ff3, 0x0fcd01b0, + 0x00770ff6, 0x0fd101c2, 0x005f0ff9, 0x0fd501d3, + 0x00470ffc, 0x0fdb01e2, 0x00320ffd, 0x0fe201ef, + 0x001e0000, 0x0fea01f8, 0x000c0000, 0x0ff501ff, + 0x02000000, 0x00000000, 0x02010ff9, 0x00000006, + 0x02000ff2, 0x0000000e, 0x01fd0fed, 0x0ffe0018, + 0x01f80fe8, 0x0ffd0023, 0x01f20fe4, 0x0ffb002f, + 0x01eb0fe0, 0x0ff9003c, 0x01e10fdd, 0x0ff7004b, + 0x01d60fda, 0x0ff4005c, 0x01c90fd9, 0x0ff2006c, + 0x01bc0fd8, 0x0fee007e, 0x01ab0fd8, 0x0fec0091, + 0x019b0fd8, 0x0fe800a5, 0x018b0fd8, 0x0fe400b9, + 0x01770fd9, 0x0fe200ce, 0x01620fdb, 0x0fdf00e4, + 0x014f0fdb, 0x0fdb00fb, 0x01380fde, 0x0fda0110, + 0x01210fe0, 0x0fd70128, 0x010a0fe2, 0x0fd5013f, + 0x00f30fe6, 0x0fd30154, 0x00da0fe9, 0x0fd3016a, + 0x00c30feb, 0x0fd20180, 0x00aa0fef, 0x0fd20195, + 0x00940ff1, 0x0fd301a8, 0x007b0ff5, 0x0fd501bb, + 0x00650ff7, 0x0fd801cc, 0x00510ffa, 0x0fdc01d9, + 0x003c0ffd, 0x0fe101e6, 0x002a0ffe, 0x0fe701f1, + 0x00190000, 0x0fee01f9, 0x000a0000, 0x0ff701ff, + 0x02000000, 0x00000000, 0x01ff0ff9, 0x00000008, + 0x01fb0ff2, 0x00000013, 0x01f50fed, 0x0ffe0020, + 0x01ed0fe8, 0x0ffd002e, 0x01e30fe4, 0x0ffb003e, + 0x01d80fe1, 0x0ff9004e, 0x01cb0fde, 0x0ff70060, + 0x01bc0fdc, 0x0ff40074, 0x01ac0fdb, 0x0ff20087, + 0x019a0fdb, 0x0fef009c, 0x01870fdb, 0x0fed00b1, + 0x01740fdb, 0x0fea00c7, 0x01600fdc, 0x0fe700dd, + 0x014b0fdd, 0x0fe500f3, 0x01350fdf, 0x0fe30109, + 0x01200fe0, 0x0fe00120, 0x01090fe3, 0x0fdf0135, + 0x00f30fe5, 0x0fdd014b, 0x00dd0fe7, 0x0fdc0160, + 0x00c70fea, 0x0fdb0174, 0x00b10fed, 0x0fdb0187, + 0x009c0fef, 0x0fdb019a, 0x00870ff2, 0x0fdb01ac, + 0x00740ff4, 0x0fdc01bc, 0x00600ff7, 0x0fde01cb, + 0x004e0ff9, 0x0fe101d8, 0x003e0ffb, 0x0fe401e3, + 0x002e0ffd, 0x0fe801ed, 0x00200ffe, 0x0fed01f5, + 0x00130000, 0x0ff201fb, 0x00080000, 0x0ff901ff +}; + + +#define MDP4_QSEED_TABLE0_OFF 0x8100 +#define MDP4_QSEED_TABLE1_OFF 0x8200 +#define MDP4_QSEED_TABLE2_OFF 0x9000 + +void mdp4_vg_qseed_init(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE0_OFF); + for (i = 0; i < (sizeof(vg_qseed_table0) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table0[i]); + off++; + } + + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE1_OFF); + for (i = 0; i < (sizeof(vg_qseed_table1) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table1[i]); + off++; + } + + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE2_OFF); + for (i = 0; i < (sizeof(vg_qseed_table2) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table2[i]); + off++; + } + +} + +void mdp4_mixer_blend_init(mixer_num) +{ + unsigned char *overlay_base; + int off; + + if (mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + /* stage 0 to stage 2 */ + off = 0; + outpdw(overlay_base + off + 0x104, 0x010); + outpdw(overlay_base + off + 0x108, 0xff);/* FG */ + outpdw(overlay_base + off + 0x10c, 0x00);/* BG */ + + off += 0x20; + outpdw(overlay_base + off + 0x104, 0x010); + outpdw(overlay_base + off + 0x108, 0xff);/* FG */ + outpdw(overlay_base + off + 0x10c, 0x00);/* BG */ + + off += 0x20; + outpdw(overlay_base + off + 0x104, 0x010); + outpdw(overlay_base + off + 0x108, 0xff);/* FG */ + outpdw(overlay_base + off + 0x10c, 0x00);/* BG */ +} + + +static uint32 csc_matrix_tab[9] = { + 0x0254, 0x0000, 0x0331, + 0x0254, 0xff37, 0xfe60, + 0x0254, 0x0409, 0x0000 +}; + +static uint32 csc_pre_bv_tab[3] = {0xfff0, 0xff80, 0xff80 }; +static uint32 csc_post_bv_tab[3] = {0, 0, 0 }; + +static uint32 csc_pre_lv_tab[6] = {0, 0xff, 0, 0xff, 0, 0xff }; +static uint32 csc_post_lv_tab[6] = {0, 0xff, 0, 0xff, 0, 0xff }; + +#define MDP4_CSC_MV_OFF 0x4400 +#define MDP4_CSC_PRE_BV_OFF 0x4500 +#define MDP4_CSC_POST_BV_OFF 0x4580 +#define MDP4_CSC_PRE_LV_OFF 0x4600 +#define MDP4_CSC_POST_LV_OFF 0x4680 + +void mdp4_vg_csc_mv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_MV_OFF); + for (i = 0; i < 9; i++) { + outpdw(off, csc_matrix_tab[i]); + off++; + } +} + +void mdp4_vg_csc_pre_bv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_PRE_BV_OFF); + for (i = 0; i < 3; i++) { + outpdw(off, csc_pre_bv_tab[i]); + off++; + } +} + +void mdp4_vg_csc_post_bv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_POST_BV_OFF); + for (i = 0; i < 3; i++) { + outpdw(off, csc_post_bv_tab[i]); + off++; + } +} + +void mdp4_vg_csc_pre_lv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_PRE_LV_OFF); + + for (i = 0; i < 6; i++) { + outpdw(off, csc_pre_lv_tab[i]); + off++; + } +} + +void mdp4_vg_csc_post_lv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_POST_LV_OFF); + + for (i = 0; i < 6; i++) { + outpdw(off, csc_post_lv_tab[i]); + off++; + } +} + +char gc_lut[] = { + 0x0, 0x1, 0x2, 0x2, 0x3, 0x4, 0x5, 0x6, + 0x6, 0x7, 0x8, 0x9, 0xA, 0xA, 0xB, 0xC, + 0xD, 0xD, 0xE, 0xF, 0xF, 0x10, 0x10, 0x11, + 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, + 0x16, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18, 0x19, + 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1C, 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, + 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, + 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, + 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, + 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, + 0x28, 0x29, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2D, 0x2D, 0x2E, 0x2E, + 0x2E, 0x2E, 0x2E, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, + 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, + 0x3D, 0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, + 0x3E, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x49, 0x4A, 0x4A, 0x4A, + 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4B, 0x4B, 0x4B, + 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4C, 0x4C, 0x4C, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4D, + 0x4D, 0x4D, 0x4D, 0x4D, 0x4E, 0x4E, 0x4E, 0x4E, + 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, + 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, + 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, + 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, + 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, + 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5A, 0x5A, + 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, + 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, + 0x5B, 0x5B, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5E, 0x5E, + 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, + 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, + 0x5F, 0x5F, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x62, + 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, + 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, + 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, + 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, + 0x69, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, + 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6B, 0x6B, 0x6B, + 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, + 0x6B, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, + 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D, + 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, + 0x6D, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, + 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6F, 0x6F, 0x6F, + 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, + 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x72, + 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, + 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, + 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, + 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, + 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, + 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, + 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, + 0x76, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x7A, 0x7A, + 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, + 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, + 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, + 0x7B, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, + 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, + 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, + 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, + 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, + 0x8A, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, + 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, + 0x8B, 0x8B, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, + 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, + 0x8C, 0x8C, 0x8C, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, + 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, + 0x8D, 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8E, 0x8E, + 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, + 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F, 0x8F, 0x8F, + 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, + 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9B, 0x9B, 0x9B, + 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, + 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, + 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, + 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, + 0x9C, 0x9C, 0x9C, 0x9C, 0x9D, 0x9D, 0x9D, 0x9D, + 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, + 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9E, + 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, + 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, + 0x9E, 0x9E, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, + 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, + 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, + 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, + 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA2, 0xA2, + 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, + 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, + 0xA2, 0xA2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, + 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, + 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA4, 0xA4, + 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, + 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, + 0xA4, 0xA4, 0xA4, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, + 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, + 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, + 0xA6, 0xA6, 0xA6, 0xA6, 0xA7, 0xA7, 0xA7, 0xA7, + 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, + 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, + 0xA7, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, + 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, + 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA9, + 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, + 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, + 0xA9, 0xA9, 0xA9, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, + 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, + 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAC, + 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, + 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, + 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAD, 0xAD, 0xAD, + 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, + 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, + 0xAD, 0xAD, 0xAD, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, + 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, + 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, + 0xAE, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, + 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, + 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xB0, + 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, + 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, + 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB1, + 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, + 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, + 0xB1, 0xB1, 0xB1, 0xB1, 0xB2, 0xB2, 0xB2, 0xB2, + 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, + 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, + 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, + 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, + 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, + 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, + 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, + 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, + 0xB4, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, + 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, + 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, + 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, + 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, + 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, + 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, + 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, + 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB8, + 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, + 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, + 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB9, + 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, + 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, + 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xBA, + 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, + 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, + 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBB, + 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, + 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, + 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, + 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, + 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, + 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, + 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, + 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, + 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, + 0xBD, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, + 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, + 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, + 0xBE, 0xBE, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, + 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, + 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, + 0xBF, 0xBF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC1, 0xC1, 0xC1, 0xC1, + 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, + 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, + 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC2, 0xC2, 0xC2, + 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, + 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, + 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, + 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, + 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, + 0xC4, 0xC4, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, + 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, + 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, + 0xC5, 0xC5, 0xC5, 0xC5, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7, 0xC7, + 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, + 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, + 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, + 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, + 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, + 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xCA, 0xCA, + 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, + 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, + 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, + 0xCA, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, + 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, + 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, + 0xCB, 0xCB, 0xCB, 0xCB, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCD, + 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, + 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, + 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, + 0xCD, 0xCD, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, + 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, + 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, + 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCF, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, + 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, + 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, + 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, + 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, + 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, + 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, + 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, + 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, + 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, + 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, + 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, + 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +void mdp4_mixer_gc_lut_setup(int mixer_num) +{ + unsigned char *base; + uint32 data; + char val; + int i, off; + + if (mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */ + base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + base += 0x4000; /* GC_LUT offset */ + + off = 0; + for (i = 0; i < 4096; i++) { + val = gc_lut[i]; + data = (val << 16 | val << 8 | val); /* R, B, and G are same */ + outpdw(base + off, data); + off += 4; + } +} + +uint32 igc_video_lut[] = { /* non linear */ + 0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x9, + 0xA, 0xB, 0xC, 0xE, 0xF, 0x10, 0x12, 0x14, + 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F, 0x21, 0x23, + 0x25, 0x28, 0x2A, 0x2D, 0x30, 0x32, 0x35, 0x38, + 0x3B, 0x3E, 0x42, 0x45, 0x48, 0x4C, 0x4F, 0x53, + 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x70, 0x74, + 0x79, 0x7E, 0x83, 0x88, 0x8D, 0x92, 0x97, 0x9C, + 0xA2, 0xA8, 0xAD, 0xB3, 0xB9, 0xBF, 0xC5, 0xCC, + 0xD2, 0xD8, 0xDF, 0xE6, 0xED, 0xF4, 0xFB, 0x102, + 0x109, 0x111, 0x118, 0x120, 0x128, 0x130, 0x138, 0x140, + 0x149, 0x151, 0x15A, 0x162, 0x16B, 0x174, 0x17D, 0x186, + 0x190, 0x199, 0x1A3, 0x1AC, 0x1B6, 0x1C0, 0x1CA, 0x1D5, + 0x1DF, 0x1EA, 0x1F4, 0x1FF, 0x20A, 0x215, 0x220, 0x22B, + 0x237, 0x242, 0x24E, 0x25A, 0x266, 0x272, 0x27F, 0x28B, + 0x298, 0x2A4, 0x2B1, 0x2BE, 0x2CB, 0x2D8, 0x2E6, 0x2F3, + 0x301, 0x30F, 0x31D, 0x32B, 0x339, 0x348, 0x356, 0x365, + 0x374, 0x383, 0x392, 0x3A1, 0x3B1, 0x3C0, 0x3D0, 0x3E0, + 0x3F0, 0x400, 0x411, 0x421, 0x432, 0x443, 0x454, 0x465, + 0x476, 0x487, 0x499, 0x4AB, 0x4BD, 0x4CF, 0x4E1, 0x4F3, + 0x506, 0x518, 0x52B, 0x53E, 0x551, 0x565, 0x578, 0x58C, + 0x5A0, 0x5B3, 0x5C8, 0x5DC, 0x5F0, 0x605, 0x61A, 0x62E, + 0x643, 0x659, 0x66E, 0x684, 0x699, 0x6AF, 0x6C5, 0x6DB, + 0x6F2, 0x708, 0x71F, 0x736, 0x74D, 0x764, 0x77C, 0x793, + 0x7AB, 0x7C3, 0x7DB, 0x7F3, 0x80B, 0x824, 0x83D, 0x855, + 0x86F, 0x888, 0x8A1, 0x8BB, 0x8D4, 0x8EE, 0x908, 0x923, + 0x93D, 0x958, 0x973, 0x98E, 0x9A9, 0x9C4, 0x9DF, 0x9FB, + 0xA17, 0xA33, 0xA4F, 0xA6C, 0xA88, 0xAA5, 0xAC2, 0xADF, + 0xAFC, 0xB19, 0xB37, 0xB55, 0xB73, 0xB91, 0xBAF, 0xBCE, + 0xBEC, 0xC0B, 0xC2A, 0xC4A, 0xC69, 0xC89, 0xCA8, 0xCC8, + 0xCE8, 0xD09, 0xD29, 0xD4A, 0xD6B, 0xD8C, 0xDAD, 0xDCF, + 0xDF0, 0xE12, 0xE34, 0xE56, 0xE79, 0xE9B, 0xEBE, 0xEE1, + 0xF04, 0xF27, 0xF4B, 0xF6E, 0xF92, 0xFB6, 0xFDB, 0xFFF, +}; + +void mdp4_vg_igc_lut_setup(int vp_num) +{ + unsigned char *base; + int i, voff, off; + uint32 data, val; + + voff = MDP4_VIDEO_OFF * vp_num; + base = MDP_BASE + MDP4_VIDEO_BASE + voff + 0x5000; + + off = 0; + for (i = 0; i < 256; i++) { + val = igc_video_lut[i]; + data = (val << 16 | val); /* color 0 and 1 */ + outpdw(base + off, data); + outpdw(base + off + 0x800, val); /* color 2 */ + off += 4; + } +} + +uint32 igc_rgb_lut[] = { /* linear */ + 0x0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x101, 0x111, 0x121, 0x131, 0x141, 0x151, 0x161, 0x171, + 0x181, 0x191, 0x1A2, 0x1B2, 0x1C2, 0x1D2, 0x1E2, 0x1F2, + 0x202, 0x212, 0x222, 0x232, 0x242, 0x252, 0x262, 0x272, + 0x282, 0x292, 0x2A2, 0x2B3, 0x2C3, 0x2D3, 0x2E3, 0x2F3, + 0x303, 0x313, 0x323, 0x333, 0x343, 0x353, 0x363, 0x373, + 0x383, 0x393, 0x3A3, 0x3B3, 0x3C4, 0x3D4, 0x3E4, 0x3F4, + 0x404, 0x414, 0x424, 0x434, 0x444, 0x454, 0x464, 0x474, + 0x484, 0x494, 0x4A4, 0x4B4, 0x4C4, 0x4D5, 0x4E5, 0x4F5, + 0x505, 0x515, 0x525, 0x535, 0x545, 0x555, 0x565, 0x575, + 0x585, 0x595, 0x5A5, 0x5B5, 0x5C5, 0x5D5, 0x5E6, 0x5F6, + 0x606, 0x616, 0x626, 0x636, 0x646, 0x656, 0x666, 0x676, + 0x686, 0x696, 0x6A6, 0x6B6, 0x6C6, 0x6D6, 0x6E6, 0x6F7, + 0x707, 0x717, 0x727, 0x737, 0x747, 0x757, 0x767, 0x777, + 0x787, 0x797, 0x7A7, 0x7B7, 0x7C7, 0x7D7, 0x7E7, 0x7F7, + 0x808, 0x818, 0x828, 0x838, 0x848, 0x858, 0x868, 0x878, + 0x888, 0x898, 0x8A8, 0x8B8, 0x8C8, 0x8D8, 0x8E8, 0x8F8, + 0x908, 0x919, 0x929, 0x939, 0x949, 0x959, 0x969, 0x979, + 0x989, 0x999, 0x9A9, 0x9B9, 0x9C9, 0x9D9, 0x9E9, 0x9F9, + 0xA09, 0xA19, 0xA2A, 0xA3A, 0xA4A, 0xA5A, 0xA6A, 0xA7A, + 0xA8A, 0xA9A, 0xAAA, 0xABA, 0xACA, 0xADA, 0xAEA, 0xAFA, + 0xB0A, 0xB1A, 0xB2A, 0xB3B, 0xB4B, 0xB5B, 0xB6B, 0xB7B, + 0xB8B, 0xB9B, 0xBAB, 0xBBB, 0xBCB, 0xBDB, 0xBEB, 0xBFB, + 0xC0B, 0xC1B, 0xC2B, 0xC3B, 0xC4C, 0xC5C, 0xC6C, 0xC7C, + 0xC8C, 0xC9C, 0xCAC, 0xCBC, 0xCCC, 0xCDC, 0xCEC, 0xCFC, + 0xD0C, 0xD1C, 0xD2C, 0xD3C, 0xD4C, 0xD5D, 0xD6D, 0xD7D, + 0xD8D, 0xD9D, 0xDAD, 0xDBD, 0xDCD, 0xDDD, 0xDED, 0xDFD, + 0xE0D, 0xE1D, 0xE2D, 0xE3D, 0xE4D, 0xE5D, 0xE6E, 0xE7E, + 0xE8E, 0xE9E, 0xEAE, 0xEBE, 0xECE, 0xEDE, 0xEEE, 0xEFE, + 0xF0E, 0xF1E, 0xF2E, 0xF3E, 0xF4E, 0xF5E, 0xF6E, 0xF7F, + 0xF8F, 0xF9F, 0xFAF, 0xFBF, 0xFCF, 0xFDF, 0xFEF, 0xFFF, +}; + +void mdp4_rgb_igc_lut_setup(int num) +{ + unsigned char *base; + int i, voff, off; + uint32 data, val; + + voff = MDP4_RGB_OFF * num; + base = MDP_BASE + MDP4_RGB_BASE + voff + 0x5000; + + off = 0; + for (i = 0; i < 256; i++) { + val = igc_rgb_lut[i]; + data = (val << 16 | val); /* color 0 and 1 */ + outpdw(base + off, data); + outpdw(base + off + 0x800, val); /* color 2 */ + off += 4; + } +} diff --git a/drivers/staging/msm/mdp_cursor.c b/drivers/staging/msm/mdp_cursor.c new file mode 100644 index 000000000000..7d28f30d9313 --- /dev/null +++ b/drivers/staging/msm/mdp_cursor.c @@ -0,0 +1,104 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/hrtimer.h> + +#include <mach/hardware.h> +#include <asm/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/spinlock.h> + +#include <linux/fb.h> + +#include "mdp.h" +#include "msm_fb.h" + +static int cursor_enabled; + +int mdp_hw_cursor_update(struct fb_info *info, struct fb_cursor *cursor) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct fb_image *img = &cursor->image; + int calpha_en, transp_en; + int alpha; + int ret = 0; + + if ((img->width > MDP_CURSOR_WIDTH) || + (img->height > MDP_CURSOR_HEIGHT) || + (img->depth != 32)) + return -EINVAL; + + if (cursor->set & FB_CUR_SETPOS) + MDP_OUTP(MDP_BASE + 0x9004c, (img->dy << 16) | img->dx); + + if (cursor->set & FB_CUR_SETIMAGE) { + ret = copy_from_user(mfd->cursor_buf, img->data, + img->width*img->height*4); + if (ret) + return ret; + + if (img->bg_color == 0xffffffff) + transp_en = 0; + else + transp_en = 1; + + alpha = (img->fg_color & 0xff000000) >> 24; + + if (alpha) + calpha_en = 0x2; /* xrgb */ + else + calpha_en = 0x1; /* argb */ + + MDP_OUTP(MDP_BASE + 0x90044, (img->height << 16) | img->width); + MDP_OUTP(MDP_BASE + 0x90048, mfd->cursor_buf_phys); + /* order the writes the cursor_buf before updating the + * hardware */ +// dma_coherent_pre_ops(); + MDP_OUTP(MDP_BASE + 0x90060, + (transp_en << 3) | (calpha_en << 1) | + (inp32(MDP_BASE + 0x90060) & 0x1)); +#ifdef CONFIG_FB_MSM_MDP40 + MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24)); + MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & img->bg_color)); + MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & img->bg_color)); +#else + MDP_OUTP(MDP_BASE + 0x90064, + (alpha << 24) | (0xffffff & img->bg_color)); + MDP_OUTP(MDP_BASE + 0x90068, 0); +#endif + } + + if ((cursor->enable) && (!cursor_enabled)) { + cursor_enabled = 1; + MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1); + } else if ((!cursor->enable) && (cursor_enabled)) { + cursor_enabled = 0; + MDP_OUTP(MDP_BASE + 0x90060, + inp32(MDP_BASE + 0x90060) & (~0x1)); + } + + return 0; +} diff --git a/drivers/staging/msm/mdp_dma.c b/drivers/staging/msm/mdp_dma.c new file mode 100644 index 000000000000..639918b143b4 --- /dev/null +++ b/drivers/staging/msm/mdp_dma.c @@ -0,0 +1,561 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/hrtimer.h> + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/spinlock.h> + +#include <linux/fb.h> + +#include "mdp.h" +#include "msm_fb.h" +#include "mddihost.h" + +static uint32 mdp_last_dma2_update_width; +static uint32 mdp_last_dma2_update_height; +static uint32 mdp_curr_dma2_update_width; +static uint32 mdp_curr_dma2_update_height; + +ktime_t mdp_dma2_last_update_time = { 0 }; + +int mdp_lcd_rd_cnt_offset_slow = 20; +int mdp_lcd_rd_cnt_offset_fast = 20; +int mdp_vsync_usec_wait_line_too_short = 5; +uint32 mdp_dma2_update_time_in_usec; +uint32 mdp_total_vdopkts; + +extern u32 msm_fb_debug_enabled; +extern struct workqueue_struct *mdp_dma_wq; + +int vsync_start_y_adjust = 4; + +static void mdp_dma2_update_lcd(struct msm_fb_data_type *mfd) +{ + MDPIBUF *iBuf = &mfd->ibuf; + int mddi_dest = FALSE; + uint32 outBpp = iBuf->bpp; + uint32 dma2_cfg_reg; + uint8 *src; + uint32 mddi_ld_param; + uint16 mddi_vdo_packet_reg; + struct msm_fb_panel_data *pdata = + (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + uint32 ystride = mfd->fbi->fix.line_length; + + dma2_cfg_reg = DMA_PACK_TIGHT | DMA_PACK_ALIGN_LSB | + DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS; + +#ifdef CONFIG_FB_MSM_MDP30 + /* + * Software workaround: On 7x25/7x27, the MDP will not + * respond if dma_w is 1 pixel. Set the update width to + * 2 pixels and adjust the x offset if needed. + */ + if (iBuf->dma_w == 1) { + iBuf->dma_w = 2; + if (iBuf->dma_x == (iBuf->ibuf_width - 2)) + iBuf->dma_x--; + } +#endif + + if (mfd->fb_imgType == MDP_BGR_565) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; + + if (outBpp == 4) + dma2_cfg_reg |= DMA_IBUF_C3ALPHA_EN; + + if (outBpp == 2) + dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565; + + mddi_ld_param = 0; + mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt; + + if ((mfd->panel_info.type == MDDI_PANEL) || + (mfd->panel_info.type == EXT_MDDI_PANEL)) { + dma2_cfg_reg |= DMA_OUT_SEL_MDDI; + mddi_dest = TRUE; + + if (mfd->panel_info.type == MDDI_PANEL) { + mdp_total_vdopkts++; + if (mfd->panel_info.pdest == DISPLAY_1) { + dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY; + mddi_ld_param = 0; +#ifdef MDDI_HOST_WINDOW_WORKAROUND + mddi_window_adjust(mfd, iBuf->dma_x, + iBuf->dma_w - 1, iBuf->dma_y, + iBuf->dma_h - 1); +#endif + } else { + dma2_cfg_reg |= + DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY; + mddi_ld_param = 1; +#ifdef MDDI_HOST_WINDOW_WORKAROUND + mddi_window_adjust(mfd, iBuf->dma_x, + iBuf->dma_w - 1, iBuf->dma_y, + iBuf->dma_h - 1); +#endif + } + } else { + dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL; + mddi_ld_param = 2; + } + } else { + if (mfd->panel_info.pdest == DISPLAY_1) { + dma2_cfg_reg |= DMA_AHBM_LCD_SEL_PRIMARY; + outp32(MDP_EBI2_LCD0, mfd->data_port_phys); + } else { + dma2_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY; + outp32(MDP_EBI2_LCD1, mfd->data_port_phys); + } + } + + dma2_cfg_reg |= DMA_DITHER_EN; + + src = (uint8 *) iBuf->buf; + /* starting input address */ + src += iBuf->dma_x * outBpp + iBuf->dma_y * ystride; + + mdp_curr_dma2_update_width = iBuf->dma_w; + mdp_curr_dma2_update_height = iBuf->dma_h; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + +#ifdef CONFIG_FB_MSM_MDP22 + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0184, + (iBuf->dma_h << 16 | iBuf->dma_w)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0188, src); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x018C, ystride); +#else + MDP_OUTP(MDP_BASE + 0x90004, (iBuf->dma_h << 16 | iBuf->dma_w)); + MDP_OUTP(MDP_BASE + 0x90008, src); + MDP_OUTP(MDP_BASE + 0x9000c, ystride); +#endif + + if (mfd->panel_info.bpp == 18) { + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else { + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } + + if (mddi_dest) { +#ifdef CONFIG_FB_MSM_MDP22 + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0194, + (iBuf->dma_y << 16) | iBuf->dma_x); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0, mddi_ld_param); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4, + (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); +#else + MDP_OUTP(MDP_BASE + 0x90010, (iBuf->dma_y << 16) | iBuf->dma_x); + MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param); + MDP_OUTP(MDP_BASE + 0x00094, + (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); +#endif + } else { + /* setting EBI2 LCDC write window */ + pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w, + iBuf->dma_h); + } + + /* dma2 config register */ +#ifdef MDP_HW_VSYNC + MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg); + + if ((mfd->use_mdp_vsync) && + (mfd->ibuf.vsync_enable) && (mfd->panel_info.lcd.vsync_enable)) { + uint32 start_y; + + if (vsync_start_y_adjust <= iBuf->dma_y) + start_y = iBuf->dma_y - vsync_start_y_adjust; + else + start_y = + (mfd->total_lcd_lines - 1) - (vsync_start_y_adjust - + iBuf->dma_y); + + /* + * MDP VSYNC clock must be On by now so, we don't have to + * re-enable it + */ + MDP_OUTP(MDP_BASE + 0x210, start_y); + MDP_OUTP(MDP_BASE + 0x20c, 1); /* enable prim vsync */ + } else { + MDP_OUTP(MDP_BASE + 0x20c, 0); /* disable prim vsync */ + } +#else +#ifdef CONFIG_FB_MSM_MDP22 + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0180, dma2_cfg_reg); +#else + MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg); +#endif +#endif /* MDP_HW_VSYNC */ + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +static ktime_t vt = { 0 }; +int mdp_usec_diff_threshold = 100; +int mdp_expected_usec_wait; + +enum hrtimer_restart mdp_dma2_vsync_hrtimer_handler(struct hrtimer *ht) +{ + struct msm_fb_data_type *mfd = NULL; + + mfd = container_of(ht, struct msm_fb_data_type, dma_hrtimer); + + mdp_pipe_kickoff(MDP_DMA2_TERM, mfd); + + if (msm_fb_debug_enabled) { + ktime_t t; + int usec_diff; + int actual_wait; + + t = ktime_get_real(); + + actual_wait = + (t.tv.sec - vt.tv.sec) * 1000000 + (t.tv.nsec - + vt.tv.nsec) / 1000; + usec_diff = actual_wait - mdp_expected_usec_wait; + + if ((mdp_usec_diff_threshold < usec_diff) || (usec_diff < 0)) + MSM_FB_DEBUG + ("HRT Diff = %d usec Exp=%d usec Act=%d usec\n", + usec_diff, mdp_expected_usec_wait, actual_wait); + } + + return HRTIMER_NORESTART; +} + +static void mdp_dma_schedule(struct msm_fb_data_type *mfd, uint32 term) +{ + /* + * dma2 configure VSYNC block + * vsync supported on Primary LCD only for now + */ + int32 mdp_lcd_rd_cnt; + uint32 usec_wait_time; + uint32 start_y; + + /* + * ToDo: if we can move HRT timer callback to workqueue, we can + * move DMA2 power on under mdp_pipe_kickoff(). + * This will save a power for hrt time wait. + * However if the latency for context switch (hrt irq -> workqueue) + * is too big, we will miss the vsync timing. + */ + if (term == MDP_DMA2_TERM) + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + mdp_dma2_update_time_in_usec = + MDP_KTIME2USEC(mdp_dma2_last_update_time); + + if ((!mfd->ibuf.vsync_enable) || (!mfd->panel_info.lcd.vsync_enable) + || (mfd->use_mdp_vsync)) { + mdp_pipe_kickoff(term, mfd); + return; + } + /* SW vsync logic starts here */ + + /* get current rd counter */ + mdp_lcd_rd_cnt = mdp_get_lcd_line_counter(mfd); + if (mdp_dma2_update_time_in_usec != 0) { + uint32 num, den; + + /* + * roi width boundary calculation to know the size of pixel + * width that MDP can send faster or slower than LCD read + * pointer + */ + + num = mdp_last_dma2_update_width * mdp_last_dma2_update_height; + den = + (((mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) / + 1000) * (mdp_dma2_update_time_in_usec / 100)) / 1000; + + if (den == 0) + mfd->vsync_width_boundary[mdp_last_dma2_update_width] = + mfd->panel_info.xres + 1; + else + mfd->vsync_width_boundary[mdp_last_dma2_update_width] = + (int)(num / den); + } + + if (mfd->vsync_width_boundary[mdp_last_dma2_update_width] > + mdp_curr_dma2_update_width) { + /* MDP wrp is faster than LCD rdp */ + mdp_lcd_rd_cnt += mdp_lcd_rd_cnt_offset_fast; + } else { + /* MDP wrp is slower than LCD rdp */ + mdp_lcd_rd_cnt -= mdp_lcd_rd_cnt_offset_slow; + } + + if (mdp_lcd_rd_cnt < 0) + mdp_lcd_rd_cnt = mfd->total_lcd_lines + mdp_lcd_rd_cnt; + else if (mdp_lcd_rd_cnt > mfd->total_lcd_lines) + mdp_lcd_rd_cnt = mdp_lcd_rd_cnt - mfd->total_lcd_lines - 1; + + /* get wrt pointer position */ + start_y = mfd->ibuf.dma_y; + + /* measure line difference between start_y and rd counter */ + if (start_y > mdp_lcd_rd_cnt) { + /* + * *100 for lcd_ref_hzx100 was already multiplied by 100 + * *1000000 is for usec conversion + */ + + if ((start_y - mdp_lcd_rd_cnt) <= + mdp_vsync_usec_wait_line_too_short) + usec_wait_time = 0; + else + usec_wait_time = + ((start_y - + mdp_lcd_rd_cnt) * 1000000) / + ((mfd->total_lcd_lines * + mfd->panel_info.lcd.refx100) / 100); + } else { + if ((start_y + (mfd->total_lcd_lines - mdp_lcd_rd_cnt)) <= + mdp_vsync_usec_wait_line_too_short) + usec_wait_time = 0; + else + usec_wait_time = + ((start_y + + (mfd->total_lcd_lines - + mdp_lcd_rd_cnt)) * 1000000) / + ((mfd->total_lcd_lines * + mfd->panel_info.lcd.refx100) / 100); + } + + mdp_last_dma2_update_width = mdp_curr_dma2_update_width; + mdp_last_dma2_update_height = mdp_curr_dma2_update_height; + + if (usec_wait_time == 0) { + mdp_pipe_kickoff(term, mfd); + } else { + ktime_t wait_time; + + wait_time.tv.sec = 0; + wait_time.tv.nsec = usec_wait_time * 1000; + + if (msm_fb_debug_enabled) { + vt = ktime_get_real(); + mdp_expected_usec_wait = usec_wait_time; + } + hrtimer_start(&mfd->dma_hrtimer, wait_time, HRTIMER_MODE_REL); + } +} + +#ifdef MDDI_HOST_WINDOW_WORKAROUND +void mdp_dma2_update(struct msm_fb_data_type *mfd) +{ + MDPIBUF *iBuf; + uint32 upper_height; + + if (mfd->panel.type == EXT_MDDI_PANEL) { + mdp_dma2_update_sub(mfd); + return; + } + + iBuf = &mfd->ibuf; + + upper_height = + (uint32) mddi_assign_pkt_height((uint16) iBuf->dma_w, + (uint16) iBuf->dma_h, 18); + + if (upper_height >= iBuf->dma_h) { + mdp_dma2_update_sub(mfd); + } else { + MDPIBUF lower_height; + + /* sending the upper region first */ + lower_height = iBuf->dma_h - upper_height; + iBuf->dma_h = upper_height; + mdp_dma2_update_sub(mfd); + + /* sending the lower region second */ + iBuf->dma_h = lower_height; + iBuf->dma_y += lower_height; + iBuf->vsync_enable = FALSE; + mdp_dma2_update_sub(mfd); + } +} + +void mdp_dma2_update_sub(struct msm_fb_data_type *mfd) +#else +void mdp_dma2_update(struct msm_fb_data_type *mfd) +#endif +{ + down(&mfd->dma->mutex); + if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) { + down(&mfd->sem); + mfd->ibuf_flushed = TRUE; + mdp_dma2_update_lcd(mfd); + + mdp_enable_irq(MDP_DMA2_TERM); + mfd->dma->busy = TRUE; + INIT_COMPLETION(mfd->dma->comp); + + /* schedule DMA to start */ + mdp_dma_schedule(mfd, MDP_DMA2_TERM); + up(&mfd->sem); + + /* wait until DMA finishes the current job */ + wait_for_completion_killable(&mfd->dma->comp); + mdp_disable_irq(MDP_DMA2_TERM); + + /* signal if pan function is waiting for the update completion */ + if (mfd->pan_waiting) { + mfd->pan_waiting = FALSE; + complete(&mfd->pan_comp); + } + } + up(&mfd->dma->mutex); +} + +void mdp_lcd_update_workqueue_handler(struct work_struct *work) +{ + struct msm_fb_data_type *mfd = NULL; + + mfd = container_of(work, struct msm_fb_data_type, dma_update_worker); + if (mfd) + mfd->dma_fnc(mfd); +} + +void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty, + boolean sync) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + MDPIBUF *iBuf; + int bpp = info->var.bits_per_pixel / 8; + + down(&mfd->sem); + iBuf = &mfd->ibuf; + iBuf->buf = (uint8 *) info->fix.smem_start; + iBuf->buf += info->var.xoffset * bpp + + info->var.yoffset * info->fix.line_length; + + iBuf->ibuf_width = info->var.xres_virtual; + iBuf->bpp = bpp; + + iBuf->vsync_enable = sync; + + if (dirty) { + /* + * ToDo: dirty region check inside var.xoffset+xres + * <-> var.yoffset+yres + */ + iBuf->dma_x = dirty->xoffset % info->var.xres; + iBuf->dma_y = dirty->yoffset % info->var.yres; + iBuf->dma_w = dirty->width; + iBuf->dma_h = dirty->height; + } else { + iBuf->dma_x = 0; + iBuf->dma_y = 0; + iBuf->dma_w = info->var.xres; + iBuf->dma_h = info->var.yres; + } + mfd->ibuf_flushed = FALSE; + up(&mfd->sem); +} + +void mdp_set_offset_info(struct fb_info *info, uint32 addr, uint32 sync) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + MDPIBUF *iBuf; + + int bpp = info->var.bits_per_pixel / 8; + + down(&mfd->sem); + iBuf = &mfd->ibuf; + iBuf->ibuf_width = info->var.xres_virtual; + iBuf->bpp = bpp; + iBuf->vsync_enable = sync; + iBuf->dma_x = 0; + iBuf->dma_y = 0; + iBuf->dma_w = info->var.xres; + iBuf->dma_h = info->var.yres; + iBuf->buf = (uint8 *) addr; + + mfd->ibuf_flushed = FALSE; + up(&mfd->sem); +} + +void mdp_dma_pan_update(struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + MDPIBUF *iBuf; + + iBuf = &mfd->ibuf; + + if (mfd->sw_currently_refreshing) { + /* we need to wait for the pending update */ + mfd->pan_waiting = TRUE; + if (!mfd->ibuf_flushed) { + wait_for_completion_killable(&mfd->pan_comp); + } + /* waiting for this update to complete */ + mfd->pan_waiting = TRUE; + wait_for_completion_killable(&mfd->pan_comp); + } else + mfd->dma_fnc(mfd); +} + +void mdp_refresh_screen(unsigned long data) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; + + if ((mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) { + init_timer(&mfd->refresh_timer); + mfd->refresh_timer.function = mdp_refresh_screen; + mfd->refresh_timer.data = data; + + if (mfd->dma->busy) + /* come back in 1 msec */ + mfd->refresh_timer.expires = jiffies + (HZ / 1000); + else + mfd->refresh_timer.expires = + jiffies + mfd->refresh_timer_duration; + + add_timer(&mfd->refresh_timer); + + if (!mfd->dma->busy) { + if (!queue_work(mdp_dma_wq, &mfd->dma_update_worker)) { + MSM_FB_DEBUG("mdp_dma: can't queue_work! -> \ + MDP/MDDI/LCD clock speed needs to be increased\n"); + } + } + } else { + if (!mfd->hw_refresh) + complete(&mfd->refresher_comp); + } +} diff --git a/drivers/staging/msm/mdp_dma_lcdc.c b/drivers/staging/msm/mdp_dma_lcdc.c new file mode 100644 index 000000000000..b57fa1a0ceb0 --- /dev/null +++ b/drivers/staging/msm/mdp_dma_lcdc.c @@ -0,0 +1,379 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/hrtimer.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/spinlock.h> + +#include <linux/fb.h> + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +#ifdef CONFIG_FB_MSM_MDP40 +#define LCDC_BASE 0xC0000 +#define DTV_BASE 0xD0000 +#define DMA_E_BASE 0xB0000 +#else +#define LCDC_BASE 0xE0000 +#endif + +#define DMA_P_BASE 0x90000 + +extern spinlock_t mdp_spin_lock; +#ifndef CONFIG_FB_MSM_MDP40 +extern uint32 mdp_intr_mask; +#endif + +int first_pixel_start_x; +int first_pixel_start_y; + +int mdp_lcdc_on(struct platform_device *pdev) +{ + int lcdc_width; + int lcdc_height; + int lcdc_bpp; + int lcdc_border_clr; + int lcdc_underflow_clr; + int lcdc_hsync_skew; + + int hsync_period; + int hsync_ctrl; + int vsync_period; + int display_hctl; + int display_v_start; + int display_v_end; + int active_hctl; + int active_h_start; + int active_h_end; + int active_v_start; + int active_v_end; + int ctrl_polarity; + int h_back_porch; + int h_front_porch; + int v_back_porch; + int v_front_porch; + int hsync_pulse_width; + int vsync_pulse_width; + int hsync_polarity; + int vsync_polarity; + int data_en_polarity; + int hsync_start_x; + int hsync_end_x; + uint8 *buf; + int bpp; + uint32 dma2_cfg_reg; + struct fb_info *fbi; + struct fb_var_screeninfo *var; + struct msm_fb_data_type *mfd; + uint32 dma_base; + uint32 timer_base = LCDC_BASE; + uint32 block = MDP_DMA2_BLOCK; + int ret; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + fbi = mfd->fbi; + var = &fbi->var; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf += fbi->var.xoffset * bpp + fbi->var.yoffset * fbi->fix.line_length; + + dma2_cfg_reg = DMA_PACK_ALIGN_LSB | DMA_DITHER_EN | DMA_OUT_SEL_LCDC; + + if (mfd->fb_imgType == MDP_BGR_565) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; + + if (bpp == 2) + dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565; + else if (bpp == 3) + dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB888; + else + dma2_cfg_reg |= DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888; + + switch (mfd->panel_info.bpp) { + case 24: + dma2_cfg_reg |= DMA_DSTC0G_8BITS | + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + break; + + case 18: + dma2_cfg_reg |= DMA_DSTC0G_6BITS | + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + break; + + case 16: + dma2_cfg_reg |= DMA_DSTC0G_6BITS | + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + break; + + default: + printk(KERN_ERR "mdp lcdc can't support format %d bpp!\n", + mfd->panel_info.bpp); + return -ENODEV; + } + + /* DMA register config */ + + dma_base = DMA_P_BASE; + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == HDMI_PANEL) + dma_base = DMA_E_BASE; +#endif + + /* starting address */ + MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf); + /* active window width and height */ + MDP_OUTP(MDP_BASE + dma_base + 0x4, ((fbi->var.yres) << 16) | + (fbi->var.xres)); + /* buffer ystride */ + MDP_OUTP(MDP_BASE + dma_base + 0xc, fbi->fix.line_length); + /* x/y coordinate = always 0 for lcdc */ + MDP_OUTP(MDP_BASE + dma_base + 0x10, 0); + /* dma config */ + MDP_OUTP(MDP_BASE + dma_base, dma2_cfg_reg); + + /* + * LCDC timing setting + */ + h_back_porch = var->left_margin; + h_front_porch = var->right_margin; + v_back_porch = var->upper_margin; + v_front_porch = var->lower_margin; + hsync_pulse_width = var->hsync_len; + vsync_pulse_width = var->vsync_len; + lcdc_border_clr = mfd->panel_info.lcdc.border_clr; + lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr; + lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew; + + lcdc_width = mfd->panel_info.xres; + lcdc_height = mfd->panel_info.yres; + lcdc_bpp = mfd->panel_info.bpp; + + hsync_period = + hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch; + hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; + hsync_start_x = hsync_pulse_width + h_back_porch; + hsync_end_x = hsync_period - h_front_porch - 1; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + + vsync_period = + (vsync_pulse_width + v_back_porch + lcdc_height + + v_front_porch) * hsync_period; + display_v_start = + (vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew; + display_v_end = + vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1; + + if (lcdc_width != var->xres) { + active_h_start = hsync_start_x + first_pixel_start_x; + active_h_end = active_h_start + var->xres - 1; + active_hctl = + ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; + } else { + active_hctl = 0; + } + + if (lcdc_height != var->yres) { + active_v_start = + display_v_start + first_pixel_start_y * hsync_period; + active_v_end = active_v_start + (var->yres) * hsync_period - 1; + active_v_start |= ACTIVE_START_Y_EN; + } else { + active_v_start = 0; + active_v_end = 0; + } + + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == HDMI_PANEL) { + block = MDP_DMA_E_BLOCK; + timer_base = DTV_BASE; + hsync_polarity = 0; + vsync_polarity = 0; + } else { + hsync_polarity = 1; + vsync_polarity = 1; + } + + lcdc_underflow_clr |= 0x80000000; /* enable recovery */ +#else + hsync_polarity = 0; + vsync_polarity = 0; +#endif + data_en_polarity = 0; + + ctrl_polarity = + (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); + + MDP_OUTP(MDP_BASE + timer_base + 0x4, hsync_ctrl); + MDP_OUTP(MDP_BASE + timer_base + 0x8, vsync_period); + MDP_OUTP(MDP_BASE + timer_base + 0xc, vsync_pulse_width * hsync_period); + if (timer_base == LCDC_BASE) { + MDP_OUTP(MDP_BASE + timer_base + 0x10, display_hctl); + MDP_OUTP(MDP_BASE + timer_base + 0x14, display_v_start); + MDP_OUTP(MDP_BASE + timer_base + 0x18, display_v_end); + MDP_OUTP(MDP_BASE + timer_base + 0x28, lcdc_border_clr); + MDP_OUTP(MDP_BASE + timer_base + 0x2c, lcdc_underflow_clr); + MDP_OUTP(MDP_BASE + timer_base + 0x30, lcdc_hsync_skew); + MDP_OUTP(MDP_BASE + timer_base + 0x38, ctrl_polarity); + MDP_OUTP(MDP_BASE + timer_base + 0x1c, active_hctl); + MDP_OUTP(MDP_BASE + timer_base + 0x20, active_v_start); + MDP_OUTP(MDP_BASE + timer_base + 0x24, active_v_end); + } else { + MDP_OUTP(MDP_BASE + timer_base + 0x18, display_hctl); + MDP_OUTP(MDP_BASE + timer_base + 0x1c, display_v_start); + MDP_OUTP(MDP_BASE + timer_base + 0x20, display_v_end); + MDP_OUTP(MDP_BASE + timer_base + 0x40, lcdc_border_clr); + MDP_OUTP(MDP_BASE + timer_base + 0x44, lcdc_underflow_clr); + MDP_OUTP(MDP_BASE + timer_base + 0x48, lcdc_hsync_skew); + MDP_OUTP(MDP_BASE + timer_base + 0x50, ctrl_polarity); + MDP_OUTP(MDP_BASE + timer_base + 0x2c, active_hctl); + MDP_OUTP(MDP_BASE + timer_base + 0x30, active_v_start); + MDP_OUTP(MDP_BASE + timer_base + 0x38, active_v_end); + } + + ret = panel_next_on(pdev); + if (ret == 0) { + /* enable LCDC block */ + MDP_OUTP(MDP_BASE + timer_base, 1); + mdp_pipe_ctrl(block, MDP_BLOCK_POWER_ON, FALSE); + } + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return ret; +} + +int mdp_lcdc_off(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + uint32 timer_base = LCDC_BASE; + uint32 block = MDP_DMA2_BLOCK; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == HDMI_PANEL) { + block = MDP_DMA_E_BLOCK; + timer_base = DTV_BASE; + } +#endif + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + timer_base, 0); + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_pipe_ctrl(block, MDP_BLOCK_POWER_OFF, FALSE); + + ret = panel_next_off(pdev); + + /* delay to make sure the last frame finishes */ + mdelay(100); + + return ret; +} + +void mdp_lcdc_update(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi = mfd->fbi; + uint8 *buf; + int bpp; + unsigned long flag; + uint32 dma_base; + int irq_block = MDP_DMA2_TERM; +#ifdef CONFIG_FB_MSM_MDP40 + int intr = INTR_DMA_P_DONE; +#endif + + if (!mfd->panel_power_on) + return; + + /* no need to power on cmd block since it's lcdc mode */ + + if (!mfd->ibuf.visible_swapped) { + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf += fbi->var.xoffset * bpp + + fbi->var.yoffset * fbi->fix.line_length; + } else { + /* we've done something to update the pointer. */ + bpp = mfd->ibuf.bpp; + buf = mfd->ibuf.buf; + } + + dma_base = DMA_P_BASE; + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == HDMI_PANEL) { + intr = INTR_DMA_E_DONE; + irq_block = MDP_DMA_E_TERM; + dma_base = DMA_E_BASE; + } +#endif + + /* starting address */ + MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf); + + /* enable LCDC irq */ + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(irq_block); + INIT_COMPLETION(mfd->dma->comp); + mfd->dma->waiting = TRUE; +#ifdef CONFIG_FB_MSM_MDP40 + outp32(MDP_INTR_CLEAR, intr); + mdp_intr_mask |= intr; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); +#else + outp32(MDP_INTR_CLEAR, LCDC_FRAME_START); + mdp_intr_mask |= LCDC_FRAME_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); +#endif + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (mfd->ibuf.vsync_enable) + wait_for_completion_killable(&mfd->dma->comp); + mdp_disable_irq(irq_block); +} diff --git a/drivers/staging/msm/mdp_dma_s.c b/drivers/staging/msm/mdp_dma_s.c new file mode 100644 index 000000000000..0c34a1010f17 --- /dev/null +++ b/drivers/staging/msm/mdp_dma_s.c @@ -0,0 +1,139 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/hrtimer.h> + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/spinlock.h> + +#include <linux/fb.h> + +#include "mdp.h" +#include "msm_fb.h" + +static void mdp_dma_s_update_lcd(struct msm_fb_data_type *mfd) +{ + MDPIBUF *iBuf = &mfd->ibuf; + int mddi_dest = FALSE; + uint32 outBpp = iBuf->bpp; + uint32 dma_s_cfg_reg; + uint8 *src; + struct msm_fb_panel_data *pdata = + (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + dma_s_cfg_reg = DMA_PACK_TIGHT | DMA_PACK_ALIGN_LSB | + DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS; + + if (mfd->fb_imgType == MDP_BGR_565) + dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma_s_cfg_reg |= DMA_PACK_PATTERN_RGB; + + if (outBpp == 4) + dma_s_cfg_reg |= DMA_IBUF_C3ALPHA_EN; + + if (outBpp == 2) + dma_s_cfg_reg |= DMA_IBUF_FORMAT_RGB565; + + if (mfd->panel_info.pdest != DISPLAY_2) { + printk(KERN_ERR "error: non-secondary type through dma_s!\n"); + return; + } + + if (mfd->panel_info.type == MDDI_PANEL) { + dma_s_cfg_reg |= DMA_OUT_SEL_MDDI; + mddi_dest = TRUE; + } else { + dma_s_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY; + outp32(MDP_EBI2_LCD1, mfd->data_port_phys); + } + + dma_s_cfg_reg |= DMA_DITHER_EN; + + src = (uint8 *) iBuf->buf; + /* starting input address */ + src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * outBpp; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* PIXELSIZE */ + MDP_OUTP(MDP_BASE + 0xa0004, (iBuf->dma_h << 16 | iBuf->dma_w)); + MDP_OUTP(MDP_BASE + 0xa0008, src); /* ibuf address */ + MDP_OUTP(MDP_BASE + 0xa000c, iBuf->ibuf_width * outBpp);/* ystride */ + + if (mfd->panel_info.bpp == 18) { + dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else { + dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } + + if (mddi_dest) { + MDP_OUTP(MDP_BASE + 0xa0010, (iBuf->dma_y << 16) | iBuf->dma_x); + MDP_OUTP(MDP_BASE + 0x00090, 1); + MDP_OUTP(MDP_BASE + 0x00094, + (MDDI_VDO_PACKET_DESC << 16) | + mfd->panel_info.mddi.vdopkt); + } else { + /* setting LCDC write window */ + pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w, + iBuf->dma_h); + } + + MDP_OUTP(MDP_BASE + 0xa0000, dma_s_cfg_reg); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd); +} + +void mdp_dma_s_update(struct msm_fb_data_type *mfd) +{ + down(&mfd->dma->mutex); + if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) { + down(&mfd->sem); + mdp_enable_irq(MDP_DMA_S_TERM); + mfd->dma->busy = TRUE; + INIT_COMPLETION(mfd->dma->comp); + mfd->ibuf_flushed = TRUE; + mdp_dma_s_update_lcd(mfd); + up(&mfd->sem); + + /* wait until DMA finishes the current job */ + wait_for_completion_killable(&mfd->dma->comp); + mdp_disable_irq(MDP_DMA_S_TERM); + + /* signal if pan function is waiting for the update completion */ + if (mfd->pan_waiting) { + mfd->pan_waiting = FALSE; + complete(&mfd->pan_comp); + } + } + up(&mfd->dma->mutex); +} diff --git a/drivers/staging/msm/mdp_dma_tv.c b/drivers/staging/msm/mdp_dma_tv.c new file mode 100644 index 000000000000..70989fb32c1d --- /dev/null +++ b/drivers/staging/msm/mdp_dma_tv.c @@ -0,0 +1,142 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/hrtimer.h> +#include <linux/delay.h> + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/spinlock.h> + +#include <linux/fb.h> + +#include "mdp.h" +#include "msm_fb.h" + +extern spinlock_t mdp_spin_lock; +extern uint32 mdp_intr_mask; + +int mdp_dma3_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct fb_info *fbi; + uint8 *buf; + int bpp; + int ret = 0; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + fbi = mfd->fbi; + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf += fbi->var.xoffset * bpp + + fbi->var.yoffset * fbi->fix.line_length; + + /* starting address[31..8] of Video frame buffer is CS0 */ + MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3); + + mdp_pipe_ctrl(MDP_DMA3_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + MDP_OUTP(MDP_BASE + 0xC0004, 0x4c60674); /* flicker filter enabled */ + MDP_OUTP(MDP_BASE + 0xC0010, 0x20); /* sobel treshold */ + + MDP_OUTP(MDP_BASE + 0xC0018, 0xeb0010); /* Y Max, Y min */ + MDP_OUTP(MDP_BASE + 0xC001C, 0xf00010); /* Cb Max, Cb min */ + MDP_OUTP(MDP_BASE + 0xC0020, 0xf00010); /* Cb Max, Cb min */ + + MDP_OUTP(MDP_BASE + 0xC000C, 0x67686970); /* add a few chars for CC */ + MDP_OUTP(MDP_BASE + 0xC0000, 0x1); /* MDP tv out enable */ + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + ret = panel_next_on(pdev); + + return ret; +} + +int mdp_dma3_off(struct platform_device *pdev) +{ + int ret = 0; + + ret = panel_next_off(pdev); + if (ret) + return ret; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + 0xC0000, 0x0); + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + mdp_pipe_ctrl(MDP_DMA3_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + /* delay to make sure the last frame finishes */ + mdelay(100); + + return ret; +} + +void mdp_dma3_update(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi = mfd->fbi; + uint8 *buf; + int bpp; + unsigned long flag; + + if (!mfd->panel_power_on) + return; + + /* no need to power on cmd block since dma3 is running */ + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf += fbi->var.xoffset * bpp + + fbi->var.yoffset * fbi->fix.line_length; + MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3); + + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(MDP_DMA3_TERM); + INIT_COMPLETION(mfd->dma->comp); + mfd->dma->waiting = TRUE; + + outp32(MDP_INTR_CLEAR, TV_OUT_DMA3_START); + mdp_intr_mask |= TV_OUT_DMA3_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + wait_for_completion_killable(&mfd->dma->comp); + mdp_disable_irq(MDP_DMA3_TERM); +} diff --git a/drivers/staging/msm/mdp_hw_init.c b/drivers/staging/msm/mdp_hw_init.c new file mode 100644 index 000000000000..807362ac592c --- /dev/null +++ b/drivers/staging/msm/mdp_hw_init.c @@ -0,0 +1,720 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "mdp.h" + +/* mdp primary csc limit vector */ +uint32 mdp_plv[] = { 0x10, 0xeb, 0x10, 0xf0 }; + +/* Color Coefficient matrix for YUV -> RGB */ +struct mdp_ccs mdp_ccs_yuv2rgb = { + MDP_CCS_YUV2RGB, + { + 0x254, + 0x000, + 0x331, + 0x254, + 0xff38, + 0xfe61, + 0x254, + 0x409, + 0x000, + }, + { +#ifdef CONFIG_FB_MSM_MDP31 + 0x1f0, + 0x180, + 0x180 +#else + 0x10, + 0x80, + 0x80 +#endif + } +}; + +/* Color Coefficient matrix for RGB -> YUV */ +struct mdp_ccs mdp_ccs_rgb2yuv = { + MDP_CCS_RGB2YUV, + { + 0x83, + 0x102, + 0x32, + 0xffb5, + 0xff6c, + 0xe1, + 0xe1, + 0xff45, + 0xffdc, + }, +#ifdef CONFIG_FB_MSM_MDP31 + { + 0x10, + 0x80, + 0x80 + } +#endif +}; + +static void mdp_load_lut_param(void) +{ + outpdw(MDP_BASE + 0x40800, 0x0); + outpdw(MDP_BASE + 0x40804, 0x151515); + outpdw(MDP_BASE + 0x40808, 0x1d1d1d); + outpdw(MDP_BASE + 0x4080c, 0x232323); + outpdw(MDP_BASE + 0x40810, 0x272727); + outpdw(MDP_BASE + 0x40814, 0x2b2b2b); + outpdw(MDP_BASE + 0x40818, 0x2f2f2f); + outpdw(MDP_BASE + 0x4081c, 0x333333); + outpdw(MDP_BASE + 0x40820, 0x363636); + outpdw(MDP_BASE + 0x40824, 0x393939); + outpdw(MDP_BASE + 0x40828, 0x3b3b3b); + outpdw(MDP_BASE + 0x4082c, 0x3e3e3e); + outpdw(MDP_BASE + 0x40830, 0x404040); + outpdw(MDP_BASE + 0x40834, 0x434343); + outpdw(MDP_BASE + 0x40838, 0x454545); + outpdw(MDP_BASE + 0x4083c, 0x474747); + outpdw(MDP_BASE + 0x40840, 0x494949); + outpdw(MDP_BASE + 0x40844, 0x4b4b4b); + outpdw(MDP_BASE + 0x40848, 0x4d4d4d); + outpdw(MDP_BASE + 0x4084c, 0x4f4f4f); + outpdw(MDP_BASE + 0x40850, 0x515151); + outpdw(MDP_BASE + 0x40854, 0x535353); + outpdw(MDP_BASE + 0x40858, 0x555555); + outpdw(MDP_BASE + 0x4085c, 0x565656); + outpdw(MDP_BASE + 0x40860, 0x585858); + outpdw(MDP_BASE + 0x40864, 0x5a5a5a); + outpdw(MDP_BASE + 0x40868, 0x5b5b5b); + outpdw(MDP_BASE + 0x4086c, 0x5d5d5d); + outpdw(MDP_BASE + 0x40870, 0x5e5e5e); + outpdw(MDP_BASE + 0x40874, 0x606060); + outpdw(MDP_BASE + 0x40878, 0x616161); + outpdw(MDP_BASE + 0x4087c, 0x636363); + outpdw(MDP_BASE + 0x40880, 0x646464); + outpdw(MDP_BASE + 0x40884, 0x666666); + outpdw(MDP_BASE + 0x40888, 0x676767); + outpdw(MDP_BASE + 0x4088c, 0x686868); + outpdw(MDP_BASE + 0x40890, 0x6a6a6a); + outpdw(MDP_BASE + 0x40894, 0x6b6b6b); + outpdw(MDP_BASE + 0x40898, 0x6c6c6c); + outpdw(MDP_BASE + 0x4089c, 0x6e6e6e); + outpdw(MDP_BASE + 0x408a0, 0x6f6f6f); + outpdw(MDP_BASE + 0x408a4, 0x707070); + outpdw(MDP_BASE + 0x408a8, 0x717171); + outpdw(MDP_BASE + 0x408ac, 0x727272); + outpdw(MDP_BASE + 0x408b0, 0x747474); + outpdw(MDP_BASE + 0x408b4, 0x757575); + outpdw(MDP_BASE + 0x408b8, 0x767676); + outpdw(MDP_BASE + 0x408bc, 0x777777); + outpdw(MDP_BASE + 0x408c0, 0x787878); + outpdw(MDP_BASE + 0x408c4, 0x797979); + outpdw(MDP_BASE + 0x408c8, 0x7a7a7a); + outpdw(MDP_BASE + 0x408cc, 0x7c7c7c); + outpdw(MDP_BASE + 0x408d0, 0x7d7d7d); + outpdw(MDP_BASE + 0x408d4, 0x7e7e7e); + outpdw(MDP_BASE + 0x408d8, 0x7f7f7f); + outpdw(MDP_BASE + 0x408dc, 0x808080); + outpdw(MDP_BASE + 0x408e0, 0x818181); + outpdw(MDP_BASE + 0x408e4, 0x828282); + outpdw(MDP_BASE + 0x408e8, 0x838383); + outpdw(MDP_BASE + 0x408ec, 0x848484); + outpdw(MDP_BASE + 0x408f0, 0x858585); + outpdw(MDP_BASE + 0x408f4, 0x868686); + outpdw(MDP_BASE + 0x408f8, 0x878787); + outpdw(MDP_BASE + 0x408fc, 0x888888); + outpdw(MDP_BASE + 0x40900, 0x898989); + outpdw(MDP_BASE + 0x40904, 0x8a8a8a); + outpdw(MDP_BASE + 0x40908, 0x8b8b8b); + outpdw(MDP_BASE + 0x4090c, 0x8c8c8c); + outpdw(MDP_BASE + 0x40910, 0x8d8d8d); + outpdw(MDP_BASE + 0x40914, 0x8e8e8e); + outpdw(MDP_BASE + 0x40918, 0x8f8f8f); + outpdw(MDP_BASE + 0x4091c, 0x8f8f8f); + outpdw(MDP_BASE + 0x40920, 0x909090); + outpdw(MDP_BASE + 0x40924, 0x919191); + outpdw(MDP_BASE + 0x40928, 0x929292); + outpdw(MDP_BASE + 0x4092c, 0x939393); + outpdw(MDP_BASE + 0x40930, 0x949494); + outpdw(MDP_BASE + 0x40934, 0x959595); + outpdw(MDP_BASE + 0x40938, 0x969696); + outpdw(MDP_BASE + 0x4093c, 0x969696); + outpdw(MDP_BASE + 0x40940, 0x979797); + outpdw(MDP_BASE + 0x40944, 0x989898); + outpdw(MDP_BASE + 0x40948, 0x999999); + outpdw(MDP_BASE + 0x4094c, 0x9a9a9a); + outpdw(MDP_BASE + 0x40950, 0x9b9b9b); + outpdw(MDP_BASE + 0x40954, 0x9c9c9c); + outpdw(MDP_BASE + 0x40958, 0x9c9c9c); + outpdw(MDP_BASE + 0x4095c, 0x9d9d9d); + outpdw(MDP_BASE + 0x40960, 0x9e9e9e); + outpdw(MDP_BASE + 0x40964, 0x9f9f9f); + outpdw(MDP_BASE + 0x40968, 0xa0a0a0); + outpdw(MDP_BASE + 0x4096c, 0xa0a0a0); + outpdw(MDP_BASE + 0x40970, 0xa1a1a1); + outpdw(MDP_BASE + 0x40974, 0xa2a2a2); + outpdw(MDP_BASE + 0x40978, 0xa3a3a3); + outpdw(MDP_BASE + 0x4097c, 0xa4a4a4); + outpdw(MDP_BASE + 0x40980, 0xa4a4a4); + outpdw(MDP_BASE + 0x40984, 0xa5a5a5); + outpdw(MDP_BASE + 0x40988, 0xa6a6a6); + outpdw(MDP_BASE + 0x4098c, 0xa7a7a7); + outpdw(MDP_BASE + 0x40990, 0xa7a7a7); + outpdw(MDP_BASE + 0x40994, 0xa8a8a8); + outpdw(MDP_BASE + 0x40998, 0xa9a9a9); + outpdw(MDP_BASE + 0x4099c, 0xaaaaaa); + outpdw(MDP_BASE + 0x409a0, 0xaaaaaa); + outpdw(MDP_BASE + 0x409a4, 0xababab); + outpdw(MDP_BASE + 0x409a8, 0xacacac); + outpdw(MDP_BASE + 0x409ac, 0xadadad); + outpdw(MDP_BASE + 0x409b0, 0xadadad); + outpdw(MDP_BASE + 0x409b4, 0xaeaeae); + outpdw(MDP_BASE + 0x409b8, 0xafafaf); + outpdw(MDP_BASE + 0x409bc, 0xafafaf); + outpdw(MDP_BASE + 0x409c0, 0xb0b0b0); + outpdw(MDP_BASE + 0x409c4, 0xb1b1b1); + outpdw(MDP_BASE + 0x409c8, 0xb2b2b2); + outpdw(MDP_BASE + 0x409cc, 0xb2b2b2); + outpdw(MDP_BASE + 0x409d0, 0xb3b3b3); + outpdw(MDP_BASE + 0x409d4, 0xb4b4b4); + outpdw(MDP_BASE + 0x409d8, 0xb4b4b4); + outpdw(MDP_BASE + 0x409dc, 0xb5b5b5); + outpdw(MDP_BASE + 0x409e0, 0xb6b6b6); + outpdw(MDP_BASE + 0x409e4, 0xb6b6b6); + outpdw(MDP_BASE + 0x409e8, 0xb7b7b7); + outpdw(MDP_BASE + 0x409ec, 0xb8b8b8); + outpdw(MDP_BASE + 0x409f0, 0xb8b8b8); + outpdw(MDP_BASE + 0x409f4, 0xb9b9b9); + outpdw(MDP_BASE + 0x409f8, 0xbababa); + outpdw(MDP_BASE + 0x409fc, 0xbababa); + outpdw(MDP_BASE + 0x40a00, 0xbbbbbb); + outpdw(MDP_BASE + 0x40a04, 0xbcbcbc); + outpdw(MDP_BASE + 0x40a08, 0xbcbcbc); + outpdw(MDP_BASE + 0x40a0c, 0xbdbdbd); + outpdw(MDP_BASE + 0x40a10, 0xbebebe); + outpdw(MDP_BASE + 0x40a14, 0xbebebe); + outpdw(MDP_BASE + 0x40a18, 0xbfbfbf); + outpdw(MDP_BASE + 0x40a1c, 0xc0c0c0); + outpdw(MDP_BASE + 0x40a20, 0xc0c0c0); + outpdw(MDP_BASE + 0x40a24, 0xc1c1c1); + outpdw(MDP_BASE + 0x40a28, 0xc1c1c1); + outpdw(MDP_BASE + 0x40a2c, 0xc2c2c2); + outpdw(MDP_BASE + 0x40a30, 0xc3c3c3); + outpdw(MDP_BASE + 0x40a34, 0xc3c3c3); + outpdw(MDP_BASE + 0x40a38, 0xc4c4c4); + outpdw(MDP_BASE + 0x40a3c, 0xc5c5c5); + outpdw(MDP_BASE + 0x40a40, 0xc5c5c5); + outpdw(MDP_BASE + 0x40a44, 0xc6c6c6); + outpdw(MDP_BASE + 0x40a48, 0xc6c6c6); + outpdw(MDP_BASE + 0x40a4c, 0xc7c7c7); + outpdw(MDP_BASE + 0x40a50, 0xc8c8c8); + outpdw(MDP_BASE + 0x40a54, 0xc8c8c8); + outpdw(MDP_BASE + 0x40a58, 0xc9c9c9); + outpdw(MDP_BASE + 0x40a5c, 0xc9c9c9); + outpdw(MDP_BASE + 0x40a60, 0xcacaca); + outpdw(MDP_BASE + 0x40a64, 0xcbcbcb); + outpdw(MDP_BASE + 0x40a68, 0xcbcbcb); + outpdw(MDP_BASE + 0x40a6c, 0xcccccc); + outpdw(MDP_BASE + 0x40a70, 0xcccccc); + outpdw(MDP_BASE + 0x40a74, 0xcdcdcd); + outpdw(MDP_BASE + 0x40a78, 0xcecece); + outpdw(MDP_BASE + 0x40a7c, 0xcecece); + outpdw(MDP_BASE + 0x40a80, 0xcfcfcf); + outpdw(MDP_BASE + 0x40a84, 0xcfcfcf); + outpdw(MDP_BASE + 0x40a88, 0xd0d0d0); + outpdw(MDP_BASE + 0x40a8c, 0xd0d0d0); + outpdw(MDP_BASE + 0x40a90, 0xd1d1d1); + outpdw(MDP_BASE + 0x40a94, 0xd2d2d2); + outpdw(MDP_BASE + 0x40a98, 0xd2d2d2); + outpdw(MDP_BASE + 0x40a9c, 0xd3d3d3); + outpdw(MDP_BASE + 0x40aa0, 0xd3d3d3); + outpdw(MDP_BASE + 0x40aa4, 0xd4d4d4); + outpdw(MDP_BASE + 0x40aa8, 0xd4d4d4); + outpdw(MDP_BASE + 0x40aac, 0xd5d5d5); + outpdw(MDP_BASE + 0x40ab0, 0xd6d6d6); + outpdw(MDP_BASE + 0x40ab4, 0xd6d6d6); + outpdw(MDP_BASE + 0x40ab8, 0xd7d7d7); + outpdw(MDP_BASE + 0x40abc, 0xd7d7d7); + outpdw(MDP_BASE + 0x40ac0, 0xd8d8d8); + outpdw(MDP_BASE + 0x40ac4, 0xd8d8d8); + outpdw(MDP_BASE + 0x40ac8, 0xd9d9d9); + outpdw(MDP_BASE + 0x40acc, 0xd9d9d9); + outpdw(MDP_BASE + 0x40ad0, 0xdadada); + outpdw(MDP_BASE + 0x40ad4, 0xdbdbdb); + outpdw(MDP_BASE + 0x40ad8, 0xdbdbdb); + outpdw(MDP_BASE + 0x40adc, 0xdcdcdc); + outpdw(MDP_BASE + 0x40ae0, 0xdcdcdc); + outpdw(MDP_BASE + 0x40ae4, 0xdddddd); + outpdw(MDP_BASE + 0x40ae8, 0xdddddd); + outpdw(MDP_BASE + 0x40aec, 0xdedede); + outpdw(MDP_BASE + 0x40af0, 0xdedede); + outpdw(MDP_BASE + 0x40af4, 0xdfdfdf); + outpdw(MDP_BASE + 0x40af8, 0xdfdfdf); + outpdw(MDP_BASE + 0x40afc, 0xe0e0e0); + outpdw(MDP_BASE + 0x40b00, 0xe0e0e0); + outpdw(MDP_BASE + 0x40b04, 0xe1e1e1); + outpdw(MDP_BASE + 0x40b08, 0xe1e1e1); + outpdw(MDP_BASE + 0x40b0c, 0xe2e2e2); + outpdw(MDP_BASE + 0x40b10, 0xe3e3e3); + outpdw(MDP_BASE + 0x40b14, 0xe3e3e3); + outpdw(MDP_BASE + 0x40b18, 0xe4e4e4); + outpdw(MDP_BASE + 0x40b1c, 0xe4e4e4); + outpdw(MDP_BASE + 0x40b20, 0xe5e5e5); + outpdw(MDP_BASE + 0x40b24, 0xe5e5e5); + outpdw(MDP_BASE + 0x40b28, 0xe6e6e6); + outpdw(MDP_BASE + 0x40b2c, 0xe6e6e6); + outpdw(MDP_BASE + 0x40b30, 0xe7e7e7); + outpdw(MDP_BASE + 0x40b34, 0xe7e7e7); + outpdw(MDP_BASE + 0x40b38, 0xe8e8e8); + outpdw(MDP_BASE + 0x40b3c, 0xe8e8e8); + outpdw(MDP_BASE + 0x40b40, 0xe9e9e9); + outpdw(MDP_BASE + 0x40b44, 0xe9e9e9); + outpdw(MDP_BASE + 0x40b48, 0xeaeaea); + outpdw(MDP_BASE + 0x40b4c, 0xeaeaea); + outpdw(MDP_BASE + 0x40b50, 0xebebeb); + outpdw(MDP_BASE + 0x40b54, 0xebebeb); + outpdw(MDP_BASE + 0x40b58, 0xececec); + outpdw(MDP_BASE + 0x40b5c, 0xececec); + outpdw(MDP_BASE + 0x40b60, 0xededed); + outpdw(MDP_BASE + 0x40b64, 0xededed); + outpdw(MDP_BASE + 0x40b68, 0xeeeeee); + outpdw(MDP_BASE + 0x40b6c, 0xeeeeee); + outpdw(MDP_BASE + 0x40b70, 0xefefef); + outpdw(MDP_BASE + 0x40b74, 0xefefef); + outpdw(MDP_BASE + 0x40b78, 0xf0f0f0); + outpdw(MDP_BASE + 0x40b7c, 0xf0f0f0); + outpdw(MDP_BASE + 0x40b80, 0xf1f1f1); + outpdw(MDP_BASE + 0x40b84, 0xf1f1f1); + outpdw(MDP_BASE + 0x40b88, 0xf2f2f2); + outpdw(MDP_BASE + 0x40b8c, 0xf2f2f2); + outpdw(MDP_BASE + 0x40b90, 0xf2f2f2); + outpdw(MDP_BASE + 0x40b94, 0xf3f3f3); + outpdw(MDP_BASE + 0x40b98, 0xf3f3f3); + outpdw(MDP_BASE + 0x40b9c, 0xf4f4f4); + outpdw(MDP_BASE + 0x40ba0, 0xf4f4f4); + outpdw(MDP_BASE + 0x40ba4, 0xf5f5f5); + outpdw(MDP_BASE + 0x40ba8, 0xf5f5f5); + outpdw(MDP_BASE + 0x40bac, 0xf6f6f6); + outpdw(MDP_BASE + 0x40bb0, 0xf6f6f6); + outpdw(MDP_BASE + 0x40bb4, 0xf7f7f7); + outpdw(MDP_BASE + 0x40bb8, 0xf7f7f7); + outpdw(MDP_BASE + 0x40bbc, 0xf8f8f8); + outpdw(MDP_BASE + 0x40bc0, 0xf8f8f8); + outpdw(MDP_BASE + 0x40bc4, 0xf9f9f9); + outpdw(MDP_BASE + 0x40bc8, 0xf9f9f9); + outpdw(MDP_BASE + 0x40bcc, 0xfafafa); + outpdw(MDP_BASE + 0x40bd0, 0xfafafa); + outpdw(MDP_BASE + 0x40bd4, 0xfafafa); + outpdw(MDP_BASE + 0x40bd8, 0xfbfbfb); + outpdw(MDP_BASE + 0x40bdc, 0xfbfbfb); + outpdw(MDP_BASE + 0x40be0, 0xfcfcfc); + outpdw(MDP_BASE + 0x40be4, 0xfcfcfc); + outpdw(MDP_BASE + 0x40be8, 0xfdfdfd); + outpdw(MDP_BASE + 0x40bec, 0xfdfdfd); + outpdw(MDP_BASE + 0x40bf0, 0xfefefe); + outpdw(MDP_BASE + 0x40bf4, 0xfefefe); + outpdw(MDP_BASE + 0x40bf8, 0xffffff); + outpdw(MDP_BASE + 0x40bfc, 0xffffff); + outpdw(MDP_BASE + 0x40c00, 0x0); + outpdw(MDP_BASE + 0x40c04, 0x0); + outpdw(MDP_BASE + 0x40c08, 0x0); + outpdw(MDP_BASE + 0x40c0c, 0x0); + outpdw(MDP_BASE + 0x40c10, 0x0); + outpdw(MDP_BASE + 0x40c14, 0x0); + outpdw(MDP_BASE + 0x40c18, 0x0); + outpdw(MDP_BASE + 0x40c1c, 0x0); + outpdw(MDP_BASE + 0x40c20, 0x0); + outpdw(MDP_BASE + 0x40c24, 0x0); + outpdw(MDP_BASE + 0x40c28, 0x0); + outpdw(MDP_BASE + 0x40c2c, 0x0); + outpdw(MDP_BASE + 0x40c30, 0x0); + outpdw(MDP_BASE + 0x40c34, 0x0); + outpdw(MDP_BASE + 0x40c38, 0x0); + outpdw(MDP_BASE + 0x40c3c, 0x0); + outpdw(MDP_BASE + 0x40c40, 0x10101); + outpdw(MDP_BASE + 0x40c44, 0x10101); + outpdw(MDP_BASE + 0x40c48, 0x10101); + outpdw(MDP_BASE + 0x40c4c, 0x10101); + outpdw(MDP_BASE + 0x40c50, 0x10101); + outpdw(MDP_BASE + 0x40c54, 0x10101); + outpdw(MDP_BASE + 0x40c58, 0x10101); + outpdw(MDP_BASE + 0x40c5c, 0x10101); + outpdw(MDP_BASE + 0x40c60, 0x10101); + outpdw(MDP_BASE + 0x40c64, 0x10101); + outpdw(MDP_BASE + 0x40c68, 0x20202); + outpdw(MDP_BASE + 0x40c6c, 0x20202); + outpdw(MDP_BASE + 0x40c70, 0x20202); + outpdw(MDP_BASE + 0x40c74, 0x20202); + outpdw(MDP_BASE + 0x40c78, 0x20202); + outpdw(MDP_BASE + 0x40c7c, 0x20202); + outpdw(MDP_BASE + 0x40c80, 0x30303); + outpdw(MDP_BASE + 0x40c84, 0x30303); + outpdw(MDP_BASE + 0x40c88, 0x30303); + outpdw(MDP_BASE + 0x40c8c, 0x30303); + outpdw(MDP_BASE + 0x40c90, 0x30303); + outpdw(MDP_BASE + 0x40c94, 0x40404); + outpdw(MDP_BASE + 0x40c98, 0x40404); + outpdw(MDP_BASE + 0x40c9c, 0x40404); + outpdw(MDP_BASE + 0x40ca0, 0x40404); + outpdw(MDP_BASE + 0x40ca4, 0x40404); + outpdw(MDP_BASE + 0x40ca8, 0x50505); + outpdw(MDP_BASE + 0x40cac, 0x50505); + outpdw(MDP_BASE + 0x40cb0, 0x50505); + outpdw(MDP_BASE + 0x40cb4, 0x50505); + outpdw(MDP_BASE + 0x40cb8, 0x60606); + outpdw(MDP_BASE + 0x40cbc, 0x60606); + outpdw(MDP_BASE + 0x40cc0, 0x60606); + outpdw(MDP_BASE + 0x40cc4, 0x70707); + outpdw(MDP_BASE + 0x40cc8, 0x70707); + outpdw(MDP_BASE + 0x40ccc, 0x70707); + outpdw(MDP_BASE + 0x40cd0, 0x70707); + outpdw(MDP_BASE + 0x40cd4, 0x80808); + outpdw(MDP_BASE + 0x40cd8, 0x80808); + outpdw(MDP_BASE + 0x40cdc, 0x80808); + outpdw(MDP_BASE + 0x40ce0, 0x90909); + outpdw(MDP_BASE + 0x40ce4, 0x90909); + outpdw(MDP_BASE + 0x40ce8, 0xa0a0a); + outpdw(MDP_BASE + 0x40cec, 0xa0a0a); + outpdw(MDP_BASE + 0x40cf0, 0xa0a0a); + outpdw(MDP_BASE + 0x40cf4, 0xb0b0b); + outpdw(MDP_BASE + 0x40cf8, 0xb0b0b); + outpdw(MDP_BASE + 0x40cfc, 0xb0b0b); + outpdw(MDP_BASE + 0x40d00, 0xc0c0c); + outpdw(MDP_BASE + 0x40d04, 0xc0c0c); + outpdw(MDP_BASE + 0x40d08, 0xd0d0d); + outpdw(MDP_BASE + 0x40d0c, 0xd0d0d); + outpdw(MDP_BASE + 0x40d10, 0xe0e0e); + outpdw(MDP_BASE + 0x40d14, 0xe0e0e); + outpdw(MDP_BASE + 0x40d18, 0xe0e0e); + outpdw(MDP_BASE + 0x40d1c, 0xf0f0f); + outpdw(MDP_BASE + 0x40d20, 0xf0f0f); + outpdw(MDP_BASE + 0x40d24, 0x101010); + outpdw(MDP_BASE + 0x40d28, 0x101010); + outpdw(MDP_BASE + 0x40d2c, 0x111111); + outpdw(MDP_BASE + 0x40d30, 0x111111); + outpdw(MDP_BASE + 0x40d34, 0x121212); + outpdw(MDP_BASE + 0x40d38, 0x121212); + outpdw(MDP_BASE + 0x40d3c, 0x131313); + outpdw(MDP_BASE + 0x40d40, 0x131313); + outpdw(MDP_BASE + 0x40d44, 0x141414); + outpdw(MDP_BASE + 0x40d48, 0x151515); + outpdw(MDP_BASE + 0x40d4c, 0x151515); + outpdw(MDP_BASE + 0x40d50, 0x161616); + outpdw(MDP_BASE + 0x40d54, 0x161616); + outpdw(MDP_BASE + 0x40d58, 0x171717); + outpdw(MDP_BASE + 0x40d5c, 0x171717); + outpdw(MDP_BASE + 0x40d60, 0x181818); + outpdw(MDP_BASE + 0x40d64, 0x191919); + outpdw(MDP_BASE + 0x40d68, 0x191919); + outpdw(MDP_BASE + 0x40d6c, 0x1a1a1a); + outpdw(MDP_BASE + 0x40d70, 0x1b1b1b); + outpdw(MDP_BASE + 0x40d74, 0x1b1b1b); + outpdw(MDP_BASE + 0x40d78, 0x1c1c1c); + outpdw(MDP_BASE + 0x40d7c, 0x1c1c1c); + outpdw(MDP_BASE + 0x40d80, 0x1d1d1d); + outpdw(MDP_BASE + 0x40d84, 0x1e1e1e); + outpdw(MDP_BASE + 0x40d88, 0x1f1f1f); + outpdw(MDP_BASE + 0x40d8c, 0x1f1f1f); + outpdw(MDP_BASE + 0x40d90, 0x202020); + outpdw(MDP_BASE + 0x40d94, 0x212121); + outpdw(MDP_BASE + 0x40d98, 0x212121); + outpdw(MDP_BASE + 0x40d9c, 0x222222); + outpdw(MDP_BASE + 0x40da0, 0x232323); + outpdw(MDP_BASE + 0x40da4, 0x242424); + outpdw(MDP_BASE + 0x40da8, 0x242424); + outpdw(MDP_BASE + 0x40dac, 0x252525); + outpdw(MDP_BASE + 0x40db0, 0x262626); + outpdw(MDP_BASE + 0x40db4, 0x272727); + outpdw(MDP_BASE + 0x40db8, 0x272727); + outpdw(MDP_BASE + 0x40dbc, 0x282828); + outpdw(MDP_BASE + 0x40dc0, 0x292929); + outpdw(MDP_BASE + 0x40dc4, 0x2a2a2a); + outpdw(MDP_BASE + 0x40dc8, 0x2b2b2b); + outpdw(MDP_BASE + 0x40dcc, 0x2c2c2c); + outpdw(MDP_BASE + 0x40dd0, 0x2c2c2c); + outpdw(MDP_BASE + 0x40dd4, 0x2d2d2d); + outpdw(MDP_BASE + 0x40dd8, 0x2e2e2e); + outpdw(MDP_BASE + 0x40ddc, 0x2f2f2f); + outpdw(MDP_BASE + 0x40de0, 0x303030); + outpdw(MDP_BASE + 0x40de4, 0x313131); + outpdw(MDP_BASE + 0x40de8, 0x323232); + outpdw(MDP_BASE + 0x40dec, 0x333333); + outpdw(MDP_BASE + 0x40df0, 0x333333); + outpdw(MDP_BASE + 0x40df4, 0x343434); + outpdw(MDP_BASE + 0x40df8, 0x353535); + outpdw(MDP_BASE + 0x40dfc, 0x363636); + outpdw(MDP_BASE + 0x40e00, 0x373737); + outpdw(MDP_BASE + 0x40e04, 0x383838); + outpdw(MDP_BASE + 0x40e08, 0x393939); + outpdw(MDP_BASE + 0x40e0c, 0x3a3a3a); + outpdw(MDP_BASE + 0x40e10, 0x3b3b3b); + outpdw(MDP_BASE + 0x40e14, 0x3c3c3c); + outpdw(MDP_BASE + 0x40e18, 0x3d3d3d); + outpdw(MDP_BASE + 0x40e1c, 0x3e3e3e); + outpdw(MDP_BASE + 0x40e20, 0x3f3f3f); + outpdw(MDP_BASE + 0x40e24, 0x404040); + outpdw(MDP_BASE + 0x40e28, 0x414141); + outpdw(MDP_BASE + 0x40e2c, 0x424242); + outpdw(MDP_BASE + 0x40e30, 0x434343); + outpdw(MDP_BASE + 0x40e34, 0x444444); + outpdw(MDP_BASE + 0x40e38, 0x464646); + outpdw(MDP_BASE + 0x40e3c, 0x474747); + outpdw(MDP_BASE + 0x40e40, 0x484848); + outpdw(MDP_BASE + 0x40e44, 0x494949); + outpdw(MDP_BASE + 0x40e48, 0x4a4a4a); + outpdw(MDP_BASE + 0x40e4c, 0x4b4b4b); + outpdw(MDP_BASE + 0x40e50, 0x4c4c4c); + outpdw(MDP_BASE + 0x40e54, 0x4d4d4d); + outpdw(MDP_BASE + 0x40e58, 0x4f4f4f); + outpdw(MDP_BASE + 0x40e5c, 0x505050); + outpdw(MDP_BASE + 0x40e60, 0x515151); + outpdw(MDP_BASE + 0x40e64, 0x525252); + outpdw(MDP_BASE + 0x40e68, 0x535353); + outpdw(MDP_BASE + 0x40e6c, 0x545454); + outpdw(MDP_BASE + 0x40e70, 0x565656); + outpdw(MDP_BASE + 0x40e74, 0x575757); + outpdw(MDP_BASE + 0x40e78, 0x585858); + outpdw(MDP_BASE + 0x40e7c, 0x595959); + outpdw(MDP_BASE + 0x40e80, 0x5b5b5b); + outpdw(MDP_BASE + 0x40e84, 0x5c5c5c); + outpdw(MDP_BASE + 0x40e88, 0x5d5d5d); + outpdw(MDP_BASE + 0x40e8c, 0x5e5e5e); + outpdw(MDP_BASE + 0x40e90, 0x606060); + outpdw(MDP_BASE + 0x40e94, 0x616161); + outpdw(MDP_BASE + 0x40e98, 0x626262); + outpdw(MDP_BASE + 0x40e9c, 0x646464); + outpdw(MDP_BASE + 0x40ea0, 0x656565); + outpdw(MDP_BASE + 0x40ea4, 0x666666); + outpdw(MDP_BASE + 0x40ea8, 0x686868); + outpdw(MDP_BASE + 0x40eac, 0x696969); + outpdw(MDP_BASE + 0x40eb0, 0x6a6a6a); + outpdw(MDP_BASE + 0x40eb4, 0x6c6c6c); + outpdw(MDP_BASE + 0x40eb8, 0x6d6d6d); + outpdw(MDP_BASE + 0x40ebc, 0x6f6f6f); + outpdw(MDP_BASE + 0x40ec0, 0x707070); + outpdw(MDP_BASE + 0x40ec4, 0x717171); + outpdw(MDP_BASE + 0x40ec8, 0x737373); + outpdw(MDP_BASE + 0x40ecc, 0x747474); + outpdw(MDP_BASE + 0x40ed0, 0x767676); + outpdw(MDP_BASE + 0x40ed4, 0x777777); + outpdw(MDP_BASE + 0x40ed8, 0x797979); + outpdw(MDP_BASE + 0x40edc, 0x7a7a7a); + outpdw(MDP_BASE + 0x40ee0, 0x7c7c7c); + outpdw(MDP_BASE + 0x40ee4, 0x7d7d7d); + outpdw(MDP_BASE + 0x40ee8, 0x7f7f7f); + outpdw(MDP_BASE + 0x40eec, 0x808080); + outpdw(MDP_BASE + 0x40ef0, 0x828282); + outpdw(MDP_BASE + 0x40ef4, 0x838383); + outpdw(MDP_BASE + 0x40ef8, 0x858585); + outpdw(MDP_BASE + 0x40efc, 0x868686); + outpdw(MDP_BASE + 0x40f00, 0x888888); + outpdw(MDP_BASE + 0x40f04, 0x898989); + outpdw(MDP_BASE + 0x40f08, 0x8b8b8b); + outpdw(MDP_BASE + 0x40f0c, 0x8d8d8d); + outpdw(MDP_BASE + 0x40f10, 0x8e8e8e); + outpdw(MDP_BASE + 0x40f14, 0x909090); + outpdw(MDP_BASE + 0x40f18, 0x919191); + outpdw(MDP_BASE + 0x40f1c, 0x939393); + outpdw(MDP_BASE + 0x40f20, 0x959595); + outpdw(MDP_BASE + 0x40f24, 0x969696); + outpdw(MDP_BASE + 0x40f28, 0x989898); + outpdw(MDP_BASE + 0x40f2c, 0x9a9a9a); + outpdw(MDP_BASE + 0x40f30, 0x9b9b9b); + outpdw(MDP_BASE + 0x40f34, 0x9d9d9d); + outpdw(MDP_BASE + 0x40f38, 0x9f9f9f); + outpdw(MDP_BASE + 0x40f3c, 0xa1a1a1); + outpdw(MDP_BASE + 0x40f40, 0xa2a2a2); + outpdw(MDP_BASE + 0x40f44, 0xa4a4a4); + outpdw(MDP_BASE + 0x40f48, 0xa6a6a6); + outpdw(MDP_BASE + 0x40f4c, 0xa7a7a7); + outpdw(MDP_BASE + 0x40f50, 0xa9a9a9); + outpdw(MDP_BASE + 0x40f54, 0xababab); + outpdw(MDP_BASE + 0x40f58, 0xadadad); + outpdw(MDP_BASE + 0x40f5c, 0xafafaf); + outpdw(MDP_BASE + 0x40f60, 0xb0b0b0); + outpdw(MDP_BASE + 0x40f64, 0xb2b2b2); + outpdw(MDP_BASE + 0x40f68, 0xb4b4b4); + outpdw(MDP_BASE + 0x40f6c, 0xb6b6b6); + outpdw(MDP_BASE + 0x40f70, 0xb8b8b8); + outpdw(MDP_BASE + 0x40f74, 0xbababa); + outpdw(MDP_BASE + 0x40f78, 0xbbbbbb); + outpdw(MDP_BASE + 0x40f7c, 0xbdbdbd); + outpdw(MDP_BASE + 0x40f80, 0xbfbfbf); + outpdw(MDP_BASE + 0x40f84, 0xc1c1c1); + outpdw(MDP_BASE + 0x40f88, 0xc3c3c3); + outpdw(MDP_BASE + 0x40f8c, 0xc5c5c5); + outpdw(MDP_BASE + 0x40f90, 0xc7c7c7); + outpdw(MDP_BASE + 0x40f94, 0xc9c9c9); + outpdw(MDP_BASE + 0x40f98, 0xcbcbcb); + outpdw(MDP_BASE + 0x40f9c, 0xcdcdcd); + outpdw(MDP_BASE + 0x40fa0, 0xcfcfcf); + outpdw(MDP_BASE + 0x40fa4, 0xd1d1d1); + outpdw(MDP_BASE + 0x40fa8, 0xd3d3d3); + outpdw(MDP_BASE + 0x40fac, 0xd5d5d5); + outpdw(MDP_BASE + 0x40fb0, 0xd7d7d7); + outpdw(MDP_BASE + 0x40fb4, 0xd9d9d9); + outpdw(MDP_BASE + 0x40fb8, 0xdbdbdb); + outpdw(MDP_BASE + 0x40fbc, 0xdddddd); + outpdw(MDP_BASE + 0x40fc0, 0xdfdfdf); + outpdw(MDP_BASE + 0x40fc4, 0xe1e1e1); + outpdw(MDP_BASE + 0x40fc8, 0xe3e3e3); + outpdw(MDP_BASE + 0x40fcc, 0xe5e5e5); + outpdw(MDP_BASE + 0x40fd0, 0xe7e7e7); + outpdw(MDP_BASE + 0x40fd4, 0xe9e9e9); + outpdw(MDP_BASE + 0x40fd8, 0xebebeb); + outpdw(MDP_BASE + 0x40fdc, 0xeeeeee); + outpdw(MDP_BASE + 0x40fe0, 0xf0f0f0); + outpdw(MDP_BASE + 0x40fe4, 0xf2f2f2); + outpdw(MDP_BASE + 0x40fe8, 0xf4f4f4); + outpdw(MDP_BASE + 0x40fec, 0xf6f6f6); + outpdw(MDP_BASE + 0x40ff0, 0xf8f8f8); + outpdw(MDP_BASE + 0x40ff4, 0xfbfbfb); + outpdw(MDP_BASE + 0x40ff8, 0xfdfdfd); + outpdw(MDP_BASE + 0x40ffc, 0xffffff); +} + +#define IRQ_EN_1__MDP_IRQ___M 0x00000800 + +void mdp_hw_init(void) +{ + int i; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* debug interface write access */ + outpdw(MDP_BASE + 0x60, 1); + + outp32(MDP_INTR_ENABLE, MDP_ANY_INTR_MASK); + outp32(MDP_EBI2_PORTMAP_MODE, 0x3); + outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8, 0x0); + outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc, 0x0); + outpdw(MDP_BASE + 0x60, 0x1); + mdp_load_lut_param(); + + /* + * clear up unused fg/main registers + */ + /* comp.plane 2&3 ystride */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0120, 0x0); + /* unpacked pattern */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x012c, 0x0); + /* unpacked pattern */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0130, 0x0); + /* unpacked pattern */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0134, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0158, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x15c, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0160, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0170, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0174, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x017c, 0x0); + + /* comp.plane 2 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0114, 0x0); + /* comp.plane 3 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0118, 0x0); + + /* clear up unused bg registers */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8, 0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0, 0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc, 0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0, 0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4, 0); + +#ifndef CONFIG_FB_MSM_MDP22 + MDP_OUTP(MDP_BASE + 0xE0000, 0); + MDP_OUTP(MDP_BASE + 0x100, 0xffffffff); + MDP_OUTP(MDP_BASE + 0x90070, 0); + MDP_OUTP(MDP_BASE + 0x94010, 1); + MDP_OUTP(MDP_BASE + 0x9401c, 2); +#endif + + /* + * limit vector + * pre gets applied before color matrix conversion + * post is after ccs + */ + writel(mdp_plv[0], MDP_CSC_PRE_LV1n(0)); + writel(mdp_plv[1], MDP_CSC_PRE_LV1n(1)); + writel(mdp_plv[2], MDP_CSC_PRE_LV1n(2)); + writel(mdp_plv[3], MDP_CSC_PRE_LV1n(3)); + +#ifdef CONFIG_FB_MSM_MDP31 + writel(mdp_plv[2], MDP_CSC_PRE_LV1n(4)); + writel(mdp_plv[3], MDP_CSC_PRE_LV1n(5)); + + writel(0, MDP_CSC_POST_LV1n(0)); + writel(0xff, MDP_CSC_POST_LV1n(1)); + writel(0, MDP_CSC_POST_LV1n(2)); + writel(0xff, MDP_CSC_POST_LV1n(3)); + writel(0, MDP_CSC_POST_LV1n(4)); + writel(0xff, MDP_CSC_POST_LV1n(5)); + + writel(0, MDP_CSC_PRE_LV2n(0)); + writel(0xff, MDP_CSC_PRE_LV2n(1)); + writel(0, MDP_CSC_PRE_LV2n(2)); + writel(0xff, MDP_CSC_PRE_LV2n(3)); + writel(0, MDP_CSC_PRE_LV2n(4)); + writel(0xff, MDP_CSC_PRE_LV2n(5)); + + writel(mdp_plv[0], MDP_CSC_POST_LV2n(0)); + writel(mdp_plv[1], MDP_CSC_POST_LV2n(1)); + writel(mdp_plv[2], MDP_CSC_POST_LV2n(2)); + writel(mdp_plv[3], MDP_CSC_POST_LV2n(3)); + writel(mdp_plv[2], MDP_CSC_POST_LV2n(4)); + writel(mdp_plv[3], MDP_CSC_POST_LV2n(5)); +#endif + + /* primary forward matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(mdp_ccs_rgb2yuv.ccs[i], MDP_CSC_PFMVn(i)); + +#ifdef CONFIG_FB_MSM_MDP31 + for (i = 0; i < MDP_BV_SIZE; i++) + writel(mdp_ccs_rgb2yuv.bv[i], MDP_CSC_POST_BV2n(i)); + + writel(0, MDP_CSC_PRE_BV2n(0)); + writel(0, MDP_CSC_PRE_BV2n(1)); + writel(0, MDP_CSC_PRE_BV2n(2)); +#endif + /* primary reverse matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(mdp_ccs_yuv2rgb.ccs[i], MDP_CSC_PRMVn(i)); + + for (i = 0; i < MDP_BV_SIZE; i++) + writel(mdp_ccs_yuv2rgb.bv[i], MDP_CSC_PRE_BV1n(i)); + +#ifdef CONFIG_FB_MSM_MDP31 + writel(0, MDP_CSC_POST_BV1n(0)); + writel(0, MDP_CSC_POST_BV1n(1)); + writel(0, MDP_CSC_POST_BV1n(2)); + + outpdw(MDP_BASE + 0x30010, 0x03e0); + outpdw(MDP_BASE + 0x30014, 0x0360); + outpdw(MDP_BASE + 0x30018, 0x0120); + outpdw(MDP_BASE + 0x3001c, 0x0140); +#endif + mdp_init_scale_table(); + +#ifndef CONFIG_FB_MSM_MDP31 + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0104, + ((16 << 6) << 16) | (16) << 6); +#endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} \ No newline at end of file diff --git a/drivers/staging/msm/mdp_ppp.c b/drivers/staging/msm/mdp_ppp.c new file mode 100644 index 000000000000..c35a6aebca14 --- /dev/null +++ b/drivers/staging/msm/mdp_ppp.c @@ -0,0 +1,1502 @@ +/* drivers/video/msm/src/drv/mdp/mdp_ppp.c + * + * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <msm_mdp.h> +#include <linux/file.h> +#include <linux/major.h> + +#include "linux/proc_fs.h" + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> + +#include "mdp.h" +#include "msm_fb.h" + +#define MDP_IS_IMGTYPE_BAD(x) (((x) >= MDP_IMGTYPE_LIMIT) && \ + (((x) < MDP_IMGTYPE2_START) || \ + ((x) >= MDP_IMGTYPE_LIMIT2))) + +static uint32_t bytes_per_pixel[] = { + [MDP_RGB_565] = 2, + [MDP_RGB_888] = 3, + [MDP_XRGB_8888] = 4, + [MDP_ARGB_8888] = 4, + [MDP_RGBA_8888] = 4, + [MDP_BGRA_8888] = 4, + [MDP_Y_CBCR_H2V1] = 1, + [MDP_Y_CBCR_H2V2] = 1, + [MDP_Y_CRCB_H2V1] = 1, + [MDP_Y_CRCB_H2V2] = 1, + [MDP_YCRYCB_H2V1] = 2, + [MDP_BGR_565] = 2 +}; + +extern uint32 mdp_plv[]; +extern struct semaphore mdp_ppp_mutex; + +uint32_t mdp_get_bytes_per_pixel(uint32_t format) +{ + uint32_t bpp = 0; + if (format < ARRAY_SIZE(bytes_per_pixel)) + bpp = bytes_per_pixel[format]; + + BUG_ON(!bpp); + return bpp; +} + +static uint32 mdp_conv_matx_rgb2yuv(uint32 input_pixel, + uint16 *matrix_and_bias_vector, + uint32 *clamp_vector, + uint32 *look_up_table) +{ + uint8 input_C2, input_C0, input_C1; + uint32 output; + int32 comp_C2, comp_C1, comp_C0, temp; + int32 temp1, temp2, temp3; + int32 matrix[9]; + int32 bias_vector[3]; + int32 Y_low_limit, Y_high_limit, C_low_limit, C_high_limit; + int32 i; + uint32 _is_lookup_table_enabled; + + input_C2 = (input_pixel >> 16) & 0xFF; + input_C1 = (input_pixel >> 8) & 0xFF; + input_C0 = (input_pixel >> 0) & 0xFF; + + comp_C0 = input_C0; + comp_C1 = input_C1; + comp_C2 = input_C2; + + for (i = 0; i < 9; i++) + matrix[i] = + ((int32) (((int32) matrix_and_bias_vector[i]) << 20)) >> 20; + + bias_vector[0] = (int32) (matrix_and_bias_vector[9] & 0xFF); + bias_vector[1] = (int32) (matrix_and_bias_vector[10] & 0xFF); + bias_vector[2] = (int32) (matrix_and_bias_vector[11] & 0xFF); + + Y_low_limit = (int32) clamp_vector[0]; + Y_high_limit = (int32) clamp_vector[1]; + C_low_limit = (int32) clamp_vector[2]; + C_high_limit = (int32) clamp_vector[3]; + + if (look_up_table == 0) /* check for NULL point */ + _is_lookup_table_enabled = 0; + else + _is_lookup_table_enabled = 1; + + if (_is_lookup_table_enabled == 1) { + comp_C2 = (look_up_table[comp_C2] >> 16) & 0xFF; + comp_C1 = (look_up_table[comp_C1] >> 8) & 0xFF; + comp_C0 = (look_up_table[comp_C0] >> 0) & 0xFF; + } + /* + * Color Conversion + * reorder input colors + */ + temp = comp_C2; + comp_C2 = comp_C1; + comp_C1 = comp_C0; + comp_C0 = temp; + + /* matrix multiplication */ + temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2]; + temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5]; + temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8]; + + comp_C0 = temp1 + 0x100; + comp_C1 = temp2 + 0x100; + comp_C2 = temp3 + 0x100; + + /* take interger part */ + comp_C0 >>= 9; + comp_C1 >>= 9; + comp_C2 >>= 9; + + /* post bias (+) */ + comp_C0 += bias_vector[0]; + comp_C1 += bias_vector[1]; + comp_C2 += bias_vector[2]; + + /* limit pixel to 8-bit */ + if (comp_C0 < 0) + comp_C0 = 0; + + if (comp_C0 > 255) + comp_C0 = 255; + + if (comp_C1 < 0) + comp_C1 = 0; + + if (comp_C1 > 255) + comp_C1 = 255; + + if (comp_C2 < 0) + comp_C2 = 0; + + if (comp_C2 > 255) + comp_C2 = 255; + + /* clamp */ + if (comp_C0 < Y_low_limit) + comp_C0 = Y_low_limit; + + if (comp_C0 > Y_high_limit) + comp_C0 = Y_high_limit; + + if (comp_C1 < C_low_limit) + comp_C1 = C_low_limit; + + if (comp_C1 > C_high_limit) + comp_C1 = C_high_limit; + + if (comp_C2 < C_low_limit) + comp_C2 = C_low_limit; + + if (comp_C2 > C_high_limit) + comp_C2 = C_high_limit; + + output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0; + return output; +} + +uint32 mdp_conv_matx_yuv2rgb(uint32 input_pixel, + uint16 *matrix_and_bias_vector, + uint32 *clamp_vector, uint32 *look_up_table) +{ + uint8 input_C2, input_C0, input_C1; + uint32 output; + int32 comp_C2, comp_C1, comp_C0, temp; + int32 temp1, temp2, temp3; + int32 matrix[9]; + int32 bias_vector[3]; + int32 Y_low_limit, Y_high_limit, C_low_limit, C_high_limit; + int32 i; + uint32 _is_lookup_table_enabled; + + input_C2 = (input_pixel >> 16) & 0xFF; + input_C1 = (input_pixel >> 8) & 0xFF; + input_C0 = (input_pixel >> 0) & 0xFF; + + comp_C0 = input_C0; + comp_C1 = input_C1; + comp_C2 = input_C2; + + for (i = 0; i < 9; i++) + matrix[i] = + ((int32) (((int32) matrix_and_bias_vector[i]) << 20)) >> 20; + + bias_vector[0] = (int32) (matrix_and_bias_vector[9] & 0xFF); + bias_vector[1] = (int32) (matrix_and_bias_vector[10] & 0xFF); + bias_vector[2] = (int32) (matrix_and_bias_vector[11] & 0xFF); + + Y_low_limit = (int32) clamp_vector[0]; + Y_high_limit = (int32) clamp_vector[1]; + C_low_limit = (int32) clamp_vector[2]; + C_high_limit = (int32) clamp_vector[3]; + + if (look_up_table == 0) /* check for NULL point */ + _is_lookup_table_enabled = 0; + else + _is_lookup_table_enabled = 1; + + /* clamp */ + if (comp_C0 < Y_low_limit) + comp_C0 = Y_low_limit; + + if (comp_C0 > Y_high_limit) + comp_C0 = Y_high_limit; + + if (comp_C1 < C_low_limit) + comp_C1 = C_low_limit; + + if (comp_C1 > C_high_limit) + comp_C1 = C_high_limit; + + if (comp_C2 < C_low_limit) + comp_C2 = C_low_limit; + + if (comp_C2 > C_high_limit) + comp_C2 = C_high_limit; + + /* + * Color Conversion + * pre bias (-) + */ + comp_C0 -= bias_vector[0]; + comp_C1 -= bias_vector[1]; + comp_C2 -= bias_vector[2]; + + /* matrix multiplication */ + temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2]; + temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5]; + temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8]; + + comp_C0 = temp1 + 0x100; + comp_C1 = temp2 + 0x100; + comp_C2 = temp3 + 0x100; + + /* take interger part */ + comp_C0 >>= 9; + comp_C1 >>= 9; + comp_C2 >>= 9; + + /* reorder output colors */ + temp = comp_C0; + comp_C0 = comp_C1; + comp_C1 = comp_C2; + comp_C2 = temp; + + /* limit pixel to 8-bit */ + if (comp_C0 < 0) + comp_C0 = 0; + + if (comp_C0 > 255) + comp_C0 = 255; + + if (comp_C1 < 0) + comp_C1 = 0; + + if (comp_C1 > 255) + comp_C1 = 255; + + if (comp_C2 < 0) + comp_C2 = 0; + + if (comp_C2 > 255) + comp_C2 = 255; + + /* Look-up table */ + if (_is_lookup_table_enabled == 1) { + comp_C2 = (look_up_table[comp_C2] >> 16) & 0xFF; + comp_C1 = (look_up_table[comp_C1] >> 8) & 0xFF; + comp_C0 = (look_up_table[comp_C0] >> 0) & 0xFF; + } + + output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0; + return output; +} + +static uint32 mdp_calc_tpval(MDPIMG *mdpImg) +{ + uint32 tpVal; + uint8 plane_tp; + + tpVal = 0; + if ((mdpImg->imgType == MDP_RGB_565) + || (mdpImg->imgType == MDP_BGR_565)) { + /* + * transparent color conversion into 24 bpp + * + * C2R_8BIT + * left shift the entire bit and or it with the upper most bits + */ + plane_tp = (uint8) ((mdpImg->tpVal & 0xF800) >> 11); + tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 16; + + /* C1B_8BIT */ + plane_tp = (uint8) (mdpImg->tpVal & 0x1F); + tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 8; + + /* C0G_8BIT */ + plane_tp = (uint8) ((mdpImg->tpVal & 0x7E0) >> 5); + tpVal |= ((plane_tp << 2) | ((plane_tp & 0x30) >> 4)); + } else { + /* 24bit RGB to RBG conversion */ + + tpVal = (mdpImg->tpVal & 0xFF00) >> 8; + tpVal |= (mdpImg->tpVal & 0xFF) << 8; + tpVal |= (mdpImg->tpVal & 0xFF0000); + } + + return tpVal; +} + +static uint8 *mdp_get_chroma_addr(MDPIBUF *iBuf) +{ + uint8 *dest1; + + dest1 = NULL; + switch (iBuf->ibuf_type) { + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + dest1 = (uint8 *) iBuf->buf; + dest1 += iBuf->ibuf_width * iBuf->ibuf_height * iBuf->bpp; + break; + + default: + break; + } + + return dest1; +} + +static void mdp_ppp_setbg(MDPIBUF *iBuf) +{ + uint8 *bg0_addr; + uint8 *bg1_addr; + uint32 bg0_ystride, bg1_ystride; + uint32 ppp_src_cfg_reg, unpack_pattern; + int v_slice, h_slice; + + v_slice = h_slice = 1; + bg0_addr = (uint8 *) iBuf->buf; + bg1_addr = mdp_get_chroma_addr(iBuf); + + bg0_ystride = iBuf->ibuf_width * iBuf->bpp; + bg1_ystride = iBuf->ibuf_width * iBuf->bpp; + + switch (iBuf->ibuf_type) { + case MDP_BGR_565: + case MDP_RGB_565: + /* 888 = 3bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_5BITS | PPP_SRC_C0G_6BITS | + PPP_SRC_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->ibuf_type == MDP_RGB_565) + unpack_pattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8); + break; + + case MDP_RGB_888: + /* + * 888 = 3bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_INTERLVD; + + unpack_pattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + break; + + case MDP_BGRA_8888: + case MDP_RGBA_8888: + case MDP_ARGB_8888: + case MDP_XRGB_8888: + /* + * 8888 = 4bytes + * ARGB = 4Components + * ARGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_C3A_8BITS | PPP_SRC_C3_ALPHA_EN | + PPP_SRC_BPP_INTERLVD_4BYTES | PPP_SRC_INTERLVD_4COMPONENTS | + PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->ibuf_type == MDP_BGRA_8888) + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else if (iBuf->ibuf_type == MDP_RGBA_8888) + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, + 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | + PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1) + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + v_slice = h_slice = 2; + break; + + case MDP_YCRYCB_H2V1: + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_4COMPONENTS | + PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB; + + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8); + h_slice = 2; + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | + PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1) + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + h_slice = 2; + break; + + default: + return; + } + + /* starting input address adjustment */ + mdp_adjust_start_addr(&bg0_addr, &bg1_addr, v_slice, h_slice, + iBuf->roi.lcd_x, iBuf->roi.lcd_y, + iBuf->ibuf_width, iBuf->ibuf_height, iBuf->bpp, + iBuf, 1); + + /* + * 0x01c0: background plane 0 addr + * 0x01c4: background plane 1 addr + * 0x01c8: background plane 2 addr + * 0x01cc: bg y stride for plane 0 and 1 + * 0x01d0: bg y stride for plane 2 + * 0x01d4: bg src PPP config + * 0x01d8: unpack pattern + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c0, bg0_addr); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c4, bg1_addr); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01cc, + (bg1_ystride << 16) | bg0_ystride); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d4, ppp_src_cfg_reg); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d8, unpack_pattern); +} + +#define IS_PSEUDOPLNR(img) ((img == MDP_Y_CRCB_H2V2) | \ + (img == MDP_Y_CBCR_H2V2) | \ + (img == MDP_Y_CRCB_H2V1) | \ + (img == MDP_Y_CBCR_H2V1)) + +#define IMG_LEN(rect_h, w, rect_w, bpp) (((rect_h) * w) * bpp) + +#define Y_TO_CRCB_RATIO(format) \ + ((format == MDP_Y_CBCR_H2V2 || format == MDP_Y_CRCB_H2V2) ? 2 :\ + (format == MDP_Y_CBCR_H2V1 || format == MDP_Y_CRCB_H2V1) ? 1 : 1) + +static void get_len(struct mdp_img *img, struct mdp_rect *rect, uint32_t bpp, + uint32_t *len0, uint32_t *len1) +{ + *len0 = IMG_LEN(rect->h, img->width, rect->w, bpp); + if (IS_PSEUDOPLNR(img->format)) + *len1 = *len0/Y_TO_CRCB_RATIO(img->format); + else + *len1 = 0; +} + +static void flush_imgs(struct mdp_blit_req *req, int src_bpp, int dst_bpp, + struct file *p_src_file, struct file *p_dst_file) +{ +#ifdef CONFIG_ANDROID_PMEM + uint32_t src0_len, src1_len, dst0_len, dst1_len; + + /* flush src images to memory before dma to mdp */ + get_len(&req->src, &req->src_rect, src_bpp, + &src0_len, &src1_len); + + flush_pmem_file(p_src_file, + req->src.offset, src0_len); + + if (IS_PSEUDOPLNR(req->src.format)) + flush_pmem_file(p_src_file, + req->src.offset + src0_len, src1_len); + + get_len(&req->dst, &req->dst_rect, dst_bpp, &dst0_len, &dst1_len); + flush_pmem_file(p_dst_file, req->dst.offset, dst0_len); + + if (IS_PSEUDOPLNR(req->dst.format)) + flush_pmem_file(p_dst_file, + req->dst.offset + dst0_len, dst1_len); +#endif +} + +static void mdp_start_ppp(struct msm_fb_data_type *mfd, MDPIBUF *iBuf, +struct mdp_blit_req *req, struct file *p_src_file, struct file *p_dst_file) +{ + uint8 *src0, *src1; + uint8 *dest0, *dest1; + uint16 inpBpp; + uint32 dest0_ystride; + uint32 src_width; + uint32 src_height; + uint32 src0_ystride; + uint32 dst_roi_width; + uint32 dst_roi_height; + uint32 ppp_src_cfg_reg, ppp_operation_reg, ppp_dst_cfg_reg; + uint32 alpha, tpVal; + uint32 packPattern; + uint32 dst_packPattern; + boolean inputRGB, outputRGB, pseudoplanr_output; + int sv_slice, sh_slice; + int dv_slice, dh_slice; + boolean perPixelAlpha = FALSE; + boolean ppp_lookUp_enable = FALSE; + + sv_slice = sh_slice = dv_slice = dh_slice = 1; + alpha = tpVal = 0; + src_width = iBuf->mdpImg.width; + src_height = iBuf->roi.y + iBuf->roi.height; + src1 = NULL; + dest1 = NULL; + + inputRGB = outputRGB = TRUE; + pseudoplanr_output = FALSE; + ppp_operation_reg = 0; + ppp_dst_cfg_reg = 0; + ppp_src_cfg_reg = 0; + + /* Wait for the pipe to clear */ + do { } while (mdp_ppp_pipe_wait() <= 0); + + /* + * destination config + */ + switch (iBuf->ibuf_type) { + case MDP_RGB_888: + dst_packPattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + ppp_dst_cfg_reg = + PPP_DST_C0G_8BIT | PPP_DST_C1B_8BIT | PPP_DST_C2R_8BIT | + PPP_DST_PACKET_CNT_INTERLVD_3ELEM | PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | PPP_DST_OUT_SEL_AXI | + PPP_DST_BPP_3BYTES | PPP_DST_PLANE_INTERLVD; + break; + + case MDP_XRGB_8888: + case MDP_ARGB_8888: + case MDP_RGBA_8888: + if (iBuf->ibuf_type == MDP_BGRA_8888) + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else if (iBuf->ibuf_type == MDP_RGBA_8888) + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, + 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + + ppp_dst_cfg_reg = PPP_DST_C0G_8BIT | + PPP_DST_C1B_8BIT | + PPP_DST_C2R_8BIT | + PPP_DST_C3A_8BIT | + PPP_DST_C3ALPHA_EN | + PPP_DST_PACKET_CNT_INTERLVD_4ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | + PPP_DST_BPP_4BYTES | PPP_DST_PLANE_INTERLVD; + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V2) + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + + ppp_dst_cfg_reg = PPP_DST_C2R_8BIT | + PPP_DST_C0G_8BIT | + PPP_DST_C1B_8BIT | + PPP_DST_C3A_8BIT | + PPP_DST_PACKET_CNT_INTERLVD_2ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES; + + ppp_operation_reg |= PPP_OP_DST_CHROMA_420; + outputRGB = FALSE; + pseudoplanr_output = TRUE; + /* + * vertically (y direction) and horizontally (x direction) + * sample reduction by 2 + */ + + /* + * H2V2(YUV420) Cosite + * + * Y Y Y Y + * CbCr CbCr + * Y Y Y Y + * Y Y Y Y + * CbCr CbCr + * Y Y Y Y + */ + dv_slice = dh_slice = 2; + + /* (x,y) and (width,height) must be even numbern */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + + iBuf->roi.lcd_y = (iBuf->roi.lcd_y / 2) * 2; + iBuf->roi.dst_height = (iBuf->roi.dst_height / 2) * 2; + iBuf->roi.y = (iBuf->roi.y / 2) * 2; + iBuf->roi.height = (iBuf->roi.height / 2) * 2; + break; + + case MDP_YCRYCB_H2V1: + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8); + ppp_dst_cfg_reg = + PPP_DST_C2R_8BIT | PPP_DST_C0G_8BIT | PPP_DST_C1B_8BIT | + PPP_DST_C3A_8BIT | PPP_DST_PACKET_CNT_INTERLVD_4ELEM | + PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES | + PPP_DST_PLANE_INTERLVD; + + ppp_operation_reg |= PPP_OP_DST_CHROMA_H2V1; + outputRGB = FALSE; + /* + * horizontally (x direction) sample reduction by 2 + * + * H2V1(YUV422) Cosite + * + * YCbCr Y YCbCr Y + * YCbCr Y YCbCr Y + * YCbCr Y YCbCr Y + * YCbCr Y YCbCr Y + */ + dh_slice = 2; + + /* + * if it's TV-Out/MDP_YCRYCB_H2V1, let's go through the + * preloaded gamma setting of 2.2 when the content is + * non-linear ppp_lookUp_enable = TRUE; + */ + + /* x and width must be even number */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1) + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + + ppp_dst_cfg_reg = PPP_DST_C2R_8BIT | + PPP_DST_C0G_8BIT | + PPP_DST_C1B_8BIT | + PPP_DST_C3A_8BIT | + PPP_DST_PACKET_CNT_INTERLVD_2ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES; + + ppp_operation_reg |= PPP_OP_DST_CHROMA_H2V1; + outputRGB = FALSE; + pseudoplanr_output = TRUE; + /* horizontally (x direction) sample reduction by 2 */ + dh_slice = 2; + + /* x and width must be even number */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + break; + + case MDP_BGR_565: + case MDP_RGB_565: + default: + if (iBuf->ibuf_type == MDP_RGB_565) + dst_packPattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8); + + ppp_dst_cfg_reg = PPP_DST_C0G_6BIT | + PPP_DST_C1B_5BIT | + PPP_DST_C2R_5BIT | + PPP_DST_PACKET_CNT_INTERLVD_3ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | + PPP_DST_BPP_2BYTES | PPP_DST_PLANE_INTERLVD; + break; + } + + /* source config */ + switch (iBuf->mdpImg.imgType) { + case MDP_RGB_888: + inpBpp = 3; + /* + * 565 = 2bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + packPattern = MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB | + PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB; + break; + + case MDP_BGRA_8888: + case MDP_RGBA_8888: + case MDP_ARGB_8888: + perPixelAlpha = TRUE; + case MDP_XRGB_8888: + inpBpp = 4; + /* + * 8888 = 4bytes + * ARGB = 4Components + * ARGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_C3A_8BITS | + PPP_SRC_C3_ALPHA_EN | PPP_SRC_BPP_INTERLVD_4BYTES | + PPP_SRC_INTERLVD_4COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->mdpImg.imgType == MDP_BGRA_8888) + packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else if (iBuf->mdpImg.imgType == MDP_RGBA_8888) + packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, + 8); + else + packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB | + PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB; + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + inpBpp = 1; + src1 = (uint8 *) iBuf->mdpImg.cbcr_addr; + + /* + * CbCr = 2bytes + * CbCr = 2Components + * Y+CbCr + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->mdpImg.imgType == MDP_Y_CRCB_H2V2) + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + else + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_YCBCR | + PPP_OP_SRC_CHROMA_420 | + PPP_OP_SRC_CHROMA_COSITE | + PPP_OP_DST_CHROMA_RGB | PPP_OP_DST_CHROMA_COSITE; + + inputRGB = FALSE; + sh_slice = sv_slice = 2; + break; + + case MDP_YCRYCB_H2V1: + inpBpp = 2; + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_4COMPONENTS | + PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB; + + packPattern = + MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8); + + ppp_operation_reg |= PPP_OP_SRC_CHROMA_H2V1 | + PPP_OP_SRC_CHROMA_COSITE | PPP_OP_DST_CHROMA_COSITE; + + /* + * if it's TV-Out/MDP_YCRYCB_H2V1, let's go through the + * preloaded inverse gamma setting of 2.2 since they're + * symetric when the content is non-linear + * ppp_lookUp_enable = TRUE; + */ + + /* x and width must be even number */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + + inputRGB = FALSE; + sh_slice = 2; + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + inpBpp = 1; + src1 = (uint8 *) iBuf->mdpImg.cbcr_addr; + + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | + PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V1) + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + + ppp_operation_reg |= PPP_OP_SRC_CHROMA_H2V1 | + PPP_OP_SRC_CHROMA_COSITE | PPP_OP_DST_CHROMA_COSITE; + inputRGB = FALSE; + sh_slice = 2; + break; + + case MDP_BGR_565: + case MDP_RGB_565: + default: + inpBpp = 2; + /* + * 565 = 2bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_5BITS | PPP_SRC_C0G_6BITS | + PPP_SRC_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->mdpImg.imgType == MDP_RGB_565) + packPattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + else + packPattern = + MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB | + PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB; + break; + + } + + if (pseudoplanr_output) + ppp_dst_cfg_reg |= PPP_DST_PLANE_PSEUDOPLN; + + /* YCbCr to RGB color conversion flag */ + if ((!inputRGB) && (outputRGB)) { + ppp_operation_reg |= PPP_OP_CONVERT_YCBCR2RGB | + PPP_OP_CONVERT_ON; + + /* + * primary/secondary is sort of misleading term...but + * in mdp2.2/3.0 we only use primary matrix (forward/rev) + * in mdp3.1 we use set1(prim) and set2(secd) + */ +#ifdef CONFIG_FB_MSM_MDP31 + ppp_operation_reg |= PPP_OP_CONVERT_MATRIX_SECONDARY | + PPP_OP_DST_RGB; + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0240, 0); +#endif + + if (ppp_lookUp_enable) { + ppp_operation_reg |= PPP_OP_LUT_C0_ON | + PPP_OP_LUT_C1_ON | PPP_OP_LUT_C2_ON; + } + } + /* RGB to YCbCr color conversion flag */ + if ((inputRGB) && (!outputRGB)) { + ppp_operation_reg |= PPP_OP_CONVERT_RGB2YCBCR | + PPP_OP_CONVERT_ON; + +#ifdef CONFIG_FB_MSM_MDP31 + ppp_operation_reg |= PPP_OP_CONVERT_MATRIX_PRIMARY | + PPP_OP_DST_YCBCR; + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0240, 0x1e); +#endif + + if (ppp_lookUp_enable) { + ppp_operation_reg |= PPP_OP_LUT_C0_ON | + PPP_OP_LUT_C1_ON | PPP_OP_LUT_C2_ON; + } + } + /* YCbCr to YCbCr color conversion flag */ + if ((!inputRGB) && (!outputRGB)) { + if ((ppp_lookUp_enable) && + (iBuf->mdpImg.imgType != iBuf->ibuf_type)) { + ppp_operation_reg |= PPP_OP_LUT_C0_ON; + } + } + + ppp_src_cfg_reg |= (iBuf->roi.x % 2) ? PPP_SRC_BPP_ROI_ODD_X : 0; + ppp_src_cfg_reg |= (iBuf->roi.y % 2) ? PPP_SRC_BPP_ROI_ODD_Y : 0; + + if (req->flags & MDP_DEINTERLACE) + ppp_operation_reg |= PPP_OP_DEINT_EN; + + /* Dither at DMA side only since iBuf format is RGB888 */ + if (iBuf->mdpImg.mdpOp & MDPOP_DITHER) + ppp_operation_reg |= PPP_OP_DITHER_EN; + + if (iBuf->mdpImg.mdpOp & MDPOP_ROTATION) { + ppp_operation_reg |= PPP_OP_ROT_ON; + + if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) { + ppp_operation_reg |= PPP_OP_ROT_90; + } + if (iBuf->mdpImg.mdpOp & MDPOP_LR) { + ppp_operation_reg |= PPP_OP_FLIP_LR; + } + if (iBuf->mdpImg.mdpOp & MDPOP_UD) { + ppp_operation_reg |= PPP_OP_FLIP_UD; + } + } + + src0_ystride = src_width * inpBpp; + dest0_ystride = iBuf->ibuf_width * iBuf->bpp; + + /* no need to care about rotation since it's the real-XY. */ + dst_roi_width = iBuf->roi.dst_width; + dst_roi_height = iBuf->roi.dst_height; + + src0 = (uint8 *) iBuf->mdpImg.bmy_addr; + dest0 = (uint8 *) iBuf->buf; + + /* Jumping from Y-Plane to Chroma Plane */ + dest1 = mdp_get_chroma_addr(iBuf); + + /* first pixel addr calculation */ + mdp_adjust_start_addr(&src0, &src1, sv_slice, sh_slice, iBuf->roi.x, + iBuf->roi.y, src_width, src_height, inpBpp, iBuf, + 0); + mdp_adjust_start_addr(&dest0, &dest1, dv_slice, dh_slice, + iBuf->roi.lcd_x, iBuf->roi.lcd_y, + iBuf->ibuf_width, iBuf->ibuf_height, iBuf->bpp, + iBuf, 2); + + /* set scale operation */ + mdp_set_scale(iBuf, dst_roi_width, dst_roi_height, + inputRGB, outputRGB, &ppp_operation_reg); + + /* + * setting background source for blending + */ + mdp_set_blend_attr(iBuf, &alpha, &tpVal, perPixelAlpha, + &ppp_operation_reg); + + if (ppp_operation_reg & PPP_OP_BLEND_ON) { + mdp_ppp_setbg(iBuf); + + if (iBuf->ibuf_type == MDP_YCRYCB_H2V1) { + ppp_operation_reg |= PPP_OP_BG_CHROMA_H2V1; + + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) { + tpVal = mdp_conv_matx_rgb2yuv(tpVal, + (uint16 *) & + mdp_ccs_rgb2yuv, + &mdp_plv[0], NULL); + } + } + } + + /* + * 0x0004: enable dbg bus + * 0x0100: "don't care" Edge Condit until scaling is on + * 0x0104: xrc tile x&y size u7.6 format = 7bit.6bit + * 0x0108: src pixel size + * 0x010c: component plane 0 starting address + * 0x011c: component plane 0 ystride + * 0x0124: PPP source config register + * 0x0128: unpacked pattern from lsb to msb (eg. RGB->BGR) + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0108, (iBuf->roi.height << 16 | + iBuf->roi.width)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x010c, src0); /* comp.plane 0 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0110, src1); /* comp.plane 1 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x011c, + (src0_ystride << 16 | src0_ystride)); + + /* setup for rgb 565 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0124, ppp_src_cfg_reg); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0128, packPattern); + /* + * 0x0138: PPP destination operation register + * 0x014c: constant_alpha|transparent_color + * 0x0150: PPP destination config register + * 0x0154: PPP packing pattern + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0138, ppp_operation_reg); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x014c, alpha << 24 | tpVal); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0150, ppp_dst_cfg_reg); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0154, dst_packPattern); + + /* + * 0x0164: ROI height and width + * 0x0168: Component Plane 0 starting addr + * 0x016c: Component Plane 1 starting addr + * 0x0178: Component Plane 1/0 y stride + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0164, + (dst_roi_height << 16 | dst_roi_width)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0168, dest0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x016c, dest1); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0178, + (dest0_ystride << 16 | dest0_ystride)); + + flush_imgs(req, inpBpp, iBuf->bpp, p_src_file, p_dst_file); +#ifdef CONFIG_MDP_PPP_ASYNC_OP + mdp_ppp_process_curr_djob(); +#else + mdp_pipe_kickoff(MDP_PPP_TERM, mfd); +#endif +} + +static int mdp_ppp_verify_req(struct mdp_blit_req *req) +{ + u32 src_width, src_height, dst_width, dst_height; + + if (req == NULL) + return -1; + + if (MDP_IS_IMGTYPE_BAD(req->src.format) || + MDP_IS_IMGTYPE_BAD(req->dst.format)) + return -1; + + if ((req->src.width == 0) || (req->src.height == 0) || + (req->src_rect.w == 0) || (req->src_rect.h == 0) || + (req->dst.width == 0) || (req->dst.height == 0) || + (req->dst_rect.w == 0) || (req->dst_rect.h == 0)) + + return -1; + + if (((req->src_rect.x + req->src_rect.w) > req->src.width) || + ((req->src_rect.y + req->src_rect.h) > req->src.height)) + return -1; + + if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) || + ((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) + return -1; + + /* + * scaling range check + */ + src_width = req->src_rect.w; + src_height = req->src_rect.h; + + if (req->flags & MDP_ROT_90) { + dst_width = req->dst_rect.h; + dst_height = req->dst_rect.w; + } else { + dst_width = req->dst_rect.w; + dst_height = req->dst_rect.h; + } + + switch (req->dst.format) { + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + src_width = (src_width / 2) * 2; + src_height = (src_height / 2) * 2; + dst_width = (src_width / 2) * 2; + dst_height = (src_height / 2) * 2; + break; + + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_YCRYCB_H2V1: + src_width = (src_width / 2) * 2; + dst_width = (src_width / 2) * 2; + break; + + default: + break; + } + + if (((MDP_SCALE_Q_FACTOR * dst_width) / src_width > + MDP_MAX_X_SCALE_FACTOR) + || ((MDP_SCALE_Q_FACTOR * dst_width) / src_width < + MDP_MIN_X_SCALE_FACTOR)) + return -1; + + if (((MDP_SCALE_Q_FACTOR * dst_height) / src_height > + MDP_MAX_Y_SCALE_FACTOR) + || ((MDP_SCALE_Q_FACTOR * dst_height) / src_height < + MDP_MIN_Y_SCALE_FACTOR)) + return -1; + + return 0; +} + +/** + * get_gem_img() - retrieve drm obj's start address and size + * @img: contains drm file descriptor and gem handle + * @start: repository of starting address of drm obj allocated memory + * @len: repository of size of drm obj alloacted memory + * + **/ +int get_gem_img(struct mdp_img *img, unsigned long *start, unsigned long *len) +{ + panic("waaaaaaaah"); + //return kgsl_gem_obj_addr(img->memory_id, (int)img->priv, start, len); +} + +int get_img(struct mdp_img *img, struct fb_info *info, unsigned long *start, + unsigned long *len, struct file **pp_file) +{ + int put_needed, ret = 0; + struct file *file; + unsigned long vstart; +#ifdef CONFIG_ANDROID_PMEM + if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file)) + return 0; +#endif + file = fget_light(img->memory_id, &put_needed); + if (file == NULL) + return -1; + + if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { + *start = info->fix.smem_start; + *len = info->fix.smem_len; + *pp_file = file; + } else { + ret = -1; + fput_light(file, put_needed); + } + return ret; +} + +int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req, + struct file **pp_src_file, struct file **pp_dst_file) +{ + unsigned long src_start, dst_start; + unsigned long src_len = 0; + unsigned long dst_len = 0; + MDPIBUF iBuf; + u32 dst_width, dst_height; + struct file *p_src_file = 0 , *p_dst_file = 0; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (req->dst.format == MDP_FB_FORMAT) + req->dst.format = mfd->fb_imgType; + if (req->src.format == MDP_FB_FORMAT) + req->src.format = mfd->fb_imgType; + + if (req->flags & MDP_BLIT_SRC_GEM) { + if (get_gem_img(&req->src, &src_start, &src_len) < 0) + return -1; + } else { + get_img(&req->src, info, &src_start, &src_len, &p_src_file); + } + if (src_len == 0) { + printk(KERN_ERR "mdp_ppp: could not retrieve image from " + "memory\n"); + return -1; + } + + if (req->flags & MDP_BLIT_DST_GEM) { + if (get_gem_img(&req->dst, &dst_start, &dst_len) < 0) + return -1; + } else { + get_img(&req->dst, info, &dst_start, &dst_len, &p_dst_file); + } + if (dst_len == 0) { + printk(KERN_ERR "mdp_ppp: could not retrieve image from " + "memory\n"); + return -1; + } + *pp_src_file = p_src_file; + *pp_dst_file = p_dst_file; + if (mdp_ppp_verify_req(req)) { + printk(KERN_ERR "mdp_ppp: invalid image!\n"); + return -1; + } + + iBuf.ibuf_width = req->dst.width; + iBuf.ibuf_height = req->dst.height; + iBuf.bpp = bytes_per_pixel[req->dst.format]; + + iBuf.ibuf_type = req->dst.format; + iBuf.buf = (uint8 *) dst_start; + iBuf.buf += req->dst.offset; + + iBuf.roi.lcd_x = req->dst_rect.x; + iBuf.roi.lcd_y = req->dst_rect.y; + iBuf.roi.dst_width = req->dst_rect.w; + iBuf.roi.dst_height = req->dst_rect.h; + + iBuf.roi.x = req->src_rect.x; + iBuf.roi.width = req->src_rect.w; + iBuf.roi.y = req->src_rect.y; + iBuf.roi.height = req->src_rect.h; + + iBuf.mdpImg.width = req->src.width; + iBuf.mdpImg.imgType = req->src.format; + + iBuf.mdpImg.bmy_addr = (uint32 *) (src_start + req->src.offset); + iBuf.mdpImg.cbcr_addr = + (uint32 *) ((uint32) iBuf.mdpImg.bmy_addr + + req->src.width * req->src.height); + + iBuf.mdpImg.mdpOp = MDPOP_NOP; + + /* blending check */ + if (req->transp_mask != MDP_TRANSP_NOP) { + iBuf.mdpImg.mdpOp |= MDPOP_TRANSP; + iBuf.mdpImg.tpVal = req->transp_mask; + iBuf.mdpImg.tpVal = mdp_calc_tpval(&iBuf.mdpImg); + } + + req->alpha &= 0xff; + if (req->alpha < MDP_ALPHA_NOP) { + iBuf.mdpImg.mdpOp |= MDPOP_ALPHAB; + iBuf.mdpImg.alpha = req->alpha; + } + + /* rotation check */ + if (req->flags & MDP_FLIP_LR) + iBuf.mdpImg.mdpOp |= MDPOP_LR; + if (req->flags & MDP_FLIP_UD) + iBuf.mdpImg.mdpOp |= MDPOP_UD; + if (req->flags & MDP_ROT_90) + iBuf.mdpImg.mdpOp |= MDPOP_ROT90; + if (req->flags & MDP_DITHER) + iBuf.mdpImg.mdpOp |= MDPOP_DITHER; + + if (req->flags & MDP_BLEND_FG_PREMULT) { +#ifdef CONFIG_FB_MSM_MDP31 + iBuf.mdpImg.mdpOp |= MDPOP_FG_PM_ALPHA; +#else + return -EINVAL; +#endif + } + + if (req->flags & MDP_DEINTERLACE) { +#ifdef CONFIG_FB_MSM_MDP31 + if ((req->src.format != MDP_Y_CBCR_H2V2) && + (req->src.format != MDP_Y_CRCB_H2V2)) +#endif + return -EINVAL; + } + + /* scale check */ + if (req->flags & MDP_ROT_90) { + dst_width = req->dst_rect.h; + dst_height = req->dst_rect.w; + } else { + dst_width = req->dst_rect.w; + dst_height = req->dst_rect.h; + } + + if ((iBuf.roi.width != dst_width) || (iBuf.roi.height != dst_height)) + iBuf.mdpImg.mdpOp |= MDPOP_ASCALE; + + if (req->flags & MDP_BLUR) { +#ifdef CONFIG_FB_MSM_MDP31 + if (req->flags & MDP_SHARPENING) + printk(KERN_WARNING + "mdp: MDP_SHARPENING is set with MDP_BLUR!\n"); + req->flags |= MDP_SHARPENING; + req->sharpening_strength = -127; +#else + iBuf.mdpImg.mdpOp |= MDPOP_ASCALE | MDPOP_BLUR; + +#endif + } + + if (req->flags & MDP_SHARPENING) { +#ifdef CONFIG_FB_MSM_MDP31 + if ((req->sharpening_strength > 127) || + (req->sharpening_strength < -127)) { + printk(KERN_ERR + "%s: sharpening strength out of range\n", + __func__); + return -EINVAL; + } + + iBuf.mdpImg.mdpOp |= MDPOP_ASCALE | MDPOP_SHARPENING; + iBuf.mdpImg.sp_value = req->sharpening_strength & 0xff; +#else + return -EINVAL; +#endif + } + + down(&mdp_ppp_mutex); + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + +#ifdef CONFIG_FB_MSM_MDP31 + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); +#else + /* bg tile fetching HW workaround */ + if (((iBuf.mdpImg.mdpOp & (MDPOP_TRANSP | MDPOP_ALPHAB)) || + (req->src.format == MDP_ARGB_8888) || + (req->src.format == MDP_BGRA_8888) || + (req->src.format == MDP_RGBA_8888)) && + (iBuf.mdpImg.mdpOp & MDPOP_ROT90) && (req->dst_rect.w <= 16)) { + int dst_h, src_w, i; + + src_w = req->src_rect.w; + dst_h = iBuf.roi.dst_height; + + for (i = 0; i < (req->dst_rect.h / 16); i++) { + /* this tile size */ + iBuf.roi.dst_height = 16; + iBuf.roi.width = + (16 * req->src_rect.w) / req->dst_rect.h; + + /* if it's out of scale range... */ + if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) > MDP_MAX_X_SCALE_FACTOR) + iBuf.roi.width = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MAX_X_SCALE_FACTOR; + else if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) < MDP_MIN_X_SCALE_FACTOR) + iBuf.roi.width = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MIN_X_SCALE_FACTOR; + + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); + + /* next tile location */ + iBuf.roi.lcd_y += 16; + iBuf.roi.x += iBuf.roi.width; + + /* this is for a remainder update */ + dst_h -= 16; + src_w -= iBuf.roi.width; + } + + if ((dst_h < 0) || (src_w < 0)) + printk + ("msm_fb: mdp_blt_ex() unexpected result! line:%d\n", + __LINE__); + + /* remainder update */ + if ((dst_h > 0) && (src_w > 0)) { + u32 tmp_v; + + iBuf.roi.dst_height = dst_h; + iBuf.roi.width = src_w; + + if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) > MDP_MAX_X_SCALE_FACTOR) { + tmp_v = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MAX_X_SCALE_FACTOR + + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) % + MDP_MAX_X_SCALE_FACTOR ? 1 : 0; + + /* move x location as roi width gets bigger */ + iBuf.roi.x -= tmp_v - iBuf.roi.width; + iBuf.roi.width = tmp_v; + } else + if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) < MDP_MIN_X_SCALE_FACTOR) { + tmp_v = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MIN_X_SCALE_FACTOR + + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) % + MDP_MIN_X_SCALE_FACTOR ? 1 : 0; + + /* + * we don't move x location for continuity of + * source image + */ + iBuf.roi.width = tmp_v; + } + + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); + } + } else { + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); + } +#endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + up(&mdp_ppp_mutex); + + return 0; +} diff --git a/drivers/staging/msm/mdp_ppp_dq.c b/drivers/staging/msm/mdp_ppp_dq.c new file mode 100644 index 000000000000..3dc1c0cc61f9 --- /dev/null +++ b/drivers/staging/msm/mdp_ppp_dq.c @@ -0,0 +1,347 @@ +/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "mdp.h" + +static boolean mdp_ppp_intr_flag = FALSE; +static boolean mdp_ppp_busy_flag = FALSE; + +/* Queue to keep track of the completed jobs for cleaning */ +static LIST_HEAD(mdp_ppp_djob_clnrq); +static DEFINE_SPINLOCK(mdp_ppp_djob_clnrq_lock); + +/* Worker to cleanup Display Jobs */ +static struct workqueue_struct *mdp_ppp_djob_clnr; + +/* Display Queue (DQ) for MDP PPP Block */ +static LIST_HEAD(mdp_ppp_dq); +static DEFINE_SPINLOCK(mdp_ppp_dq_lock); + +/* Current Display Job for MDP PPP */ +static struct mdp_ppp_djob *curr_djob; + +/* Track ret code for the last opeartion */ +static int mdp_ppp_ret_code; + +inline int mdp_ppp_get_ret_code(void) +{ + return mdp_ppp_ret_code; +} + +/* Push <Reg, Val> pair into DQ (if available) to later + * program the MDP PPP Block */ +inline void mdp_ppp_outdw(uint32_t addr, uint32_t data) +{ + if (curr_djob) { + + /* get the last node of the list. */ + struct mdp_ppp_roi_cmd_set *node = + list_entry(curr_djob->roi_cmd_list.prev, + struct mdp_ppp_roi_cmd_set, node); + + /* If a node is already full, create a new one and add it to + * the list (roi_cmd_list). + */ + if (node->ncmds == MDP_PPP_ROI_NODE_SIZE) { + node = kmalloc(sizeof(struct mdp_ppp_roi_cmd_set), + GFP_KERNEL); + if (!node) { + printk(KERN_ERR + "MDP_PPP: not enough memory.\n"); + mdp_ppp_ret_code = -EINVAL; + return; + } + + /* no ROI commands initially */ + node->ncmds = 0; + + /* add one node to roi_cmd_list. */ + list_add_tail(&node->node, &curr_djob->roi_cmd_list); + } + + /* register ROI commands */ + node->cmd[node->ncmds].reg = addr; + node->cmd[node->ncmds].val = data; + node->ncmds++; + } else + /* program MDP PPP block now */ + outpdw((addr), (data)); +} + +/* Initialize DQ */ +inline void mdp_ppp_dq_init(void) +{ + mdp_ppp_djob_clnr = create_singlethread_workqueue("MDPDJobClnrThrd"); +} + +/* Release resources of a job (DJob). */ +static void mdp_ppp_del_djob(struct mdp_ppp_djob *job) +{ + struct mdp_ppp_roi_cmd_set *node, *tmp; + + /* release mem */ + mdp_ppp_put_img(job->p_src_file, job->p_dst_file); + + /* release roi_cmd_list */ + list_for_each_entry_safe(node, tmp, &job->roi_cmd_list, node) { + list_del(&node->node); + kfree(node); + } + + /* release job struct */ + kfree(job); +} + +/* Worker thread to reclaim resources once a display job is done */ +static void mdp_ppp_djob_cleaner(struct work_struct *work) +{ + struct mdp_ppp_djob *job; + + MDP_PPP_DEBUG_MSG("mdp ppp display job cleaner started \n"); + + /* cleanup display job */ + job = container_of(work, struct mdp_ppp_djob, cleaner.work); + if (likely(work && job)) + mdp_ppp_del_djob(job); +} + +/* Create a new Display Job (DJob) */ +inline struct mdp_ppp_djob *mdp_ppp_new_djob(void) +{ + struct mdp_ppp_djob *job; + struct mdp_ppp_roi_cmd_set *node; + + /* create a new djob */ + job = kmalloc(sizeof(struct mdp_ppp_djob), GFP_KERNEL); + if (!job) + return NULL; + + /* add the first node to curr_djob->roi_cmd_list */ + node = kmalloc(sizeof(struct mdp_ppp_roi_cmd_set), GFP_KERNEL); + if (!node) { + kfree(job); + return NULL; + } + + /* make this current djob container to keep track of the curr djob not + * used in the async path i.e. no sync needed + * + * Should not contain any references from the past djob + */ + BUG_ON(curr_djob); + curr_djob = job; + INIT_LIST_HEAD(&curr_djob->roi_cmd_list); + + /* no ROI commands initially */ + node->ncmds = 0; + INIT_LIST_HEAD(&node->node); + list_add_tail(&node->node, &curr_djob->roi_cmd_list); + + /* register this djob with the djob cleaner + * initializes 'work' data struct + */ + INIT_DELAYED_WORK(&curr_djob->cleaner, mdp_ppp_djob_cleaner); + INIT_LIST_HEAD(&curr_djob->entry); + + curr_djob->p_src_file = 0; + curr_djob->p_dst_file = 0; + + return job; +} + +/* Undo the effect of mdp_ppp_new_djob() */ +inline void mdp_ppp_clear_curr_djob(void) +{ + if (likely(curr_djob)) { + mdp_ppp_del_djob(curr_djob); + curr_djob = NULL; + } +} + +/* Cleanup dirty djobs */ +static void mdp_ppp_flush_dirty_djobs(void *cond) +{ + unsigned long flags; + struct mdp_ppp_djob *job; + + /* Flush the jobs from the djob clnr queue */ + while (cond && test_bit(0, (unsigned long *)cond)) { + + /* Until we are done with the cleanup queue */ + spin_lock_irqsave(&mdp_ppp_djob_clnrq_lock, flags); + if (list_empty(&mdp_ppp_djob_clnrq)) { + spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags); + break; + } + + MDP_PPP_DEBUG_MSG("flushing djobs ... loop \n"); + + /* Retrieve the job that needs to be cleaned */ + job = list_entry(mdp_ppp_djob_clnrq.next, + struct mdp_ppp_djob, entry); + list_del_init(&job->entry); + spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags); + + /* Keep mem state coherent */ + msm_fb_ensure_mem_coherency_after_dma(job->info, &job->req, 1); + + /* Schedule jobs for cleanup + * A seperate worker thread does this */ + queue_delayed_work(mdp_ppp_djob_clnr, &job->cleaner, + mdp_timer_duration); + } +} + +/* If MDP PPP engine is busy, wait until it is available again */ +void mdp_ppp_wait(void) +{ + unsigned long flags; + int cond = 1; + + /* keep flushing dirty djobs as long as MDP PPP engine is busy */ + mdp_ppp_flush_dirty_djobs(&mdp_ppp_busy_flag); + + /* block if MDP PPP engine is still busy */ + spin_lock_irqsave(&mdp_ppp_dq_lock, flags); + if (test_bit(0, (unsigned long *)&mdp_ppp_busy_flag)) { + + /* prepare for the wakeup event */ + test_and_set_bit(0, (unsigned long *)&mdp_ppp_waiting); + INIT_COMPLETION(mdp_ppp_comp); + spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags); + + /* block uninterruptibly until available */ + MDP_PPP_DEBUG_MSG("waiting for mdp... \n"); + wait_for_completion_killable(&mdp_ppp_comp); + + /* if MDP PPP engine is still free, + * disable INT_MDP if enabled + */ + spin_lock_irqsave(&mdp_ppp_dq_lock, flags); + if (!test_bit(0, (unsigned long *)&mdp_ppp_busy_flag) && + test_and_clear_bit(0, (unsigned long *)&mdp_ppp_intr_flag)) + mdp_disable_irq(MDP_PPP_TERM); + } + spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags); + + /* flush remaining dirty djobs, if any */ + mdp_ppp_flush_dirty_djobs(&cond); +} + +/* Program MDP PPP block to process this ROI */ +static void mdp_ppp_process_roi(struct list_head *roi_cmd_list) +{ + + /* program PPP engine with registered ROI commands */ + struct mdp_ppp_roi_cmd_set *node; + list_for_each_entry(node, roi_cmd_list, node) { + int i = 0; + for (; i < node->ncmds; i++) { + MDP_PPP_DEBUG_MSG("%d: reg: 0x%x val: 0x%x \n", + i, node->cmd[i].reg, node->cmd[i].val); + outpdw(node->cmd[i].reg, node->cmd[i].val); + } + } + + /* kickoff MDP PPP engine */ + MDP_PPP_DEBUG_MSG("kicking off mdp \n"); + outpdw(MDP_BASE + 0x30, 0x1000); +} + +/* Submit this display job to MDP PPP engine */ +static void mdp_ppp_dispatch_djob(struct mdp_ppp_djob *job) +{ + /* enable INT_MDP if disabled */ + if (!test_and_set_bit(0, (unsigned long *)&mdp_ppp_intr_flag)) + mdp_enable_irq(MDP_PPP_TERM); + + /* turn on PPP and CMD blocks */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* process this ROI */ + mdp_ppp_process_roi(&job->roi_cmd_list); +} + +/* Enqueue this display job to be cleaned up later in "mdp_ppp_djob_done" */ +static inline void mdp_ppp_enqueue_djob(struct mdp_ppp_djob *job) +{ + unsigned long flags; + + spin_lock_irqsave(&mdp_ppp_dq_lock, flags); + list_add_tail(&job->entry, &mdp_ppp_dq); + spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags); +} + +/* First enqueue display job for cleanup and dispatch immediately + * if MDP PPP engine is free */ +void mdp_ppp_process_curr_djob(void) +{ + /* enqueue djob */ + mdp_ppp_enqueue_djob(curr_djob); + + /* dispatch now if MDP PPP engine is free */ + if (!test_and_set_bit(0, (unsigned long *)&mdp_ppp_busy_flag)) + mdp_ppp_dispatch_djob(curr_djob); + + /* done with the current djob */ + curr_djob = NULL; +} + +/* Called from mdp_isr - cleanup finished job and start with next + * if available else set MDP PPP engine free */ +void mdp_ppp_djob_done(void) +{ + struct mdp_ppp_djob *curr, *next; + unsigned long flags; + + /* dequeue current */ + spin_lock_irqsave(&mdp_ppp_dq_lock, flags); + curr = list_entry(mdp_ppp_dq.next, struct mdp_ppp_djob, entry); + list_del_init(&curr->entry); + spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags); + + /* cleanup current - enqueue in the djob clnr queue */ + spin_lock_irqsave(&mdp_ppp_djob_clnrq_lock, flags); + list_add_tail(&curr->entry, &mdp_ppp_djob_clnrq); + spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags); + + /* grab next pending */ + spin_lock_irqsave(&mdp_ppp_dq_lock, flags); + if (!list_empty(&mdp_ppp_dq)) { + next = list_entry(mdp_ppp_dq.next, struct mdp_ppp_djob, + entry); + spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags); + + /* process next in the queue */ + mdp_ppp_process_roi(&next->roi_cmd_list); + } else { + /* no pending display job */ + spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags); + + /* turn off PPP and CMD blocks - "in_isr" is TRUE */ + mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + + /* notify if waiting */ + if (test_and_clear_bit(0, (unsigned long *)&mdp_ppp_waiting)) + complete(&mdp_ppp_comp); + + /* set free */ + test_and_clear_bit(0, (unsigned long *)&mdp_ppp_busy_flag); + } +} diff --git a/drivers/staging/msm/mdp_ppp_dq.h b/drivers/staging/msm/mdp_ppp_dq.h new file mode 100644 index 000000000000..03e4e9a5f234 --- /dev/null +++ b/drivers/staging/msm/mdp_ppp_dq.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora Forum, Inc. 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 "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * + */ + +#ifndef MDP_PPP_DQ_H +#define MDP_PPP_DQ_H + +#include "msm_fb_def.h" + +#define MDP_PPP_DEBUG_MSG MSM_FB_DEBUG + +/* The maximum number of <Reg,Val> pairs in an mdp_ppp_roi_cmd_set structure (a + * node) + */ +#define MDP_PPP_ROI_NODE_SIZE 32 + +/* ROI config command (<Reg,Val> pair) for MDP PPP block */ +struct mdp_ppp_roi_cmd { + uint32_t reg; + uint32_t val; +}; + +/* ROI config commands for MDP PPP block are stored in a list of + * mdp_ppp_roi_cmd_set structures (nodes). + */ +struct mdp_ppp_roi_cmd_set { + struct list_head node; + uint32_t ncmds; /* number of commands in this set (node). */ + struct mdp_ppp_roi_cmd cmd[MDP_PPP_ROI_NODE_SIZE]; +}; + +/* MDP PPP Display Job (DJob) */ +struct mdp_ppp_djob { + struct list_head entry; + /* One ROI per MDP PPP DJob */ + struct list_head roi_cmd_list; + struct mdp_blit_req req; + struct fb_info *info; + struct delayed_work cleaner; + struct file *p_src_file, *p_dst_file; +}; + +extern struct completion mdp_ppp_comp; +extern boolean mdp_ppp_waiting; +extern unsigned long mdp_timer_duration; + +unsigned int mdp_ppp_async_op_get(void); +void mdp_ppp_async_op_set(unsigned int flag); +void msm_fb_ensure_mem_coherency_after_dma(struct fb_info *info, + struct mdp_blit_req *req_list, int req_list_count); +void mdp_ppp_put_img(struct file *p_src_file, struct file *p_dst_file); +void mdp_ppp_dq_init(void); +void mdp_ppp_outdw(uint32_t addr, uint32_t data); +struct mdp_ppp_djob *mdp_ppp_new_djob(void); +void mdp_ppp_clear_curr_djob(void); +void mdp_ppp_process_curr_djob(void); +int mdp_ppp_get_ret_code(void); +void mdp_ppp_djob_done(void); +void mdp_ppp_wait(void); + +#endif /* MDP_PPP_DQ_H */ diff --git a/drivers/staging/msm/mdp_ppp_v20.c b/drivers/staging/msm/mdp_ppp_v20.c new file mode 100644 index 000000000000..b5b7271921e0 --- /dev/null +++ b/drivers/staging/msm/mdp_ppp_v20.c @@ -0,0 +1,2486 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include "linux/proc_fs.h" + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <asm/div64.h> + +#include "mdp.h" +#include "msm_fb.h" + +static MDP_SCALE_MODE mdp_curr_up_scale_xy; +static MDP_SCALE_MODE mdp_curr_down_scale_x; +static MDP_SCALE_MODE mdp_curr_down_scale_y; + +static long long mdp_do_div(long long num, long long den) +{ + do_div(num, den); + return num; +} + +struct mdp_table_entry mdp_gaussian_blur_table[] = { + /* max variance */ + { 0x5fffc, 0x20000080 }, + { 0x50280, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50284, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50288, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5028c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50290, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50294, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50298, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5029c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502ac, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502bc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502cc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502dc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502ec, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502fc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50300, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50304, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50308, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5030c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50310, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50314, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50318, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5031c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50320, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50324, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50328, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5032c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50330, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50334, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50338, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5033c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50340, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50344, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50348, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5034c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50350, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50354, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50358, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5035c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50360, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50364, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50368, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5036c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50370, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50374, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50378, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5037c, 0x20000080 }, +}; + +static void load_scale_table( + struct mdp_table_entry *table, int len) +{ + int i; + for (i = 0; i < len; i++) + MDP_OUTP(MDP_BASE + table[i].reg, table[i].val); +} + +static void mdp_load_pr_upscale_table(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50200, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50204, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50208, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5020c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50210, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50214, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50218, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5021c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50220, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50224, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50228, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5022c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50230, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50234, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50238, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5023c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50240, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50244, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50248, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5024c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50250, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50254, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50258, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5025c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50260, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50264, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50268, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5026c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50270, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50274, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50278, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5027c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_bc_upscale_table(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50200, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d); + MDP_OUTP(MDP_BASE + 0x50204, 0x7ec003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c); + MDP_OUTP(MDP_BASE + 0x50208, 0x7d4003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b); + MDP_OUTP(MDP_BASE + 0x5020c, 0x7b8003ed); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c); + MDP_OUTP(MDP_BASE + 0x50210, 0x794003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d); + MDP_OUTP(MDP_BASE + 0x50214, 0x76c003e4); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f); + MDP_OUTP(MDP_BASE + 0x50218, 0x73c003e0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071); + MDP_OUTP(MDP_BASE + 0x5021c, 0x708003de); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085); + MDP_OUTP(MDP_BASE + 0x50220, 0x6d0003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098); + MDP_OUTP(MDP_BASE + 0x50224, 0x698003d9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac); + MDP_OUTP(MDP_BASE + 0x50228, 0x654003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1); + MDP_OUTP(MDP_BASE + 0x5022c, 0x610003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5); + MDP_OUTP(MDP_BASE + 0x50230, 0x5c8003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9); + MDP_OUTP(MDP_BASE + 0x50234, 0x580003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd); + MDP_OUTP(MDP_BASE + 0x50238, 0x534003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112); + MDP_OUTP(MDP_BASE + 0x5023c, 0x4e8003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126); + MDP_OUTP(MDP_BASE + 0x50240, 0x494003da); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a); + MDP_OUTP(MDP_BASE + 0x50244, 0x448003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d); + MDP_OUTP(MDP_BASE + 0x50248, 0x3f4003dd); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160); + MDP_OUTP(MDP_BASE + 0x5024c, 0x3a4003df); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172); + MDP_OUTP(MDP_BASE + 0x50250, 0x354003e1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184); + MDP_OUTP(MDP_BASE + 0x50254, 0x304003e3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195); + MDP_OUTP(MDP_BASE + 0x50258, 0x2b0003e6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6); + MDP_OUTP(MDP_BASE + 0x5025c, 0x260003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4); + MDP_OUTP(MDP_BASE + 0x50260, 0x214003eb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2); + MDP_OUTP(MDP_BASE + 0x50264, 0x1c4003ee); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf); + MDP_OUTP(MDP_BASE + 0x50268, 0x17c003f1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db); + MDP_OUTP(MDP_BASE + 0x5026c, 0x134003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5); + MDP_OUTP(MDP_BASE + 0x50270, 0xf0003f6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee); + MDP_OUTP(MDP_BASE + 0x50274, 0xac003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5); + MDP_OUTP(MDP_BASE + 0x50278, 0x70003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb); + MDP_OUTP(MDP_BASE + 0x5027c, 0x34003fe); +} + +static void mdp_load_bc_downscale_table_x_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac00084); + MDP_OUTP(MDP_BASE + 0x50280, 0x23400083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b000084); + MDP_OUTP(MDP_BASE + 0x50284, 0x23000083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400084); + MDP_OUTP(MDP_BASE + 0x50288, 0x23000082); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400085); + MDP_OUTP(MDP_BASE + 0x5028c, 0x23000081); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b800085); + MDP_OUTP(MDP_BASE + 0x50290, 0x23000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc00086); + MDP_OUTP(MDP_BASE + 0x50294, 0x22c0007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c000086); + MDP_OUTP(MDP_BASE + 0x50298, 0x2280007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c400086); + MDP_OUTP(MDP_BASE + 0x5029c, 0x2280007e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c800086); + MDP_OUTP(MDP_BASE + 0x502a0, 0x2280007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00086); + MDP_OUTP(MDP_BASE + 0x502a4, 0x2240007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00087); + MDP_OUTP(MDP_BASE + 0x502a8, 0x2240007c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d000087); + MDP_OUTP(MDP_BASE + 0x502ac, 0x2240007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400087); + MDP_OUTP(MDP_BASE + 0x502b0, 0x2200007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400088); + MDP_OUTP(MDP_BASE + 0x502b4, 0x22400079); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d800088); + MDP_OUTP(MDP_BASE + 0x502b8, 0x22400078); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00088); + MDP_OUTP(MDP_BASE + 0x502bc, 0x22400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00089); + MDP_OUTP(MDP_BASE + 0x502c0, 0x22000077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e000089); + MDP_OUTP(MDP_BASE + 0x502c4, 0x22000076); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e400089); + MDP_OUTP(MDP_BASE + 0x502c8, 0x22000075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00088); + MDP_OUTP(MDP_BASE + 0x502cc, 0x21c00075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00089); + MDP_OUTP(MDP_BASE + 0x502d0, 0x21c00074); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f000089); + MDP_OUTP(MDP_BASE + 0x502d4, 0x21c00073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f400089); + MDP_OUTP(MDP_BASE + 0x502d8, 0x21800073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f40008a); + MDP_OUTP(MDP_BASE + 0x502dc, 0x21800072); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f80008a); + MDP_OUTP(MDP_BASE + 0x502e0, 0x21800071); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008a); + MDP_OUTP(MDP_BASE + 0x502e4, 0x21800070); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008b); + MDP_OUTP(MDP_BASE + 0x502e8, 0x2180006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2000008c); + MDP_OUTP(MDP_BASE + 0x502ec, 0x2140006e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2040008c); + MDP_OUTP(MDP_BASE + 0x502f0, 0x2140006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2080008c); + MDP_OUTP(MDP_BASE + 0x502f4, 0x2100006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008c); + MDP_OUTP(MDP_BASE + 0x502f8, 0x2100006c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008d); + MDP_OUTP(MDP_BASE + 0x502fc, 0x2100006b); +} + +static void mdp_load_bc_downscale_table_y_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac00084); + MDP_OUTP(MDP_BASE + 0x50300, 0x23400083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b000084); + MDP_OUTP(MDP_BASE + 0x50304, 0x23000083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400084); + MDP_OUTP(MDP_BASE + 0x50308, 0x23000082); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400085); + MDP_OUTP(MDP_BASE + 0x5030c, 0x23000081); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b800085); + MDP_OUTP(MDP_BASE + 0x50310, 0x23000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc00086); + MDP_OUTP(MDP_BASE + 0x50314, 0x22c0007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c000086); + MDP_OUTP(MDP_BASE + 0x50318, 0x2280007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c400086); + MDP_OUTP(MDP_BASE + 0x5031c, 0x2280007e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c800086); + MDP_OUTP(MDP_BASE + 0x50320, 0x2280007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00086); + MDP_OUTP(MDP_BASE + 0x50324, 0x2240007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00087); + MDP_OUTP(MDP_BASE + 0x50328, 0x2240007c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d000087); + MDP_OUTP(MDP_BASE + 0x5032c, 0x2240007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400087); + MDP_OUTP(MDP_BASE + 0x50330, 0x2200007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400088); + MDP_OUTP(MDP_BASE + 0x50334, 0x22400079); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d800088); + MDP_OUTP(MDP_BASE + 0x50338, 0x22400078); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00088); + MDP_OUTP(MDP_BASE + 0x5033c, 0x22400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00089); + MDP_OUTP(MDP_BASE + 0x50340, 0x22000077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e000089); + MDP_OUTP(MDP_BASE + 0x50344, 0x22000076); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e400089); + MDP_OUTP(MDP_BASE + 0x50348, 0x22000075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00088); + MDP_OUTP(MDP_BASE + 0x5034c, 0x21c00075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00089); + MDP_OUTP(MDP_BASE + 0x50350, 0x21c00074); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f000089); + MDP_OUTP(MDP_BASE + 0x50354, 0x21c00073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f400089); + MDP_OUTP(MDP_BASE + 0x50358, 0x21800073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f40008a); + MDP_OUTP(MDP_BASE + 0x5035c, 0x21800072); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f80008a); + MDP_OUTP(MDP_BASE + 0x50360, 0x21800071); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008a); + MDP_OUTP(MDP_BASE + 0x50364, 0x21800070); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008b); + MDP_OUTP(MDP_BASE + 0x50368, 0x2180006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2000008c); + MDP_OUTP(MDP_BASE + 0x5036c, 0x2140006e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2040008c); + MDP_OUTP(MDP_BASE + 0x50370, 0x2140006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2080008c); + MDP_OUTP(MDP_BASE + 0x50374, 0x2100006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008c); + MDP_OUTP(MDP_BASE + 0x50378, 0x2100006c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008d); + MDP_OUTP(MDP_BASE + 0x5037c, 0x2100006b); +} + +static void mdp_load_bc_downscale_table_x_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x740008c); + MDP_OUTP(MDP_BASE + 0x50280, 0x33800088); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x800008e); + MDP_OUTP(MDP_BASE + 0x50284, 0x33400084); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8400092); + MDP_OUTP(MDP_BASE + 0x50288, 0x33000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9000094); + MDP_OUTP(MDP_BASE + 0x5028c, 0x3300007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9c00098); + MDP_OUTP(MDP_BASE + 0x50290, 0x32400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xa40009b); + MDP_OUTP(MDP_BASE + 0x50294, 0x32000073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xb00009d); + MDP_OUTP(MDP_BASE + 0x50298, 0x31c0006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xbc000a0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x3140006b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc8000a2); + MDP_OUTP(MDP_BASE + 0x502a0, 0x31000067); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xd8000a5); + MDP_OUTP(MDP_BASE + 0x502a4, 0x30800062); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xe4000a8); + MDP_OUTP(MDP_BASE + 0x502a8, 0x2fc0005f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xec000aa); + MDP_OUTP(MDP_BASE + 0x502ac, 0x2fc0005b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8000ad); + MDP_OUTP(MDP_BASE + 0x502b0, 0x2f400057); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x108000b0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x2e400054); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x114000b2); + MDP_OUTP(MDP_BASE + 0x502b8, 0x2e000050); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x124000b4); + MDP_OUTP(MDP_BASE + 0x502bc, 0x2d80004c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x130000b6); + MDP_OUTP(MDP_BASE + 0x502c0, 0x2d000049); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x140000b8); + MDP_OUTP(MDP_BASE + 0x502c4, 0x2c800045); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x150000b9); + MDP_OUTP(MDP_BASE + 0x502c8, 0x2c000042); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x15c000bd); + MDP_OUTP(MDP_BASE + 0x502cc, 0x2b40003e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x16c000bf); + MDP_OUTP(MDP_BASE + 0x502d0, 0x2a80003b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x17c000bf); + MDP_OUTP(MDP_BASE + 0x502d4, 0x2a000039); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x188000c2); + MDP_OUTP(MDP_BASE + 0x502d8, 0x29400036); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x19c000c4); + MDP_OUTP(MDP_BASE + 0x502dc, 0x28800032); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac000c5); + MDP_OUTP(MDP_BASE + 0x502e0, 0x2800002f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc000c7); + MDP_OUTP(MDP_BASE + 0x502e4, 0x2740002c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc000c8); + MDP_OUTP(MDP_BASE + 0x502e8, 0x26c00029); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc000c9); + MDP_OUTP(MDP_BASE + 0x502ec, 0x26000027); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec000cc); + MDP_OUTP(MDP_BASE + 0x502f0, 0x25000024); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x200000cc); + MDP_OUTP(MDP_BASE + 0x502f4, 0x24800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x210000cd); + MDP_OUTP(MDP_BASE + 0x502f8, 0x23800020); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x220000ce); + MDP_OUTP(MDP_BASE + 0x502fc, 0x2300001d); +} + +static void mdp_load_bc_downscale_table_y_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x740008c); + MDP_OUTP(MDP_BASE + 0x50300, 0x33800088); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x800008e); + MDP_OUTP(MDP_BASE + 0x50304, 0x33400084); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8400092); + MDP_OUTP(MDP_BASE + 0x50308, 0x33000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9000094); + MDP_OUTP(MDP_BASE + 0x5030c, 0x3300007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9c00098); + MDP_OUTP(MDP_BASE + 0x50310, 0x32400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xa40009b); + MDP_OUTP(MDP_BASE + 0x50314, 0x32000073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xb00009d); + MDP_OUTP(MDP_BASE + 0x50318, 0x31c0006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xbc000a0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x3140006b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc8000a2); + MDP_OUTP(MDP_BASE + 0x50320, 0x31000067); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xd8000a5); + MDP_OUTP(MDP_BASE + 0x50324, 0x30800062); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xe4000a8); + MDP_OUTP(MDP_BASE + 0x50328, 0x2fc0005f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xec000aa); + MDP_OUTP(MDP_BASE + 0x5032c, 0x2fc0005b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8000ad); + MDP_OUTP(MDP_BASE + 0x50330, 0x2f400057); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x108000b0); + MDP_OUTP(MDP_BASE + 0x50334, 0x2e400054); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x114000b2); + MDP_OUTP(MDP_BASE + 0x50338, 0x2e000050); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x124000b4); + MDP_OUTP(MDP_BASE + 0x5033c, 0x2d80004c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x130000b6); + MDP_OUTP(MDP_BASE + 0x50340, 0x2d000049); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x140000b8); + MDP_OUTP(MDP_BASE + 0x50344, 0x2c800045); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x150000b9); + MDP_OUTP(MDP_BASE + 0x50348, 0x2c000042); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x15c000bd); + MDP_OUTP(MDP_BASE + 0x5034c, 0x2b40003e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x16c000bf); + MDP_OUTP(MDP_BASE + 0x50350, 0x2a80003b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x17c000bf); + MDP_OUTP(MDP_BASE + 0x50354, 0x2a000039); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x188000c2); + MDP_OUTP(MDP_BASE + 0x50358, 0x29400036); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x19c000c4); + MDP_OUTP(MDP_BASE + 0x5035c, 0x28800032); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac000c5); + MDP_OUTP(MDP_BASE + 0x50360, 0x2800002f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc000c7); + MDP_OUTP(MDP_BASE + 0x50364, 0x2740002c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc000c8); + MDP_OUTP(MDP_BASE + 0x50368, 0x26c00029); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc000c9); + MDP_OUTP(MDP_BASE + 0x5036c, 0x26000027); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec000cc); + MDP_OUTP(MDP_BASE + 0x50370, 0x25000024); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x200000cc); + MDP_OUTP(MDP_BASE + 0x50374, 0x24800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x210000cd); + MDP_OUTP(MDP_BASE + 0x50378, 0x23800020); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x220000ce); + MDP_OUTP(MDP_BASE + 0x5037c, 0x2300001d); +} + +static void mdp_load_bc_downscale_table_x_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000070); + MDP_OUTP(MDP_BASE + 0x50280, 0x4bc00068); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000078); + MDP_OUTP(MDP_BASE + 0x50284, 0x4bc00060); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000080); + MDP_OUTP(MDP_BASE + 0x50288, 0x4b800059); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000089); + MDP_OUTP(MDP_BASE + 0x5028c, 0x4b000052); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe400091); + MDP_OUTP(MDP_BASE + 0x50290, 0x4a80004b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40009a); + MDP_OUTP(MDP_BASE + 0x50294, 0x4a000044); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe8000a3); + MDP_OUTP(MDP_BASE + 0x50298, 0x4940003d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec000ac); + MDP_OUTP(MDP_BASE + 0x5029c, 0x48400037); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff0000b4); + MDP_OUTP(MDP_BASE + 0x502a0, 0x47800031); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff8000bd); + MDP_OUTP(MDP_BASE + 0x502a4, 0x4640002b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc5); + MDP_OUTP(MDP_BASE + 0x502a8, 0x45000026); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8000ce); + MDP_OUTP(MDP_BASE + 0x502ac, 0x43800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x10000d6); + MDP_OUTP(MDP_BASE + 0x502b0, 0x4240001c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x18000df); + MDP_OUTP(MDP_BASE + 0x502b4, 0x40800018); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x24000e6); + MDP_OUTP(MDP_BASE + 0x502b8, 0x3f000014); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x30000ee); + MDP_OUTP(MDP_BASE + 0x502bc, 0x3d400010); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x40000f5); + MDP_OUTP(MDP_BASE + 0x502c0, 0x3b80000c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x50000fc); + MDP_OUTP(MDP_BASE + 0x502c4, 0x39800009); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x6000102); + MDP_OUTP(MDP_BASE + 0x502c8, 0x37c00006); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x7000109); + MDP_OUTP(MDP_BASE + 0x502cc, 0x35800004); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x840010e); + MDP_OUTP(MDP_BASE + 0x502d0, 0x33800002); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9800114); + MDP_OUTP(MDP_BASE + 0x502d4, 0x31400000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xac00119); + MDP_OUTP(MDP_BASE + 0x502d8, 0x2f4003fe); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc40011e); + MDP_OUTP(MDP_BASE + 0x502dc, 0x2d0003fc); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xdc00121); + MDP_OUTP(MDP_BASE + 0x502e0, 0x2b0003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf400125); + MDP_OUTP(MDP_BASE + 0x502e4, 0x28c003fa); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x11000128); + MDP_OUTP(MDP_BASE + 0x502e8, 0x268003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x12c0012a); + MDP_OUTP(MDP_BASE + 0x502ec, 0x244003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1480012c); + MDP_OUTP(MDP_BASE + 0x502f0, 0x224003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1640012e); + MDP_OUTP(MDP_BASE + 0x502f4, 0x200003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1800012f); + MDP_OUTP(MDP_BASE + 0x502f8, 0x1e0003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1a00012f); + MDP_OUTP(MDP_BASE + 0x502fc, 0x1c0003f8); +} + +static void mdp_load_bc_downscale_table_y_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000070); + MDP_OUTP(MDP_BASE + 0x50300, 0x4bc00068); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000078); + MDP_OUTP(MDP_BASE + 0x50304, 0x4bc00060); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000080); + MDP_OUTP(MDP_BASE + 0x50308, 0x4b800059); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000089); + MDP_OUTP(MDP_BASE + 0x5030c, 0x4b000052); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe400091); + MDP_OUTP(MDP_BASE + 0x50310, 0x4a80004b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40009a); + MDP_OUTP(MDP_BASE + 0x50314, 0x4a000044); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe8000a3); + MDP_OUTP(MDP_BASE + 0x50318, 0x4940003d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec000ac); + MDP_OUTP(MDP_BASE + 0x5031c, 0x48400037); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff0000b4); + MDP_OUTP(MDP_BASE + 0x50320, 0x47800031); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff8000bd); + MDP_OUTP(MDP_BASE + 0x50324, 0x4640002b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc5); + MDP_OUTP(MDP_BASE + 0x50328, 0x45000026); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8000ce); + MDP_OUTP(MDP_BASE + 0x5032c, 0x43800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x10000d6); + MDP_OUTP(MDP_BASE + 0x50330, 0x4240001c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x18000df); + MDP_OUTP(MDP_BASE + 0x50334, 0x40800018); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x24000e6); + MDP_OUTP(MDP_BASE + 0x50338, 0x3f000014); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x30000ee); + MDP_OUTP(MDP_BASE + 0x5033c, 0x3d400010); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x40000f5); + MDP_OUTP(MDP_BASE + 0x50340, 0x3b80000c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x50000fc); + MDP_OUTP(MDP_BASE + 0x50344, 0x39800009); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x6000102); + MDP_OUTP(MDP_BASE + 0x50348, 0x37c00006); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x7000109); + MDP_OUTP(MDP_BASE + 0x5034c, 0x35800004); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x840010e); + MDP_OUTP(MDP_BASE + 0x50350, 0x33800002); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9800114); + MDP_OUTP(MDP_BASE + 0x50354, 0x31400000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xac00119); + MDP_OUTP(MDP_BASE + 0x50358, 0x2f4003fe); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc40011e); + MDP_OUTP(MDP_BASE + 0x5035c, 0x2d0003fc); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xdc00121); + MDP_OUTP(MDP_BASE + 0x50360, 0x2b0003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf400125); + MDP_OUTP(MDP_BASE + 0x50364, 0x28c003fa); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x11000128); + MDP_OUTP(MDP_BASE + 0x50368, 0x268003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x12c0012a); + MDP_OUTP(MDP_BASE + 0x5036c, 0x244003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1480012c); + MDP_OUTP(MDP_BASE + 0x50370, 0x224003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1640012e); + MDP_OUTP(MDP_BASE + 0x50374, 0x200003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1800012f); + MDP_OUTP(MDP_BASE + 0x50378, 0x1e0003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1a00012f); + MDP_OUTP(MDP_BASE + 0x5037c, 0x1c0003f8); +} + +static void mdp_load_bc_downscale_table_x_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d); + MDP_OUTP(MDP_BASE + 0x50284, 0x7ec003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c); + MDP_OUTP(MDP_BASE + 0x50288, 0x7d4003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7b8003ed); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c); + MDP_OUTP(MDP_BASE + 0x50290, 0x794003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d); + MDP_OUTP(MDP_BASE + 0x50294, 0x76c003e4); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f); + MDP_OUTP(MDP_BASE + 0x50298, 0x73c003e0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071); + MDP_OUTP(MDP_BASE + 0x5029c, 0x708003de); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085); + MDP_OUTP(MDP_BASE + 0x502a0, 0x6d0003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098); + MDP_OUTP(MDP_BASE + 0x502a4, 0x698003d9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac); + MDP_OUTP(MDP_BASE + 0x502a8, 0x654003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1); + MDP_OUTP(MDP_BASE + 0x502ac, 0x610003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5); + MDP_OUTP(MDP_BASE + 0x502b0, 0x5c8003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9); + MDP_OUTP(MDP_BASE + 0x502b4, 0x580003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd); + MDP_OUTP(MDP_BASE + 0x502b8, 0x534003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112); + MDP_OUTP(MDP_BASE + 0x502bc, 0x4e8003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126); + MDP_OUTP(MDP_BASE + 0x502c0, 0x494003da); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a); + MDP_OUTP(MDP_BASE + 0x502c4, 0x448003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d); + MDP_OUTP(MDP_BASE + 0x502c8, 0x3f4003dd); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160); + MDP_OUTP(MDP_BASE + 0x502cc, 0x3a4003df); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172); + MDP_OUTP(MDP_BASE + 0x502d0, 0x354003e1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184); + MDP_OUTP(MDP_BASE + 0x502d4, 0x304003e3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195); + MDP_OUTP(MDP_BASE + 0x502d8, 0x2b0003e6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6); + MDP_OUTP(MDP_BASE + 0x502dc, 0x260003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4); + MDP_OUTP(MDP_BASE + 0x502e0, 0x214003eb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2); + MDP_OUTP(MDP_BASE + 0x502e4, 0x1c4003ee); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf); + MDP_OUTP(MDP_BASE + 0x502e8, 0x17c003f1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db); + MDP_OUTP(MDP_BASE + 0x502ec, 0x134003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5); + MDP_OUTP(MDP_BASE + 0x502f0, 0xf0003f6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee); + MDP_OUTP(MDP_BASE + 0x502f4, 0xac003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5); + MDP_OUTP(MDP_BASE + 0x502f8, 0x70003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb); + MDP_OUTP(MDP_BASE + 0x502fc, 0x34003fe); +} + +static void mdp_load_bc_downscale_table_y_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d); + MDP_OUTP(MDP_BASE + 0x50304, 0x7ec003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c); + MDP_OUTP(MDP_BASE + 0x50308, 0x7d4003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7b8003ed); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c); + MDP_OUTP(MDP_BASE + 0x50310, 0x794003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d); + MDP_OUTP(MDP_BASE + 0x50314, 0x76c003e4); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f); + MDP_OUTP(MDP_BASE + 0x50318, 0x73c003e0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071); + MDP_OUTP(MDP_BASE + 0x5031c, 0x708003de); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085); + MDP_OUTP(MDP_BASE + 0x50320, 0x6d0003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098); + MDP_OUTP(MDP_BASE + 0x50324, 0x698003d9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac); + MDP_OUTP(MDP_BASE + 0x50328, 0x654003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1); + MDP_OUTP(MDP_BASE + 0x5032c, 0x610003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5); + MDP_OUTP(MDP_BASE + 0x50330, 0x5c8003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9); + MDP_OUTP(MDP_BASE + 0x50334, 0x580003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd); + MDP_OUTP(MDP_BASE + 0x50338, 0x534003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112); + MDP_OUTP(MDP_BASE + 0x5033c, 0x4e8003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126); + MDP_OUTP(MDP_BASE + 0x50340, 0x494003da); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a); + MDP_OUTP(MDP_BASE + 0x50344, 0x448003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d); + MDP_OUTP(MDP_BASE + 0x50348, 0x3f4003dd); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160); + MDP_OUTP(MDP_BASE + 0x5034c, 0x3a4003df); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172); + MDP_OUTP(MDP_BASE + 0x50350, 0x354003e1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184); + MDP_OUTP(MDP_BASE + 0x50354, 0x304003e3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195); + MDP_OUTP(MDP_BASE + 0x50358, 0x2b0003e6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6); + MDP_OUTP(MDP_BASE + 0x5035c, 0x260003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4); + MDP_OUTP(MDP_BASE + 0x50360, 0x214003eb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2); + MDP_OUTP(MDP_BASE + 0x50364, 0x1c4003ee); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf); + MDP_OUTP(MDP_BASE + 0x50368, 0x17c003f1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db); + MDP_OUTP(MDP_BASE + 0x5036c, 0x134003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5); + MDP_OUTP(MDP_BASE + 0x50370, 0xf0003f6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee); + MDP_OUTP(MDP_BASE + 0x50374, 0xac003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5); + MDP_OUTP(MDP_BASE + 0x50378, 0x70003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb); + MDP_OUTP(MDP_BASE + 0x5037c, 0x34003fe); +} + +static int mdp_get_edge_cond(MDPIBUF *iBuf, uint32 *dup, uint32 *dup2) +{ + uint32 reg; + uint32 dst_roi_width; /* Dimensions of DST ROI. */ + uint32 dst_roi_height; /* Used to calculate scaling ratios. */ + + /* + * positions of the luma pixel(relative to the image ) required for + * scaling the ROI + */ + int32 luma_interp_point_left = 0; /* left-most luma pixel needed */ + int32 luma_interp_point_right = 0; /* right-most luma pixel needed */ + int32 luma_interp_point_top = 0; /* top-most luma pixel needed */ + int32 luma_interp_point_bottom = 0; /* bottom-most luma pixel needed */ + + /* + * positions of the chroma pixel(relative to the image ) required for + * interpolating a chroma value at all required luma positions + */ + /* left-most chroma pixel needed */ + int32 chroma_interp_point_left = 0; + /* right-most chroma pixel needed */ + int32 chroma_interp_point_right = 0; + /* top-most chroma pixel needed */ + int32 chroma_interp_point_top = 0; + /* bottom-most chroma pixel needed */ + int32 chroma_interp_point_bottom = 0; + + /* + * a rectangular region within the chroma plane of the "image". + * Chroma pixels falling inside of this rectangle belongs to the ROI + */ + int32 chroma_bound_left = 0; + int32 chroma_bound_right = 0; + int32 chroma_bound_top = 0; + int32 chroma_bound_bottom = 0; + + /* + * number of chroma pixels to replicate on the left, right, + * top and bottom edge of the ROI. + */ + int32 chroma_repeat_left = 0; + int32 chroma_repeat_right = 0; + int32 chroma_repeat_top = 0; + int32 chroma_repeat_bottom = 0; + + /* + * number of luma pixels to replicate on the left, right, + * top and bottom edge of the ROI. + */ + int32 luma_repeat_left = 0; + int32 luma_repeat_right = 0; + int32 luma_repeat_top = 0; + int32 luma_repeat_bottom = 0; + + boolean chroma_edge_enable; + + uint32 _is_scale_enabled = 0; + uint32 _is_yuv_offsite_vertical = 0; + + /* fg edge duplicate */ + reg = 0x0; + + if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) { /* if scaling enabled */ + + _is_scale_enabled = 1; + + /* + * if rotation mode involves a 90 deg rotation, flip + * dst_roi_width with dst_roi_height. + * Scaling ratios is based on source ROI dimensions, and + * dst ROI dimensions before rotation. + */ + if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) { + dst_roi_width = iBuf->roi.dst_height; + dst_roi_height = iBuf->roi.dst_width; + } else { + dst_roi_width = iBuf->roi.dst_width; + dst_roi_height = iBuf->roi.dst_height; + } + + /* + * Find out the luma pixels needed for scaling in the + * x direction (LEFT and RIGHT). Locations of pixels are + * relative to the ROI. Upper-left corner of ROI corresponds + * to coordinates (0,0). Also set the number of luma pixel + * to repeat. + */ + if (iBuf->roi.width > 3 * dst_roi_width) { + /* scale factor < 1/3 */ + luma_interp_point_left = 0; + luma_interp_point_right = (iBuf->roi.width - 1); + luma_repeat_left = 0; + luma_repeat_right = 0; + } else if (iBuf->roi.width == 3 * dst_roi_width) { + /* scale factor == 1/3 */ + luma_interp_point_left = 0; + luma_interp_point_right = (iBuf->roi.width - 1) + 1; + luma_repeat_left = 0; + luma_repeat_right = 1; + } else if ((iBuf->roi.width > dst_roi_width) && + (iBuf->roi.width < 3 * dst_roi_width)) { + /* 1/3 < scale factor < 1 */ + luma_interp_point_left = -1; + luma_interp_point_right = (iBuf->roi.width - 1) + 1; + luma_repeat_left = 1; + luma_repeat_right = 1; + } + + else if (iBuf->roi.width == dst_roi_width) { + /* scale factor == 1 */ + luma_interp_point_left = -1; + luma_interp_point_right = (iBuf->roi.width - 1) + 2; + luma_repeat_left = 1; + luma_repeat_right = 2; + } else { /* (iBuf->roi.width < dst_roi_width) */ + /* scale factor > 1 */ + luma_interp_point_left = -2; + luma_interp_point_right = (iBuf->roi.width - 1) + 2; + luma_repeat_left = 2; + luma_repeat_right = 2; + } + + /* + * Find out the number of pixels needed for scaling in the + * y direction (TOP and BOTTOM). Locations of pixels are + * relative to the ROI. Upper-left corner of ROI corresponds + * to coordinates (0,0). Also set the number of luma pixel + * to repeat. + */ + if (iBuf->roi.height > 3 * dst_roi_height) { + /* scale factor < 1/3 */ + luma_interp_point_top = 0; + luma_interp_point_bottom = (iBuf->roi.height - 1); + luma_repeat_top = 0; + luma_repeat_bottom = 0; + } else if (iBuf->roi.height == 3 * dst_roi_height) { + /* scale factor == 1/3 */ + luma_interp_point_top = 0; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 1; + luma_repeat_top = 0; + luma_repeat_bottom = 1; + } else if ((iBuf->roi.height > dst_roi_height) && + (iBuf->roi.height < 3 * dst_roi_height)) { + /* 1/3 < scale factor < 1 */ + luma_interp_point_top = -1; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 1; + luma_repeat_top = 1; + luma_repeat_bottom = 1; + } else if (iBuf->roi.height == dst_roi_height) { + /* scale factor == 1 */ + luma_interp_point_top = -1; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 2; + luma_repeat_top = 1; + luma_repeat_bottom = 2; + } else { /* (iBuf->roi.height < dst_roi_height) */ + /* scale factor > 1 */ + luma_interp_point_top = -2; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 2; + luma_repeat_top = 2; + luma_repeat_bottom = 2; + } + } /* if (iBuf->scale.scale_flag) */ + else { /* scaling disabled */ + /* + * Since no scaling needed, Tile Fetch does not require any + * more luma pixel than what the ROI contains. + */ + luma_interp_point_left = (int32) 0; + luma_interp_point_right = (int32) (iBuf->roi.width - 1); + luma_interp_point_top = (int32) 0; + luma_interp_point_bottom = (int32) (iBuf->roi.height - 1); + + luma_repeat_left = 0; + luma_repeat_right = 0; + luma_repeat_top = 0; + luma_repeat_bottom = 0; + } + + /* After adding the ROI offsets, we have locations of + * luma_interp_points relative to the image. + */ + luma_interp_point_left += (int32) (iBuf->roi.x); + luma_interp_point_right += (int32) (iBuf->roi.x); + luma_interp_point_top += (int32) (iBuf->roi.y); + luma_interp_point_bottom += (int32) (iBuf->roi.y); + + /* + * After adding the ROI offsets, we have locations of + * chroma_interp_points relative to the image. + */ + chroma_interp_point_left = luma_interp_point_left; + chroma_interp_point_right = luma_interp_point_right; + chroma_interp_point_top = luma_interp_point_top; + chroma_interp_point_bottom = luma_interp_point_bottom; + + chroma_edge_enable = TRUE; + /* find out which chroma pixels are needed for chroma upsampling. */ + switch (iBuf->mdpImg.imgType) { + /* + * cosite in horizontal axis + * fully sampled in vertical axis + */ + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + /* floor( luma_interp_point_left / 2 ); */ + chroma_interp_point_left = luma_interp_point_left >> 1; + /* floor( ( luma_interp_point_right + 1 ) / 2 ); */ + chroma_interp_point_right = (luma_interp_point_right + 1) >> 1; + + chroma_interp_point_top = luma_interp_point_top; + chroma_interp_point_bottom = luma_interp_point_bottom; + break; + + /* + * cosite in horizontal axis + * offsite in vertical axis + */ + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + /* floor( luma_interp_point_left / 2) */ + chroma_interp_point_left = luma_interp_point_left >> 1; + + /* floor( ( luma_interp_point_right + 1 )/ 2 ) */ + chroma_interp_point_right = (luma_interp_point_right + 1) >> 1; + + /* floor( (luma_interp_point_top - 1 ) / 2 ) */ + chroma_interp_point_top = (luma_interp_point_top - 1) >> 1; + + /* floor( ( luma_interp_point_bottom + 1 ) / 2 ) */ + chroma_interp_point_bottom = + (luma_interp_point_bottom + 1) >> 1; + + _is_yuv_offsite_vertical = 1; + break; + + default: + chroma_edge_enable = FALSE; + chroma_interp_point_left = luma_interp_point_left; + chroma_interp_point_right = luma_interp_point_right; + chroma_interp_point_top = luma_interp_point_top; + chroma_interp_point_bottom = luma_interp_point_bottom; + + break; + } + + /* only if the image type is in YUV domain, we calculate chroma edge */ + if (chroma_edge_enable) { + /* Defines which chroma pixels belongs to the roi */ + switch (iBuf->mdpImg.imgType) { + /* + * Cosite in horizontal direction, and fully sampled + * in vertical direction. + */ + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + /* + * width of chroma ROI is 1/2 of size of luma ROI + * height of chroma ROI same as size of luma ROI + */ + chroma_bound_left = iBuf->roi.x / 2; + + /* there are half as many chroma pixel as luma pixels */ + chroma_bound_right = + (iBuf->roi.width + iBuf->roi.x - 1) / 2; + chroma_bound_top = iBuf->roi.y; + chroma_bound_bottom = + (iBuf->roi.height + iBuf->roi.y - 1); + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + /* + * cosite in horizontal dir, and offsite in vertical dir + * width of chroma ROI is 1/2 of size of luma ROI + * height of chroma ROI is 1/2 of size of luma ROI + */ + + chroma_bound_left = iBuf->roi.x / 2; + chroma_bound_right = + (iBuf->roi.width + iBuf->roi.x - 1) / 2; + chroma_bound_top = iBuf->roi.y / 2; + chroma_bound_bottom = + (iBuf->roi.height + iBuf->roi.y - 1) / 2; + break; + + default: + /* + * If no valid chroma sub-sampling format specified, + * assume 4:4:4 ( i.e. fully sampled). Set ROI + * boundaries for chroma same as ROI boundaries for + * luma. + */ + chroma_bound_left = iBuf->roi.x; + chroma_bound_right = iBuf->roi.width + iBuf->roi.x - 1; + chroma_bound_top = iBuf->roi.y; + chroma_bound_bottom = + (iBuf->roi.height + iBuf->roi.y - 1); + break; + } + + /* + * Knowing which chroma pixels are needed, and which chroma + * pixels belong to the ROI (i.e. available for fetching ), + * calculate how many chroma pixels Tile Fetch needs to + * duplicate. If any required chroma pixels falls outside + * of the ROI, Tile Fetch must obtain them by replicating + * pixels. + */ + if (chroma_bound_left > chroma_interp_point_left) + chroma_repeat_left = + chroma_bound_left - chroma_interp_point_left; + else + chroma_repeat_left = 0; + + if (chroma_interp_point_right > chroma_bound_right) + chroma_repeat_right = + chroma_interp_point_right - chroma_bound_right; + else + chroma_repeat_right = 0; + + if (chroma_bound_top > chroma_interp_point_top) + chroma_repeat_top = + chroma_bound_top - chroma_interp_point_top; + else + chroma_repeat_top = 0; + + if (chroma_interp_point_bottom > chroma_bound_bottom) + chroma_repeat_bottom = + chroma_interp_point_bottom - chroma_bound_bottom; + else + chroma_repeat_bottom = 0; + + if (_is_scale_enabled && (iBuf->roi.height == 1) + && _is_yuv_offsite_vertical) { + chroma_repeat_bottom = 3; + chroma_repeat_top = 0; + } + } + /* make sure chroma repeats are non-negative */ + if ((chroma_repeat_left < 0) || (chroma_repeat_right < 0) || + (chroma_repeat_top < 0) || (chroma_repeat_bottom < 0)) + return -1; + + /* make sure chroma repeats are no larger than 3 pixels */ + if ((chroma_repeat_left > 3) || (chroma_repeat_right > 3) || + (chroma_repeat_top > 3) || (chroma_repeat_bottom > 3)) + return -1; + + /* make sure luma repeats are non-negative */ + if ((luma_repeat_left < 0) || (luma_repeat_right < 0) || + (luma_repeat_top < 0) || (luma_repeat_bottom < 0)) + return -1; + + /* make sure luma repeats are no larger than 3 pixels */ + if ((luma_repeat_left > 3) || (luma_repeat_right > 3) || + (luma_repeat_top > 3) || (luma_repeat_bottom > 3)) + return -1; + + /* write chroma_repeat_left to register */ + reg |= (chroma_repeat_left & 3) << MDP_LEFT_CHROMA; + + /* write chroma_repeat_right to register */ + reg |= (chroma_repeat_right & 3) << MDP_RIGHT_CHROMA; + + /* write chroma_repeat_top to register */ + reg |= (chroma_repeat_top & 3) << MDP_TOP_CHROMA; + + /* write chroma_repeat_bottom to register */ + reg |= (chroma_repeat_bottom & 3) << MDP_BOTTOM_CHROMA; + + /* write luma_repeat_left to register */ + reg |= (luma_repeat_left & 3) << MDP_LEFT_LUMA; + + /* write luma_repeat_right to register */ + reg |= (luma_repeat_right & 3) << MDP_RIGHT_LUMA; + + /* write luma_repeat_top to register */ + reg |= (luma_repeat_top & 3) << MDP_TOP_LUMA; + + /* write luma_repeat_bottom to register */ + reg |= (luma_repeat_bottom & 3) << MDP_BOTTOM_LUMA; + + /* done with reg */ + *dup = reg; + + /* bg edge duplicate */ + reg = 0x0; + + switch (iBuf->ibuf_type) { + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + /* + * Edge condition for MDP_Y_CRCB/CBCR_H2V2 cosite only. + * For 420 cosite, 1 chroma replicated on all sides except + * left, so reg 101b8 should be 0x0209. For 420 offsite, + * 1 chroma replicated all sides. + */ + if (iBuf->roi.lcd_y == 0) { + reg |= BIT(MDP_TOP_CHROMA); + } + + if ((iBuf->roi.lcd_y + iBuf->roi.dst_height) == + iBuf->ibuf_height) { + reg |= BIT(MDP_BOTTOM_CHROMA); + } + + if (((iBuf->roi.lcd_x + iBuf->roi.dst_width) == + iBuf->ibuf_width) && ((iBuf->roi.dst_width % 2) == 0)) { + reg |= BIT(MDP_RIGHT_CHROMA); + } + + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + if (((iBuf->roi.lcd_x + iBuf->roi.dst_width) == + iBuf->ibuf_width) && ((iBuf->roi.dst_width % 2) == 0)) { + reg |= BIT(MDP_RIGHT_CHROMA); + } + break; + default: + break; + } + + *dup2 = reg; + + return 0; +} + +#define ADJUST_IP /* for 1/3 scale factor fix */ + +static int mdp_calc_scale_params( +/* ROI origin coordinate for the dimension */ + uint32 org, +/* src ROI dimension */ + uint32 dim_in, +/* scaled ROI dimension*/ + uint32 dim_out, +/* is this ROI width dimension? */ + boolean is_W, +/* initial phase location address */ + int32 *phase_init_ptr, +/* phase increment location address */ + uint32 *phase_step_ptr, +/* ROI start over-fetch location address */ + uint32 *num_repl_beg_ptr, +/* ROI end over-fetch location address */ + uint32 *num_repl_end_ptr) +{ + boolean rpa_on = FALSE; + int init_phase = 0; + uint32 beg_of = 0; + uint32 end_of = 0; + uint64 numer = 0; + uint64 denom = 0; + /*uint64 inverter = 1; */ + int64 point5 = 1; + int64 one = 1; + int64 k1, k2, k3, k4; /* linear equation coefficients */ + uint64 int_mask; + uint64 fract_mask; + uint64 Os; + int64 Osprime; + int64 Od; + int64 Odprime; + int64 Oreq; + uint64 Es; + uint64 Ed; + uint64 Ereq; +#ifdef ADJUST_IP + int64 IP64; + int64 delta; +#endif + uint32 mult; + + /* + * The phase accumulator should really be rational for all cases in a + * general purpose polyphase scaler for a tiled architecture with + * non-zero * origin capability because there is no way to represent + * certain scale factors in fixed point regardless of precision. + * The error incurred in attempting to use fixed point is most + * eggregious for SF where 1/SF is an integral multiple of 1/3. + * + * However, since the MDP2 has already been committed to HW, we + * only use the rational phase accumulator (RPA) when 1/SF is an + * integral multiple of 1/3. This will help minimize regressions in + * matching the HW to the C-Sim. + */ + /* + * Set the RPA flag for this dimension. + * + * In order for 1/SF (dim_in/dim_out) to be an integral multiple of + * 1/3, dim_out must be an integral multiple of 3. + */ + if (!(dim_out % 3)) { + mult = dim_out / 3; + rpa_on = (!(dim_in % mult)); + } + + numer = dim_out; + denom = dim_in; + + /* + * convert to U30.34 before division + * + * The K vectors carry 4 extra bits of precision + * and are rounded. + * + * We initially go 5 bits over then round by adding + * 1 and right shifting by 1 + * so final result is U31.33 + */ + numer <<= PQF_PLUS_5; + + /* now calculate the scale factor (aka k3) */ + k3 = ((mdp_do_div(numer, denom) + 1) >> 1); + + /* check scale factor for legal range [0.25 - 4.0] */ + if (((k3 >> 4) < (1LL << PQF_MINUS_2)) || + ((k3 >> 4) > (1LL << PQF_PLUS_2))) { + return -1; + } + + /* calculate inverse scale factor (aka k1) for phase init */ + numer = dim_in; + denom = dim_out; + numer <<= PQF_PLUS_5; + k1 = ((mdp_do_div(numer, denom) + 1) >> 1); + + /* + * calculate initial phase and ROI overfetch + */ + /* convert point5 & one to S39.24 (will always be positive) */ + point5 <<= (PQF_PLUS_4 - 1); + one <<= PQF_PLUS_4; + k2 = ((k1 - one) >> 1); + init_phase = (int)(k2 >> 4); + k4 = ((k3 - one) >> 1); + if (k3 == one) { + /* the simple case; SF = 1.0 */ + beg_of = 1; + end_of = 2; + } else { + /* calculate the masks */ + fract_mask = one - 1; + int_mask = ~fract_mask; + + if (!rpa_on) { + /* + * FIXED POINT IMPLEMENTATION + */ + if (!org) { + /* A fairly simple case; ROI origin = 0 */ + if (k1 < one) { + /* upscaling */ + beg_of = end_of = 2; + } + /* 0.33 <= SF < 1.0 */ + else if (k1 < (3LL << PQF_PLUS_4)) + beg_of = end_of = 1; + /* 0.33 == SF */ + else if (k1 == (3LL << PQF_PLUS_4)) { + beg_of = 0; + end_of = 1; + } + /* 0.25 <= SF < 0.33 */ + else + beg_of = end_of = 0; + } else { + /* + * The complicated case; ROI origin != 0 + * init_phase needs to be adjusted + * OF is also position dependent + */ + + /* map (org - .5) into destination space */ + Os = ((uint64) org << 1) - 1; + Od = ((k3 * Os) >> 1) + k4; + + /* take the ceiling */ + Odprime = (Od & int_mask); + if (Odprime != Od) + Odprime += one; + + /* now map that back to source space */ + Osprime = (k1 * (Odprime >> PQF_PLUS_4)) + k2; + + /* then floor & decrement to calculate the required + starting coordinate */ + Oreq = (Osprime & int_mask) - one; + + /* calculate end coord in destination space then map to + source space */ + Ed = Odprime + + ((uint64) dim_out << PQF_PLUS_4) - one; + Es = (k1 * (Ed >> PQF_PLUS_4)) + k2; + + /* now floor & increment by 2 to calculate the required + ending coordinate */ + Ereq = (Es & int_mask) + (one << 1); + + /* calculate initial phase */ +#ifdef ADJUST_IP + + IP64 = Osprime - Oreq; + delta = ((int64) (org) << PQF_PLUS_4) - Oreq; + IP64 -= delta; + + /* limit to valid range before the left shift */ + delta = (IP64 & (1LL << 63)) ? 4 : -4; + delta <<= PQF_PLUS_4; + while (abs((int)(IP64 >> PQF_PLUS_4)) > 4) + IP64 += delta; + + /* right shift to account for extra bits of precision */ + init_phase = (int)(IP64 >> 4); + +#else /* ADJUST_IP */ + + /* just calculate the real initial phase */ + init_phase = (int)((Osprime - Oreq) >> 4); + +#endif /* ADJUST_IP */ + + /* calculate the overfetch */ + beg_of = org - (uint32) (Oreq >> PQF_PLUS_4); + end_of = + (uint32) (Ereq >> PQF_PLUS_4) - (org + + dim_in - + 1); + } + } else { + /* + * RPA IMPLEMENTATION + * + * init_phase needs to be calculated in all RPA_on cases + * because it's a numerator, not a fixed point value. + */ + + /* map (org - .5) into destination space */ + Os = ((uint64) org << PQF_PLUS_4) - point5; + Od = mdp_do_div((dim_out * (Os + point5)), + dim_in) - point5; + + /* take the ceiling */ + Odprime = (Od & int_mask); + if (Odprime != Od) + Odprime += one; + + /* now map that back to source space */ + Osprime = + mdp_do_div((dim_in * (Odprime + point5)), + dim_out) - point5; + + /* then floor & decrement to calculate the required + starting coordinate */ + Oreq = (Osprime & int_mask) - one; + + /* calculate end coord in destination space then map to + source space */ + Ed = Odprime + ((uint64) dim_out << PQF_PLUS_4) - one; + Es = mdp_do_div((dim_in * (Ed + point5)), + dim_out) - point5; + + /* now floor & increment by 2 to calculate the required + ending coordinate */ + Ereq = (Es & int_mask) + (one << 1); + + /* calculate initial phase */ + +#ifdef ADJUST_IP + + IP64 = Osprime - Oreq; + delta = ((int64) (org) << PQF_PLUS_4) - Oreq; + IP64 -= delta; + + /* limit to valid range before the left shift */ + delta = (IP64 & (1LL << 63)) ? 4 : -4; + delta <<= PQF_PLUS_4; + while (abs((int)(IP64 >> PQF_PLUS_4)) > 4) + IP64 += delta; + + /* right shift to account for extra bits of precision */ + init_phase = (int)(IP64 >> 4); + +#else /* ADJUST_IP */ + + /* just calculate the real initial phase */ + init_phase = (int)((Osprime - Oreq) >> 4); + +#endif /* ADJUST_IP */ + + /* calculate the overfetch */ + beg_of = org - (uint32) (Oreq >> PQF_PLUS_4); + end_of = + (uint32) (Ereq >> PQF_PLUS_4) - (org + dim_in - 1); + } + } + + /* return the scale parameters */ + *phase_init_ptr = init_phase; + *phase_step_ptr = (uint32) (k1 >> 4); + *num_repl_beg_ptr = beg_of; + *num_repl_end_ptr = end_of; + + return 0; +} + +static uint8 *mdp_adjust_rot_addr(MDPIBUF *iBuf, uint8 *addr, uint32 uv) +{ + uint32 dest_ystride = iBuf->ibuf_width * iBuf->bpp; + uint32 h_slice = 1; + + if (uv && ((iBuf->ibuf_type == MDP_Y_CBCR_H2V2) || + (iBuf->ibuf_type == MDP_Y_CRCB_H2V2))) + h_slice = 2; + + if (MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_ROT90) ^ + MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_LR)) { + addr = + addr + (iBuf->roi.dst_width - + MIN(16, iBuf->roi.dst_width)) * iBuf->bpp; + } + if (MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_UD)) { + addr = + addr + ((iBuf->roi.dst_height - + MIN(16, iBuf->roi.dst_height))/h_slice) * dest_ystride; + } + + return addr; +} + +void mdp_set_scale(MDPIBUF *iBuf, + uint32 dst_roi_width, + uint32 dst_roi_height, + boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr) +{ + uint32 dst_roi_width_scale; + uint32 dst_roi_height_scale; + boolean use_pr; + uint32 phasex_step = 0; + uint32 phasey_step = 0; + int32 phasex_init = 0; + int32 phasey_init = 0; + uint32 lines_dup = 0; + uint32 lines_dup_bg = 0; + uint32 dummy; + uint32 mdp_blur = 0; + + if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) { + if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) { + dst_roi_width_scale = dst_roi_height; + dst_roi_height_scale = dst_roi_width; + } else { + dst_roi_width_scale = dst_roi_width; + dst_roi_height_scale = dst_roi_height; + } + + mdp_blur = iBuf->mdpImg.mdpOp & MDPOP_BLUR; + + if ((dst_roi_width_scale != iBuf->roi.width) || + (dst_roi_height_scale != iBuf->roi.height) || + mdp_blur) { + *pppop_reg_ptr |= + (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON); + + /* let's use SHIM logic to calculate the partial ROI scaling */ +#if 0 + phasex_step = + (uint32) mdp_do_div(0x20000000 * iBuf->roi.width, + dst_roi_width_scale); + phasey_step = + (uint32) mdp_do_div(0x20000000 * iBuf->roi.height, + dst_roi_height_scale); + +/* + phasex_step= ((long long) iBuf->roi.width * 0x20000000)/dst_roi_width_scale; + phasey_step= ((long long)iBuf->roi.height * 0x20000000)/dst_roi_height_scale; +*/ + + phasex_init = + (((long long)phasex_step - 0x20000000) >> 1); + phasey_init = + (((long long)phasey_step - 0x20000000) >> 1); + +#else + mdp_calc_scale_params(iBuf->roi.x, iBuf->roi.width, + dst_roi_width_scale, 1, + &phasex_init, &phasex_step, + &dummy, &dummy); + mdp_calc_scale_params(iBuf->roi.y, iBuf->roi.height, + dst_roi_height_scale, 0, + &phasey_init, &phasey_step, + &dummy, &dummy); +#endif + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c, + phasex_init); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140, + phasey_init); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0144, + phasex_step); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0148, + phasey_step); + + use_pr = (inputRGB) && (outputRGB); + + if ((dst_roi_width_scale > iBuf->roi.width) || + (dst_roi_height_scale > iBuf->roi.height)) { + if ((use_pr) + && (mdp_curr_up_scale_xy != + MDP_PR_SCALE_UP)) { + mdp_load_pr_upscale_table(); + mdp_curr_up_scale_xy = MDP_PR_SCALE_UP; + } else if ((!use_pr) + && (mdp_curr_up_scale_xy != + MDP_BC_SCALE_UP)) { + mdp_load_bc_upscale_table(); + mdp_curr_up_scale_xy = MDP_BC_SCALE_UP; + } + } + + if (mdp_blur) { + load_scale_table(mdp_gaussian_blur_table, + ARRAY_SIZE(mdp_gaussian_blur_table)); + mdp_curr_down_scale_x = MDP_SCALE_BLUR; + mdp_curr_down_scale_y = MDP_SCALE_BLUR; + } + + /* 0.2 < x <= 1 scaling factor */ + if ((dst_roi_width_scale <= iBuf->roi.width) && + !mdp_blur) { + if (((dst_roi_width_scale * 10) / + iBuf->roi.width) > 8) { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT8_1)) { + mdp_load_pr_downscale_table_x_point8TO1 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT8_1; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT8_1)) { + mdp_load_bc_downscale_table_x_point8TO1 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT8_1; + } + } else + if (((dst_roi_width_scale * 10) / + iBuf->roi.width) > 6) { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT6_POINT8)) { + mdp_load_pr_downscale_table_x_point6TOpoint8 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT6_POINT8; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT6_POINT8)) + { + mdp_load_bc_downscale_table_x_point6TOpoint8 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT6_POINT8; + } + } else + if (((dst_roi_width_scale * 10) / + iBuf->roi.width) > 4) { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT4_POINT6)) { + mdp_load_pr_downscale_table_x_point4TOpoint6 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT4_POINT6; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT4_POINT6)) + { + mdp_load_bc_downscale_table_x_point4TOpoint6 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT4_POINT6; + } + } else { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT2_POINT4)) { + mdp_load_pr_downscale_table_x_point2TOpoint4 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT2_POINT4; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT2_POINT4)) + { + mdp_load_bc_downscale_table_x_point2TOpoint4 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT2_POINT4; + } + } + } + /* 0.2 < y <= 1 scaling factor */ + if ((dst_roi_height_scale <= iBuf->roi.height) && + !mdp_blur) { + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 8) { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT8_1)) { + mdp_load_pr_downscale_table_y_point8TO1 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT8_1; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT8_1)) { + mdp_load_bc_downscale_table_y_point8TO1 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT8_1; + } + } else + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 6) { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT6_POINT8)) { + mdp_load_pr_downscale_table_y_point6TOpoint8 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT6_POINT8; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT6_POINT8)) + { + mdp_load_bc_downscale_table_y_point6TOpoint8 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT6_POINT8; + } + } else + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 4) { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT4_POINT6)) { + mdp_load_pr_downscale_table_y_point4TOpoint6 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT4_POINT6; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT4_POINT6)) + { + mdp_load_bc_downscale_table_y_point4TOpoint6 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT4_POINT6; + } + } else { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT2_POINT4)) { + mdp_load_pr_downscale_table_y_point2TOpoint4 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT2_POINT4; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT2_POINT4)) + { + mdp_load_bc_downscale_table_y_point2TOpoint4 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT2_POINT4; + } + } + } + } else { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ASCALE); + } + } + /* setting edge condition here after scaling check */ + if (mdp_get_edge_cond(iBuf, &lines_dup, &lines_dup_bg)) + printk(KERN_ERR "msm_fb: mdp_get_edge_cond() error!\n"); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01b8, lines_dup); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01bc, lines_dup_bg); +} + +void mdp_init_scale_table(void) +{ + mdp_curr_up_scale_xy = MDP_INIT_SCALE; + mdp_curr_down_scale_x = MDP_INIT_SCALE; + mdp_curr_down_scale_y = MDP_INIT_SCALE; +} + +void mdp_adjust_start_addr(uint8 **src0, + uint8 **src1, + int v_slice, + int h_slice, + int x, + int y, + uint32 width, + uint32 height, int bpp, MDPIBUF *iBuf, int layer) +{ + *src0 += (x + y * width) * bpp; + + /* if it's dest/bg buffer, we need to adjust it for rotation */ + if (layer != 0) + *src0 = mdp_adjust_rot_addr(iBuf, *src0, 0); + + if (*src1) { + /* + * MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now + * we need to shift x direction same as y dir for offsite + */ + *src1 += + ((x / h_slice) * h_slice + + ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp; + + /* if it's dest/bg buffer, we need to adjust it for rotation */ + if (layer != 0) + *src1 = mdp_adjust_rot_addr(iBuf, *src1, 1); + } +} + +void mdp_set_blend_attr(MDPIBUF *iBuf, + uint32 *alpha, + uint32 *tpVal, + uint32 perPixelAlpha, uint32 *pppop_reg_ptr) +{ + if (perPixelAlpha) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA; + } else { + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + && (iBuf->mdpImg.alpha == 0xff)) { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB); + } + + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + && (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) { + *pppop_reg_ptr |= + PPP_OP_ROT_ON | PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL | + PPP_BLEND_CALPHA_TRNASP; + + *alpha = iBuf->mdpImg.alpha; + *tpVal = iBuf->mdpImg.tpVal; + } else { + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_SRCPIXEL_TRANSP; + *tpVal = iBuf->mdpImg.tpVal; + } else if (iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL | + PPP_OP_BLEND_CONSTANT_ALPHA; + *alpha = iBuf->mdpImg.alpha; + } + } + } +} diff --git a/drivers/staging/msm/mdp_ppp_v31.c b/drivers/staging/msm/mdp_ppp_v31.c new file mode 100644 index 000000000000..76495dbe4e64 --- /dev/null +++ b/drivers/staging/msm/mdp_ppp_v31.c @@ -0,0 +1,828 @@ +/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include "linux/proc_fs.h" + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <asm/div64.h> + +#include "mdp.h" +#include "msm_fb.h" + +#define MDP_SCALE_COEFF_NUM 32 +#define MDP_SCALE_0P2_TO_0P4_INDEX 0 +#define MDP_SCALE_0P4_TO_0P6_INDEX 32 +#define MDP_SCALE_0P6_TO_0P8_INDEX 64 +#define MDP_SCALE_0P8_TO_8P0_INDEX 96 +#define MDP_SCALE_COEFF_MASK 0x3ff + +#define MDP_SCALE_PR 0 +#define MDP_SCALE_FIR 1 + +static uint32 mdp_scale_0p8_to_8p0_mode; +static uint32 mdp_scale_0p6_to_0p8_mode; +static uint32 mdp_scale_0p4_to_0p6_mode; +static uint32 mdp_scale_0p2_to_0p4_mode; + +/* -------- All scaling range, "pixel repeat" -------- */ +static int16 mdp_scale_pixel_repeat_C0[MDP_SCALE_COEFF_NUM] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static int16 mdp_scale_pixel_repeat_C1[MDP_SCALE_COEFF_NUM] = { + 511, 511, 511, 511, 511, 511, 511, 511, + 511, 511, 511, 511, 511, 511, 511, 511, + 511, 511, 511, 511, 511, 511, 511, 511, + 511, 511, 511, 511, 511, 511, 511, 511 +}; + +static int16 mdp_scale_pixel_repeat_C2[MDP_SCALE_COEFF_NUM] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static int16 mdp_scale_pixel_repeat_C3[MDP_SCALE_COEFF_NUM] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* --------------------------- FIR ------------------------------------- */ +/* -------- Downscale, ranging from 0.8x to 8.0x of original size -------- */ + +static int16 mdp_scale_0p8_to_8p0_C0[MDP_SCALE_COEFF_NUM] = { + 0, -7, -13, -19, -24, -28, -32, -34, -37, -39, + -40, -41, -41, -41, -40, -40, -38, -37, -35, -33, + -31, -29, -26, -24, -21, -18, -15, -13, -10, -7, + -5, -2 +}; + +static int16 mdp_scale_0p8_to_8p0_C1[MDP_SCALE_COEFF_NUM] = { + 511, 507, 501, 494, 485, 475, 463, 450, 436, 422, + 405, 388, 370, 352, 333, 314, 293, 274, 253, 233, + 213, 193, 172, 152, 133, 113, 95, 77, 60, 43, + 28, 13 +}; + +static int16 mdp_scale_0p8_to_8p0_C2[MDP_SCALE_COEFF_NUM] = { + 0, 13, 28, 43, 60, 77, 95, 113, 133, 152, + 172, 193, 213, 233, 253, 274, 294, 314, 333, 352, + 370, 388, 405, 422, 436, 450, 463, 475, 485, 494, + 501, 507, +}; + +static int16 mdp_scale_0p8_to_8p0_C3[MDP_SCALE_COEFF_NUM] = { + 0, -2, -5, -7, -10, -13, -15, -18, -21, -24, + -26, -29, -31, -33, -35, -37, -38, -40, -40, -41, + -41, -41, -40, -39, -37, -34, -32, -28, -24, -19, + -13, -7 +}; + +/* -------- Downscale, ranging from 0.6x to 0.8x of original size -------- */ + +static int16 mdp_scale_0p6_to_0p8_C0[MDP_SCALE_COEFF_NUM] = { + 104, 96, 89, 82, 75, 68, 61, 55, 49, 43, + 38, 33, 28, 24, 20, 16, 12, 9, 6, 4, + 2, 0, -2, -4, -5, -6, -7, -7, -8, -8, + -8, -8 +}; + +static int16 mdp_scale_0p6_to_0p8_C1[MDP_SCALE_COEFF_NUM] = { + 303, 303, 302, 300, 298, 296, 293, 289, 286, 281, + 276, 270, 265, 258, 252, 245, 238, 230, 223, 214, + 206, 197, 189, 180, 172, 163, 154, 145, 137, 128, + 120, 112 +}; + +static int16 mdp_scale_0p6_to_0p8_C2[MDP_SCALE_COEFF_NUM] = { + 112, 120, 128, 137, 145, 154, 163, 172, 180, 189, + 197, 206, 214, 223, 230, 238, 245, 252, 258, 265, + 270, 276, 281, 286, 289, 293, 296, 298, 300, 302, + 303, 303 +}; + +static int16 mdp_scale_0p6_to_0p8_C3[MDP_SCALE_COEFF_NUM] = { + -8, -8, -8, -8, -7, -7, -6, -5, -4, -2, + 0, 2, 4, 6, 9, 12, 16, 20, 24, 28, + 33, 38, 43, 49, 55, 61, 68, 75, 82, 89, + 96, 104 +}; + +/* -------- Downscale, ranging from 0.4x to 0.6x of original size -------- */ + +static int16 mdp_scale_0p4_to_0p6_C0[MDP_SCALE_COEFF_NUM] = { + 136, 132, 128, 123, 119, 115, 111, 107, 103, 98, + 95, 91, 87, 84, 80, 76, 73, 69, 66, 62, + 59, 57, 54, 50, 47, 44, 41, 39, 36, 33, + 32, 29 +}; + +static int16 mdp_scale_0p4_to_0p6_C1[MDP_SCALE_COEFF_NUM] = { + 206, 205, 204, 204, 201, 200, 199, 197, 196, 194, + 191, 191, 189, 185, 184, 182, 180, 178, 176, 173, + 170, 168, 165, 162, 160, 157, 155, 152, 148, 146, + 142, 140 +}; + +static int16 mdp_scale_0p4_to_0p6_C2[MDP_SCALE_COEFF_NUM] = { + 140, 142, 146, 148, 152, 155, 157, 160, 162, 165, + 168, 170, 173, 176, 178, 180, 182, 184, 185, 189, + 191, 191, 194, 196, 197, 199, 200, 201, 204, 204, + 205, 206 +}; + +static int16 mdp_scale_0p4_to_0p6_C3[MDP_SCALE_COEFF_NUM] = { + 29, 32, 33, 36, 39, 41, 44, 47, 50, 54, + 57, 59, 62, 66, 69, 73, 76, 80, 84, 87, + 91, 95, 98, 103, 107, 111, 115, 119, 123, 128, + 132, 136 +}; + +/* -------- Downscale, ranging from 0.2x to 0.4x of original size -------- */ + +static int16 mdp_scale_0p2_to_0p4_C0[MDP_SCALE_COEFF_NUM] = { + 131, 131, 130, 129, 128, 127, 127, 126, 125, 125, + 124, 123, 123, 121, 120, 119, 119, 118, 117, 117, + 116, 115, 115, 114, 113, 112, 111, 110, 109, 109, + 108, 107 +}; + +static int16 mdp_scale_0p2_to_0p4_C1[MDP_SCALE_COEFF_NUM] = { + 141, 140, 140, 140, 140, 139, 138, 138, 138, 137, + 137, 137, 136, 137, 137, 137, 136, 136, 136, 135, + 135, 135, 134, 134, 134, 134, 134, 133, 133, 132, + 132, 132 +}; + +static int16 mdp_scale_0p2_to_0p4_C2[MDP_SCALE_COEFF_NUM] = { + 132, 132, 132, 133, 133, 134, 134, 134, 134, 134, + 135, 135, 135, 136, 136, 136, 137, 137, 137, 136, + 137, 137, 137, 138, 138, 138, 139, 140, 140, 140, + 140, 141 +}; + +static int16 mdp_scale_0p2_to_0p4_C3[MDP_SCALE_COEFF_NUM] = { + 107, 108, 109, 109, 110, 111, 112, 113, 114, 115, + 115, 116, 117, 117, 118, 119, 119, 120, 121, 123, + 123, 124, 125, 125, 126, 127, 127, 128, 129, 130, + 131, 131 +}; + +static void mdp_update_scale_table(int index, int16 *c0, int16 *c1, + int16 *c2, int16 *c3) +{ + int i, val; + + for (i = 0; i < MDP_SCALE_COEFF_NUM; i++) { + val = + ((MDP_SCALE_COEFF_MASK & c1[i]) << 16) | + (MDP_SCALE_COEFF_MASK & c0[i]); + MDP_OUTP(MDP_PPP_SCALE_COEFF_LSBn(index), val); + val = + ((MDP_SCALE_COEFF_MASK & c3[i]) << 16) | + (MDP_SCALE_COEFF_MASK & c2[i]); + MDP_OUTP(MDP_PPP_SCALE_COEFF_MSBn(index), val); + index++; + } +} + +void mdp_init_scale_table(void) +{ + mdp_scale_0p2_to_0p4_mode = MDP_SCALE_FIR; + mdp_update_scale_table(MDP_SCALE_0P2_TO_0P4_INDEX, + mdp_scale_0p2_to_0p4_C0, + mdp_scale_0p2_to_0p4_C1, + mdp_scale_0p2_to_0p4_C2, + mdp_scale_0p2_to_0p4_C3); + + mdp_scale_0p4_to_0p6_mode = MDP_SCALE_FIR; + mdp_update_scale_table(MDP_SCALE_0P4_TO_0P6_INDEX, + mdp_scale_0p4_to_0p6_C0, + mdp_scale_0p4_to_0p6_C1, + mdp_scale_0p4_to_0p6_C2, + mdp_scale_0p4_to_0p6_C3); + + mdp_scale_0p6_to_0p8_mode = MDP_SCALE_FIR; + mdp_update_scale_table(MDP_SCALE_0P6_TO_0P8_INDEX, + mdp_scale_0p6_to_0p8_C0, + mdp_scale_0p6_to_0p8_C1, + mdp_scale_0p6_to_0p8_C2, + mdp_scale_0p6_to_0p8_C3); + + mdp_scale_0p8_to_8p0_mode = MDP_SCALE_FIR; + mdp_update_scale_table(MDP_SCALE_0P8_TO_8P0_INDEX, + mdp_scale_0p8_to_8p0_C0, + mdp_scale_0p8_to_8p0_C1, + mdp_scale_0p8_to_8p0_C2, + mdp_scale_0p8_to_8p0_C3); +} + +static long long mdp_do_div(long long num, long long den) +{ + do_div(num, den); + return num; +} + +#define SCALER_PHASE_BITS 29 +#define HAL_MDP_PHASE_STEP_2P50 0x50000000 +#define HAL_MDP_PHASE_STEP_1P66 0x35555555 +#define HAL_MDP_PHASE_STEP_1P25 0x28000000 + +struct phase_val { + int phase_init_x; + int phase_init_y; + int phase_step_x; + int phase_step_y; +}; + +static void mdp_calc_scaleInitPhase_3p1(uint32 in_w, + uint32 in_h, + uint32 out_w, + uint32 out_h, + boolean is_rotate, + boolean is_pp_x, + boolean is_pp_y, struct phase_val *pval) +{ + uint64 dst_ROI_width; + uint64 dst_ROI_height; + uint64 src_ROI_width; + uint64 src_ROI_height; + + /* + * phase_step_x, phase_step_y, phase_init_x and phase_init_y + * are represented in fixed-point, unsigned 3.29 format + */ + uint32 phase_step_x = 0; + uint32 phase_step_y = 0; + uint32 phase_init_x = 0; + uint32 phase_init_y = 0; + uint32 yscale_filter_sel, xscale_filter_sel; + uint32 scale_unit_sel_x, scale_unit_sel_y; + + uint64 numerator, denominator; + uint64 temp_dim; + + src_ROI_width = in_w; + src_ROI_height = in_h; + dst_ROI_width = out_w; + dst_ROI_height = out_h; + + /* if there is a 90 degree rotation */ + if (is_rotate) { + /* decide whether to use FIR or M/N for scaling */ + + /* if down-scaling by a factor smaller than 1/4 */ + if (src_ROI_width > (4 * dst_ROI_height)) + scale_unit_sel_x = 1; /* use M/N scalar */ + else + scale_unit_sel_x = 0; /* use FIR scalar */ + + /* if down-scaling by a factor smaller than 1/4 */ + if (src_ROI_height > (4 * dst_ROI_width)) + scale_unit_sel_y = 1; /* use M/N scalar */ + else + scale_unit_sel_y = 0; /* use FIR scalar */ + } else { + /* decide whether to use FIR or M/N for scaling */ + + if (src_ROI_width > (4 * dst_ROI_width)) + scale_unit_sel_x = 1; /* use M/N scalar */ + else + scale_unit_sel_x = 0; /* use FIR scalar */ + + if (src_ROI_height > (4 * dst_ROI_height)) + scale_unit_sel_y = 1; /* use M/N scalar */ + else + scale_unit_sel_y = 0; /* use FIR scalar */ + + } + + /* if there is a 90 degree rotation */ + if (is_rotate) { + /* swap the width and height of dst ROI */ + temp_dim = dst_ROI_width; + dst_ROI_width = dst_ROI_height; + dst_ROI_height = temp_dim; + } + + /* calculate phase step for the x direction */ + + /* if destination is only 1 pixel wide, the value of phase_step_x + is unimportant. Assigning phase_step_x to src ROI width + as an arbitrary value. */ + if (dst_ROI_width == 1) + phase_step_x = (uint32) ((src_ROI_width) << SCALER_PHASE_BITS); + + /* if using FIR scalar */ + else if (scale_unit_sel_x == 0) { + + /* Calculate the quotient ( src_ROI_width - 1 ) / ( dst_ROI_width - 1) + with u3.29 precision. Quotient is rounded up to the larger + 29th decimal point. */ + numerator = (src_ROI_width - 1) << SCALER_PHASE_BITS; + denominator = (dst_ROI_width - 1); /* never equals to 0 because of the "( dst_ROI_width == 1 ) case" */ + phase_step_x = (uint32) mdp_do_div((numerator + denominator - 1), denominator); /* divide and round up to the larger 29th decimal point. */ + + } + + /* if M/N scalar */ + else if (scale_unit_sel_x == 1) { + /* Calculate the quotient ( src_ROI_width ) / ( dst_ROI_width) + with u3.29 precision. Quotient is rounded down to the + smaller 29th decimal point. */ + numerator = (src_ROI_width) << SCALER_PHASE_BITS; + denominator = (dst_ROI_width); + phase_step_x = (uint32) mdp_do_div(numerator, denominator); + } + /* calculate phase step for the y direction */ + + /* if destination is only 1 pixel wide, the value of + phase_step_x is unimportant. Assigning phase_step_x + to src ROI width as an arbitrary value. */ + if (dst_ROI_height == 1) + phase_step_y = (uint32) ((src_ROI_height) << SCALER_PHASE_BITS); + + /* if FIR scalar */ + else if (scale_unit_sel_y == 0) { + /* Calculate the quotient ( src_ROI_height - 1 ) / ( dst_ROI_height - 1) + with u3.29 precision. Quotient is rounded up to the larger + 29th decimal point. */ + numerator = (src_ROI_height - 1) << SCALER_PHASE_BITS; + denominator = (dst_ROI_height - 1); /* never equals to 0 because of the "( dst_ROI_height == 1 )" case */ + phase_step_y = (uint32) mdp_do_div((numerator + denominator - 1), denominator); /* Quotient is rounded up to the larger 29th decimal point. */ + + } + + /* if M/N scalar */ + else if (scale_unit_sel_y == 1) { + /* Calculate the quotient ( src_ROI_height ) / ( dst_ROI_height) + with u3.29 precision. Quotient is rounded down to the smaller + 29th decimal point. */ + numerator = (src_ROI_height) << SCALER_PHASE_BITS; + denominator = (dst_ROI_height); + phase_step_y = (uint32) mdp_do_div(numerator, denominator); + } + + /* decide which set of FIR coefficients to use */ + if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) + xscale_filter_sel = 0; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) + xscale_filter_sel = 1; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) + xscale_filter_sel = 2; + else + xscale_filter_sel = 3; + + if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) + yscale_filter_sel = 0; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) + yscale_filter_sel = 1; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) + yscale_filter_sel = 2; + else + yscale_filter_sel = 3; + + /* calculate phase init for the x direction */ + + /* if using FIR scalar */ + if (scale_unit_sel_x == 0) { + if (dst_ROI_width == 1) + phase_init_x = + (uint32) ((src_ROI_width - 1) << SCALER_PHASE_BITS); + else + phase_init_x = 0; + + } + /* M over N scalar */ + else if (scale_unit_sel_x == 1) + phase_init_x = 0; + + /* calculate phase init for the y direction + if using FIR scalar */ + if (scale_unit_sel_y == 0) { + if (dst_ROI_height == 1) + phase_init_y = + (uint32) ((src_ROI_height - + 1) << SCALER_PHASE_BITS); + else + phase_init_y = 0; + + } + /* M over N scalar */ + else if (scale_unit_sel_y == 1) + phase_init_y = 0; + + /* write registers */ + pval->phase_step_x = (uint32) phase_step_x; + pval->phase_step_y = (uint32) phase_step_y; + pval->phase_init_x = (uint32) phase_init_x; + pval->phase_init_y = (uint32) phase_init_y; + + return; +} + +void mdp_set_scale(MDPIBUF *iBuf, + uint32 dst_roi_width, + uint32 dst_roi_height, + boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr) +{ + uint32 dst_roi_width_scale; + uint32 dst_roi_height_scale; + struct phase_val pval; + boolean use_pr; + uint32 ppp_scale_config = 0; + + if (!inputRGB) + ppp_scale_config |= BIT(6); + + if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) { + if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) { + dst_roi_width_scale = dst_roi_height; + dst_roi_height_scale = dst_roi_width; + } else { + dst_roi_width_scale = dst_roi_width; + dst_roi_height_scale = dst_roi_height; + } + + if ((dst_roi_width_scale != iBuf->roi.width) || + (dst_roi_height_scale != iBuf->roi.height) || + (iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) { + *pppop_reg_ptr |= + (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON); + + mdp_calc_scaleInitPhase_3p1(iBuf->roi.width, + iBuf->roi.height, + dst_roi_width, + dst_roi_height, + iBuf->mdpImg. + mdpOp & MDPOP_ROT90, 1, 1, + &pval); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c, + pval.phase_init_x); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140, + pval.phase_init_y); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0144, + pval.phase_step_x); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0148, + pval.phase_step_y); + + use_pr = (inputRGB) && (outputRGB); + + /* x-direction */ + if ((dst_roi_width_scale == iBuf->roi.width) && + !(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) { + *pppop_reg_ptr &= ~PPP_OP_SCALE_X_ON; + } else + if (((dst_roi_width_scale * 10) / iBuf->roi.width) > + 8) { + if ((use_pr) + && (mdp_scale_0p8_to_8p0_mode != + MDP_SCALE_PR)) { + mdp_scale_0p8_to_8p0_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P8_TO_8P0_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p8_to_8p0_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p8_to_8p0_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P8_TO_8P0_INDEX, + mdp_scale_0p8_to_8p0_C0, + mdp_scale_0p8_to_8p0_C1, + mdp_scale_0p8_to_8p0_C2, + mdp_scale_0p8_to_8p0_C3); + } + ppp_scale_config |= (SCALE_U1_SET << 2); + } else + if (((dst_roi_width_scale * 10) / iBuf->roi.width) > + 6) { + if ((use_pr) + && (mdp_scale_0p6_to_0p8_mode != + MDP_SCALE_PR)) { + mdp_scale_0p6_to_0p8_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P6_TO_0P8_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p6_to_0p8_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p6_to_0p8_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P6_TO_0P8_INDEX, + mdp_scale_0p6_to_0p8_C0, + mdp_scale_0p6_to_0p8_C1, + mdp_scale_0p6_to_0p8_C2, + mdp_scale_0p6_to_0p8_C3); + } + ppp_scale_config |= (SCALE_D2_SET << 2); + } else + if (((dst_roi_width_scale * 10) / iBuf->roi.width) > + 4) { + if ((use_pr) + && (mdp_scale_0p4_to_0p6_mode != + MDP_SCALE_PR)) { + mdp_scale_0p4_to_0p6_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P4_TO_0P6_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p4_to_0p6_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p4_to_0p6_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P4_TO_0P6_INDEX, + mdp_scale_0p4_to_0p6_C0, + mdp_scale_0p4_to_0p6_C1, + mdp_scale_0p4_to_0p6_C2, + mdp_scale_0p4_to_0p6_C3); + } + ppp_scale_config |= (SCALE_D1_SET << 2); + } else + if (((dst_roi_width_scale * 4) / iBuf->roi.width) >= + 1) { + if ((use_pr) + && (mdp_scale_0p2_to_0p4_mode != + MDP_SCALE_PR)) { + mdp_scale_0p2_to_0p4_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P2_TO_0P4_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p2_to_0p4_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p2_to_0p4_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P2_TO_0P4_INDEX, + mdp_scale_0p2_to_0p4_C0, + mdp_scale_0p2_to_0p4_C1, + mdp_scale_0p2_to_0p4_C2, + mdp_scale_0p2_to_0p4_C3); + } + ppp_scale_config |= (SCALE_D0_SET << 2); + } else + ppp_scale_config |= BIT(0); + + /* y-direction */ + if ((dst_roi_height_scale == iBuf->roi.height) && + !(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) { + *pppop_reg_ptr &= ~PPP_OP_SCALE_Y_ON; + } else if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 8) { + if ((use_pr) + && (mdp_scale_0p8_to_8p0_mode != + MDP_SCALE_PR)) { + mdp_scale_0p8_to_8p0_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P8_TO_8P0_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p8_to_8p0_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p8_to_8p0_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P8_TO_8P0_INDEX, + mdp_scale_0p8_to_8p0_C0, + mdp_scale_0p8_to_8p0_C1, + mdp_scale_0p8_to_8p0_C2, + mdp_scale_0p8_to_8p0_C3); + } + ppp_scale_config |= (SCALE_U1_SET << 4); + } else + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 6) { + if ((use_pr) + && (mdp_scale_0p6_to_0p8_mode != + MDP_SCALE_PR)) { + mdp_scale_0p6_to_0p8_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P6_TO_0P8_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p6_to_0p8_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p6_to_0p8_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P6_TO_0P8_INDEX, + mdp_scale_0p6_to_0p8_C0, + mdp_scale_0p6_to_0p8_C1, + mdp_scale_0p6_to_0p8_C2, + mdp_scale_0p6_to_0p8_C3); + } + ppp_scale_config |= (SCALE_D2_SET << 4); + } else + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 4) { + if ((use_pr) + && (mdp_scale_0p4_to_0p6_mode != + MDP_SCALE_PR)) { + mdp_scale_0p4_to_0p6_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P4_TO_0P6_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p4_to_0p6_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p4_to_0p6_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P4_TO_0P6_INDEX, + mdp_scale_0p4_to_0p6_C0, + mdp_scale_0p4_to_0p6_C1, + mdp_scale_0p4_to_0p6_C2, + mdp_scale_0p4_to_0p6_C3); + } + ppp_scale_config |= (SCALE_D1_SET << 4); + } else + if (((dst_roi_height_scale * 4) / + iBuf->roi.height) >= 1) { + if ((use_pr) + && (mdp_scale_0p2_to_0p4_mode != + MDP_SCALE_PR)) { + mdp_scale_0p2_to_0p4_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P2_TO_0P4_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p2_to_0p4_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p2_to_0p4_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P2_TO_0P4_INDEX, + mdp_scale_0p2_to_0p4_C0, + mdp_scale_0p2_to_0p4_C1, + mdp_scale_0p2_to_0p4_C2, + mdp_scale_0p2_to_0p4_C3); + } + ppp_scale_config |= (SCALE_D0_SET << 4); + } else + ppp_scale_config |= BIT(1); + + if (iBuf->mdpImg.mdpOp & MDPOP_SHARPENING) { + ppp_scale_config |= BIT(7); + MDP_OUTP(MDP_BASE + 0x50020, + iBuf->mdpImg.sp_value); + } + + MDP_OUTP(MDP_BASE + 0x10230, ppp_scale_config); + } else { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ASCALE); + } + } +} + +void mdp_adjust_start_addr(uint8 **src0, + uint8 **src1, + int v_slice, + int h_slice, + int x, + int y, + uint32 width, + uint32 height, int bpp, MDPIBUF *iBuf, int layer) +{ + switch (layer) { + case 0: + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0200, (y << 16) | (x)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0208, + (height << 16) | (width)); + break; + + case 1: + /* MDP 3.1 HW bug workaround */ + if (iBuf->ibuf_type == MDP_YCRYCB_H2V1) { + *src0 += (x + y * width) * bpp; + x = y = 0; + width = iBuf->roi.dst_width; + height = iBuf->roi.dst_height; + } + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0204, (y << 16) | (x)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x020c, + (height << 16) | (width)); + break; + + case 2: + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x019c, (y << 16) | (x)); + break; + } +} + +void mdp_set_blend_attr(MDPIBUF *iBuf, + uint32 *alpha, + uint32 *tpVal, + uint32 perPixelAlpha, uint32 *pppop_reg_ptr) +{ + int bg_alpha; + + *alpha = iBuf->mdpImg.alpha; + *tpVal = iBuf->mdpImg.tpVal; + + if (iBuf->mdpImg.mdpOp & MDPOP_FG_PM_ALPHA) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | PPP_OP_BLEND_CONSTANT_ALPHA; + + bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL | + PPP_BLEND_BG_ALPHA_REVERSE; + + if (perPixelAlpha) + bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA; + else + bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA; + + outpdw(MDP_BASE + 0x70010, bg_alpha); + + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) + *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP; + } else if (perPixelAlpha) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA; + } else { + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + && (iBuf->mdpImg.alpha == 0xff)) { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB); + } + + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + || (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) { + *pppop_reg_ptr |= + PPP_OP_ROT_ON | PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL; + } + + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) + *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP; + } +} diff --git a/drivers/staging/msm/mdp_vsync.c b/drivers/staging/msm/mdp_vsync.c new file mode 100644 index 000000000000..bbd456044356 --- /dev/null +++ b/drivers/staging/msm/mdp_vsync.c @@ -0,0 +1,389 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/vmalloc.h> +#include <linux/clk.h> + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <mach/gpio.h> + +#include "mdp.h" +#include "msm_fb.h" +#include "mddihost.h" + +#ifdef CONFIG_FB_MSM_MDP40 +#define MDP_SYNC_CFG_0 0x100 +#define MDP_SYNC_STATUS_0 0x10c +#define MDP_PRIM_VSYNC_OUT_CTRL 0x118 +#define MDP_PRIM_VSYNC_INIT_VAL 0x128 +#else +#define MDP_SYNC_CFG_0 0x300 +#define MDP_SYNC_STATUS_0 0x30c +#define MDP_PRIM_VSYNC_OUT_CTRL 0x318 +#define MDP_PRIM_VSYNC_INIT_VAL 0x328 +#endif + +extern mddi_lcd_type mddi_lcd_idx; +extern spinlock_t mdp_spin_lock; +extern struct workqueue_struct *mdp_vsync_wq; +extern int lcdc_mode; +extern int vsync_mode; + +#ifdef MDP_HW_VSYNC +int vsync_above_th = 4; +int vsync_start_th = 1; +int vsync_load_cnt; + +struct clk *mdp_vsync_clk; + +void mdp_hw_vsync_clk_enable(struct msm_fb_data_type *mfd) +{ + if (mfd->use_mdp_vsync) + clk_enable(mdp_vsync_clk); +} + +void mdp_hw_vsync_clk_disable(struct msm_fb_data_type *mfd) +{ + if (mfd->use_mdp_vsync) + clk_disable(mdp_vsync_clk); +} +#endif + +static void mdp_set_vsync(unsigned long data) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; + struct msm_fb_panel_data *pdata = NULL; + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + if ((pdata) && (pdata->set_vsync_notifier == NULL)) + return; + + init_timer(&mfd->vsync_resync_timer); + mfd->vsync_resync_timer.function = mdp_set_vsync; + mfd->vsync_resync_timer.data = data; + mfd->vsync_resync_timer.expires = + jiffies + mfd->panel_info.lcd.vsync_notifier_period; + add_timer(&mfd->vsync_resync_timer); + + if ((mfd->panel_info.lcd.vsync_enable) && (mfd->panel_power_on) + && (!mfd->vsync_handler_pending)) { + mfd->vsync_handler_pending = TRUE; + if (!queue_work(mdp_vsync_wq, &mfd->vsync_resync_worker)) { + MSM_FB_INFO + ("mdp_set_vsync: can't queue_work! -> needs to increase vsync_resync_timer_duration\n"); + } + } else { + MSM_FB_DEBUG + ("mdp_set_vsync failed! EN:%d PWR:%d PENDING:%d\n", + mfd->panel_info.lcd.vsync_enable, mfd->panel_power_on, + mfd->vsync_handler_pending); + } +} + +static void mdp_vsync_handler(void *data) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; + + if (mfd->use_mdp_vsync) { +#ifdef MDP_HW_VSYNC + if (mfd->panel_power_on) + MDP_OUTP(MDP_BASE + MDP_SYNC_STATUS_0, vsync_load_cnt); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); +#endif + } else { + mfd->last_vsync_timetick = ktime_get_real(); + } + + mfd->vsync_handler_pending = FALSE; +} + +irqreturn_t mdp_hw_vsync_handler_proxy(int irq, void *data) +{ + /* + * ToDo: tried enabling/disabling GPIO MDP HW VSYNC interrupt + * but getting inaccurate timing in mdp_vsync_handler() + * disable_irq(MDP_HW_VSYNC_IRQ); + */ + mdp_vsync_handler(data); + + return IRQ_HANDLED; +} + +#ifdef MDP_HW_VSYNC +static void mdp_set_sync_cfg_0(struct msm_fb_data_type *mfd, int vsync_cnt) +{ + unsigned long cfg; + + cfg = mfd->total_lcd_lines - 1; + cfg <<= MDP_SYNCFG_HGT_LOC; + if (mfd->panel_info.lcd.hw_vsync_mode) + cfg |= MDP_SYNCFG_VSYNC_EXT_EN; + cfg |= (MDP_SYNCFG_VSYNC_INT_EN | vsync_cnt); + + MDP_OUTP(MDP_BASE + MDP_SYNC_CFG_0, cfg); +} +#endif + +void mdp_config_vsync(struct msm_fb_data_type *mfd) +{ + + /* vsync on primary lcd only for now */ + if ((mfd->dest != DISPLAY_LCD) || (mfd->panel_info.pdest != DISPLAY_1) + || (!vsync_mode)) { + goto err_handle; + } + + if (mfd->panel_info.lcd.vsync_enable) { + mfd->total_porch_lines = mfd->panel_info.lcd.v_back_porch + + mfd->panel_info.lcd.v_front_porch + + mfd->panel_info.lcd.v_pulse_width; + mfd->total_lcd_lines = + mfd->panel_info.yres + mfd->total_porch_lines; + mfd->lcd_ref_usec_time = + 100000000 / mfd->panel_info.lcd.refx100; + mfd->vsync_handler_pending = FALSE; + mfd->last_vsync_timetick.tv.sec = 0; + mfd->last_vsync_timetick.tv.nsec = 0; + +#ifdef MDP_HW_VSYNC + if (mdp_vsync_clk == NULL) + mdp_vsync_clk = clk_get(NULL, "mdp_vsync_clk"); + + if (IS_ERR(mdp_vsync_clk)) { + printk(KERN_ERR "error: can't get mdp_vsync_clk!\n"); + mfd->use_mdp_vsync = 0; + } else + mfd->use_mdp_vsync = 1; + + if (mfd->use_mdp_vsync) { + uint32 vsync_cnt_cfg, vsync_cnt_cfg_dem; + uint32 mdp_vsync_clk_speed_hz; + + mdp_vsync_clk_speed_hz = clk_get_rate(mdp_vsync_clk); + + if (mdp_vsync_clk_speed_hz == 0) { + mfd->use_mdp_vsync = 0; + } else { + /* + * Do this calculation in 2 steps for + * rounding uint32 properly. + */ + vsync_cnt_cfg_dem = + (mfd->panel_info.lcd.refx100 * + mfd->total_lcd_lines) / 100; + vsync_cnt_cfg = + (mdp_vsync_clk_speed_hz) / + vsync_cnt_cfg_dem; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, + FALSE); + mdp_hw_vsync_clk_enable(mfd); + + mdp_set_sync_cfg_0(mfd, vsync_cnt_cfg); + + /* + * load the last line + 1 to be in the + * safety zone + */ + vsync_load_cnt = mfd->panel_info.yres; + + /* line counter init value at the next pulse */ + MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_INIT_VAL, + vsync_load_cnt); + + /* + * external vsync source pulse width and + * polarity flip + */ + MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_OUT_CTRL, + BIT(30) | BIT(0)); + + + /* threshold */ + MDP_OUTP(MDP_BASE + 0x200, + (vsync_above_th << 16) | + (vsync_start_th)); + + mdp_hw_vsync_clk_disable(mfd); + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, + MDP_BLOCK_POWER_OFF, FALSE); + } + } +#else + mfd->use_mdp_vsync = 0; + hrtimer_init(&mfd->dma_hrtimer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + mfd->dma_hrtimer.function = mdp_dma2_vsync_hrtimer_handler; + mfd->vsync_width_boundary = vmalloc(mfd->panel_info.xres * 4); +#endif + + mfd->channel_irq = 0; + if (mfd->panel_info.lcd.hw_vsync_mode) { + u32 vsync_gpio = mfd->vsync_gpio; + u32 ret; + + if (vsync_gpio == -1) { + MSM_FB_INFO("vsync_gpio not defined!\n"); + goto err_handle; + } + + ret = gpio_tlmm_config(GPIO_CFG + (vsync_gpio, + (mfd->use_mdp_vsync) ? 1 : 0, + GPIO_INPUT, + GPIO_PULL_DOWN, + GPIO_2MA), + GPIO_ENABLE); + if (ret) + goto err_handle; + + if (!mfd->use_mdp_vsync) { + mfd->channel_irq = MSM_GPIO_TO_INT(vsync_gpio); + if (request_irq + (mfd->channel_irq, + &mdp_hw_vsync_handler_proxy, + IRQF_TRIGGER_FALLING, "VSYNC_GPIO", + (void *)mfd)) { + MSM_FB_INFO + ("irq=%d failed! vsync_gpio=%d\n", + mfd->channel_irq, + vsync_gpio); + goto err_handle; + } + } + } + + mdp_set_vsync((unsigned long)mfd); + } + + return; + +err_handle: + if (mfd->vsync_width_boundary) + vfree(mfd->vsync_width_boundary); + mfd->panel_info.lcd.vsync_enable = FALSE; + printk(KERN_ERR "%s: failed!\n", __func__); +} + +void mdp_vsync_resync_workqueue_handler(struct work_struct *work) +{ + struct msm_fb_data_type *mfd = NULL; + int vsync_fnc_enabled = FALSE; + struct msm_fb_panel_data *pdata = NULL; + + mfd = container_of(work, struct msm_fb_data_type, vsync_resync_worker); + + if (mfd) { + if (mfd->panel_power_on) { + pdata = + (struct msm_fb_panel_data *)mfd->pdev->dev. + platform_data; + + /* + * we need to turn on MDP power if it uses MDP vsync + * HW block in SW mode + */ + if ((!mfd->panel_info.lcd.hw_vsync_mode) && + (mfd->use_mdp_vsync) && + (pdata) && (pdata->set_vsync_notifier != NULL)) { + /* + * enable pwr here since we can't enable it in + * vsync callback in isr mode + */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, + FALSE); + } + + if (pdata->set_vsync_notifier != NULL) { + vsync_fnc_enabled = TRUE; + pdata->set_vsync_notifier(mdp_vsync_handler, + (void *)mfd); + } + } + } + + if ((mfd) && (!vsync_fnc_enabled)) + mfd->vsync_handler_pending = FALSE; +} + +boolean mdp_hw_vsync_set_handler(msm_fb_vsync_handler_type handler, void *data) +{ + /* + * ToDo: tried enabling/disabling GPIO MDP HW VSYNC interrupt + * but getting inaccurate timing in mdp_vsync_handler() + * enable_irq(MDP_HW_VSYNC_IRQ); + */ + + return TRUE; +} + +uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd) +{ + uint32 elapsed_usec_time; + uint32 lcd_line; + ktime_t last_vsync_timetick_local; + ktime_t curr_time; + unsigned long flag; + + if ((!mfd->panel_info.lcd.vsync_enable) || (!vsync_mode)) + return 0; + + spin_lock_irqsave(&mdp_spin_lock, flag); + last_vsync_timetick_local = mfd->last_vsync_timetick; + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + curr_time = ktime_get_real(); + elapsed_usec_time = + ((curr_time.tv.sec - last_vsync_timetick_local.tv.sec) * 1000000) + + ((curr_time.tv.nsec - last_vsync_timetick_local.tv.nsec) / 1000); + + elapsed_usec_time = elapsed_usec_time % mfd->lcd_ref_usec_time; + + /* lcd line calculation referencing to line counter = 0 */ + lcd_line = + (elapsed_usec_time * mfd->total_lcd_lines) / mfd->lcd_ref_usec_time; + + /* lcd line adjusment referencing to the actual line counter at vsync */ + lcd_line = + (mfd->total_lcd_lines - mfd->panel_info.lcd.v_back_porch + + lcd_line) % (mfd->total_lcd_lines + 1); + + if (lcd_line > mfd->total_lcd_lines) { + MSM_FB_INFO + ("mdp_get_lcd_line_counter: mdp_lcd_rd_cnt >= mfd->total_lcd_lines error!\n"); + } + + return lcd_line; +} diff --git a/drivers/staging/msm/memory.c b/drivers/staging/msm/memory.c new file mode 100644 index 000000000000..cc80fdf17d61 --- /dev/null +++ b/drivers/staging/msm/memory.c @@ -0,0 +1,214 @@ +/* arch/arm/mach-msm/memory.c + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/mm.h> +#include <linux/mm_types.h> +#include <linux/bootmem.h> +#include <linux/module.h> +#include <asm/pgtable.h> +#include <asm/io.h> +#include <asm/mach/map.h> +#include "memory_ll.h" +#include <asm/cacheflush.h> +#if defined(CONFIG_MSM_NPA_REMOTE) +#include "npa_remote.h" +#include <linux/completion.h> +#include <linux/err.h> +#endif + +int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, + unsigned long pfn, unsigned long size, pgprot_t prot) +{ + unsigned long pfn_addr = pfn << PAGE_SHIFT; +/* + if ((pfn_addr >= 0x88000000) && (pfn_addr < 0xD0000000)) { + prot = pgprot_device(prot); + printk("remapping device %lx\n", prot); + } +*/ + panic("Memory remap PFN stuff not done\n"); + return remap_pfn_range(vma, addr, pfn, size, prot); +} + +void *zero_page_strongly_ordered; + +static void map_zero_page_strongly_ordered(void) +{ + if (zero_page_strongly_ordered) + return; +/* + zero_page_strongly_ordered = + ioremap_strongly_ordered(page_to_pfn(empty_zero_page) + << PAGE_SHIFT, PAGE_SIZE); +*/ + panic("Strongly ordered memory functions not implemented\n"); +} + +void write_to_strongly_ordered_memory(void) +{ + map_zero_page_strongly_ordered(); + *(int *)zero_page_strongly_ordered = 0; +} +EXPORT_SYMBOL(write_to_strongly_ordered_memory); + +void flush_axi_bus_buffer(void) +{ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \ + : : "r" (0) : "memory"); + write_to_strongly_ordered_memory(); +} + +#define CACHE_LINE_SIZE 32 + +/* These cache related routines make the assumption that the associated + * physical memory is contiguous. They will operate on all (L1 + * and L2 if present) caches. + */ +void clean_and_invalidate_caches(unsigned long vstart, + unsigned long length, unsigned long pstart) +{ + unsigned long vaddr; + + for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE) + asm ("mcr p15, 0, %0, c7, c14, 1" : : "r" (vaddr)); +#ifdef CONFIG_OUTER_CACHE + outer_flush_range(pstart, pstart + length); +#endif + asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0)); + asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0)); + + flush_axi_bus_buffer(); +} + +void clean_caches(unsigned long vstart, + unsigned long length, unsigned long pstart) +{ + unsigned long vaddr; + + for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE) + asm ("mcr p15, 0, %0, c7, c10, 1" : : "r" (vaddr)); +#ifdef CONFIG_OUTER_CACHE + outer_clean_range(pstart, pstart + length); +#endif + asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0)); + asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0)); + + flush_axi_bus_buffer(); +} + +void invalidate_caches(unsigned long vstart, + unsigned long length, unsigned long pstart) +{ + unsigned long vaddr; + + for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE) + asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (vaddr)); +#ifdef CONFIG_OUTER_CACHE + outer_inv_range(pstart, pstart + length); +#endif + asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0)); + asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0)); + + flush_axi_bus_buffer(); +} + +void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment) +{ + void *unused_addr = NULL; + unsigned long addr, tmp_size, unused_size; + + /* Allocate maximum size needed, see where it ends up. + * Then free it -- in this path there are no other allocators + * so we can depend on getting the same address back + * when we allocate a smaller piece that is aligned + * at the end (if necessary) and the piece we really want, + * then free the unused first piece. + */ + + tmp_size = size + alignment - PAGE_SIZE; + addr = (unsigned long)alloc_bootmem(tmp_size); + free_bootmem(__pa(addr), tmp_size); + + unused_size = alignment - (addr % alignment); + if (unused_size) + unused_addr = alloc_bootmem(unused_size); + + addr = (unsigned long)alloc_bootmem(size); + if (unused_size) + free_bootmem(__pa(unused_addr), unused_size); + + return (void *)addr; +} + +#if defined(CONFIG_MSM_NPA_REMOTE) +struct npa_client *npa_memory_client; +#endif + +static int change_memory_power_state(unsigned long start_pfn, + unsigned long nr_pages, int state) +{ +#if defined(CONFIG_MSM_NPA_REMOTE) + static atomic_t node_created_flag = ATOMIC_INIT(1); +#else + unsigned long start; + unsigned long size; + unsigned long virtual; +#endif + int rc = 0; + +#if defined(CONFIG_MSM_NPA_REMOTE) + if (atomic_dec_and_test(&node_created_flag)) { + /* Create NPA 'required' client. */ + npa_memory_client = npa_create_sync_client(NPA_MEMORY_NODE_NAME, + "memory node", NPA_CLIENT_REQUIRED); + if (IS_ERR(npa_memory_client)) { + rc = PTR_ERR(npa_memory_client); + return rc; + } + } + + rc = npa_issue_required_request(npa_memory_client, state); +#else + if (state == MEMORY_DEEP_POWERDOWN) { + /* simulate turning off memory by writing bit pattern into it */ + start = start_pfn << PAGE_SHIFT; + size = nr_pages << PAGE_SHIFT; + virtual = __phys_to_virt(start); + memset((void *)virtual, 0x27, size); + } +#endif + return rc; +} + +int platform_physical_remove_pages(unsigned long start_pfn, + unsigned long nr_pages) +{ + return change_memory_power_state(start_pfn, nr_pages, + MEMORY_DEEP_POWERDOWN); +} + +int platform_physical_add_pages(unsigned long start_pfn, + unsigned long nr_pages) +{ + return change_memory_power_state(start_pfn, nr_pages, MEMORY_ACTIVE); +} + +int platform_physical_low_power_pages(unsigned long start_pfn, + unsigned long nr_pages) +{ + return change_memory_power_state(start_pfn, nr_pages, + MEMORY_SELF_REFRESH); +} diff --git a/drivers/staging/msm/memory_ll.h b/drivers/staging/msm/memory_ll.h new file mode 100644 index 000000000000..18a239a89a78 --- /dev/null +++ b/drivers/staging/msm/memory_ll.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __ASM_ARCH_MEMORY_LL_H +#define __ASM_ARCH_MEMORY_LL_H + +#define MAX_PHYSMEM_BITS 32 +#define SECTION_SIZE_BITS 25 + +#define HAS_ARCH_IO_REMAP_PFN_RANGE + +#ifndef __ASSEMBLY__ +void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment); +void clean_and_invalidate_caches(unsigned long, unsigned long, unsigned long); +void clean_caches(unsigned long, unsigned long, unsigned long); +void invalidate_caches(unsigned long, unsigned long, unsigned long); +int platform_physical_remove_pages(unsigned long, unsigned long); +int platform_physical_add_pages(unsigned long, unsigned long); +int platform_physical_low_power_pages(unsigned long, unsigned long); + +#ifdef CONFIG_ARCH_MSM_ARM11 +void write_to_strongly_ordered_memory(void); + +#include <asm/mach-types.h> + +#define arch_barrier_extra() do \ + { if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) \ + write_to_strongly_ordered_memory(); \ + } while (0) +#endif + +#ifdef CONFIG_CACHE_L2X0 +extern void l2x0_cache_sync(void); +#define finish_arch_switch(prev) do { l2x0_cache_sync(); } while (0) +#endif + +#endif + +#ifdef CONFIG_ARCH_MSM_SCORPION +#define arch_has_speculative_dfetch() 1 +#endif + +#endif + +/* these correspond to values known by the modem */ +#define MEMORY_DEEP_POWERDOWN 0 +#define MEMORY_SELF_REFRESH 1 +#define MEMORY_ACTIVE 2 + +#define NPA_MEMORY_NODE_NAME "/mem/ebi1/cs1" diff --git a/drivers/staging/msm/msm_fb.c b/drivers/staging/msm/msm_fb.c new file mode 100644 index 000000000000..af5620e4eee1 --- /dev/null +++ b/drivers/staging/msm/msm_fb.c @@ -0,0 +1,2354 @@ +/* + * + * Core MSM framebuffer driver. + * + * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/fb.h> +#include "msm_mdp.h" +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <mach/board.h> +#include <linux/uaccess.h> + +#include <linux/workqueue.h> +#include <linux/string.h> +#include <linux/version.h> +#include <linux/proc_fs.h> +#include <linux/vmalloc.h> +#include <linux/debugfs.h> +#include <linux/console.h> +#include <linux/leds.h> +#include <asm/dma-mapping.h> + + +#define MSM_FB_C +#include "msm_fb.h" +#include "mddihosti.h" +#include "tvenc.h" +#include "mdp.h" +#include "mdp4.h" + +#ifdef CONFIG_FB_MSM_LOGO +#define INIT_IMAGE_FILE "/logo.rle" +extern int load_565rle_image(char *filename); +#endif + + +#define pgprot_noncached(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED) +#define pgprot_writecombine(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE) +#define pgprot_device(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_DEV_NONSHARED) +#define pgprot_writethroughcache(prot) \ + __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITETHROUGH) +#define pgprot_writebackcache(prot) \ + __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITEBACK) +#define pgprot_writebackwacache(prot) \ + __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITEALLOC) + +static unsigned char *fbram; +static unsigned char *fbram_phys; +static int fbram_size; + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +int vsync_mode = 1; + +#define MAX_FBI_LIST 32 +static struct fb_info *fbi_list[MAX_FBI_LIST]; +static int fbi_list_index; + +static struct msm_fb_data_type *mfd_list[MAX_FBI_LIST]; +static int mfd_list_index; + +static u32 msm_fb_pseudo_palette[16] = { + 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff +}; + +u32 msm_fb_debug_enabled; +/* Setting msm_fb_msg_level to 8 prints out ALL messages */ +u32 msm_fb_msg_level = 7; + +/* Setting mddi_msg_level to 8 prints out ALL messages */ +u32 mddi_msg_level = 5; + +extern int32 mdp_block_power_cnt[MDP_MAX_BLOCK]; +extern unsigned long mdp_timer_duration; + +static int msm_fb_register(struct msm_fb_data_type *mfd); +static int msm_fb_open(struct fb_info *info, int user); +static int msm_fb_release(struct fb_info *info, int user); +static int msm_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd); +int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd); +static int msm_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int msm_fb_set_par(struct fb_info *info); +static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, + boolean op_enable); +static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd); +static int msm_fb_resume_sub(struct msm_fb_data_type *mfd); +static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg); +static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma); + +#ifdef MSM_FB_ENABLE_DBGFS + +#define MSM_FB_MAX_DBGFS 1024 +#define MAX_BACKLIGHT_BRIGHTNESS 255 + +int msm_fb_debugfs_file_index; +struct dentry *msm_fb_debugfs_root; +struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS]; + +struct dentry *msm_fb_get_debugfs_root(void) +{ + if (msm_fb_debugfs_root == NULL) + msm_fb_debugfs_root = debugfs_create_dir("msm_fb", NULL); + + return msm_fb_debugfs_root; +} + +void msm_fb_debugfs_file_create(struct dentry *root, const char *name, + u32 *var) +{ + if (msm_fb_debugfs_file_index >= MSM_FB_MAX_DBGFS) + return; + + msm_fb_debugfs_file[msm_fb_debugfs_file_index++] = + debugfs_create_u32(name, S_IRUGO | S_IWUSR, root, var); +} +#endif + +int msm_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (!mfd->cursor_update) + return -ENODEV; + + return mfd->cursor_update(info, cursor); +} + +static int msm_fb_resource_initialized; + +#ifndef CONFIG_FB_BACKLIGHT +static int lcd_backlight_registered; + +static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent); + int bl_lvl; + + if (value > MAX_BACKLIGHT_BRIGHTNESS) + value = MAX_BACKLIGHT_BRIGHTNESS; + + /* This maps android backlight level 0 to 255 into + driver backlight level 0 to bl_max with rounding */ + bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS) + /(2 * MAX_BACKLIGHT_BRIGHTNESS); + + if (!bl_lvl && value) + bl_lvl = 1; + + msm_fb_set_backlight(mfd, bl_lvl, 1); +} + +static struct led_classdev backlight_led = { + .name = "lcd-backlight", + .brightness = MAX_BACKLIGHT_BRIGHTNESS, + .brightness_set = msm_fb_set_bl_brightness, +}; +#endif + +static struct msm_fb_platform_data *msm_fb_pdata; + +int msm_fb_detect_client(const char *name) +{ + int ret = -EPERM; +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; +#endif + + if (msm_fb_pdata && msm_fb_pdata->detect_client) { + ret = msm_fb_pdata->detect_client(name); + + /* if it's non mddi panel, we need to pre-scan + mddi client to see if we can disable mddi host */ + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + if (!ret && msm_fb_pdata->mddi_prescan) + id = mddi_get_client_id(); +#endif + } + + return ret; +} + +static int msm_fb_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + int rc; + + MSM_FB_DEBUG("msm_fb_probe\n"); + + if ((pdev->id == 0) && (pdev->num_resources > 0)) { + msm_fb_pdata = pdev->dev.platform_data; + fbram_size = + pdev->resource[0].end - pdev->resource[0].start + 1; + fbram_phys = (char *)pdev->resource[0].start; + fbram = ioremap((unsigned long)fbram_phys, fbram_size); + + if (!fbram) { + printk(KERN_ERR "fbram ioremap failed!\n"); + return -ENOMEM; + } + MSM_FB_INFO("msm_fb_probe: phy_Addr = 0x%x virt = 0x%x\n", + (int)fbram_phys, (int)fbram); + + msm_fb_resource_initialized = 1; + return 0; + } + + if (!msm_fb_resource_initialized) + return -EPERM; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + mfd->panel_info.frame_count = 0; + mfd->bl_level = mfd->panel_info.bl_max; + + if (mfd->panel_info.type == LCDC_PANEL) + mfd->allow_set_offset = + msm_fb_pdata->allow_set_offset != NULL ? + msm_fb_pdata->allow_set_offset() : 0; + else + mfd->allow_set_offset = 0; + + rc = msm_fb_register(mfd); + if (rc) + return rc; + +#ifdef CONFIG_FB_BACKLIGHT + msm_fb_config_backlight(mfd); +#else + /* android supports only one lcd-backlight/lcd for now */ + if (!lcd_backlight_registered) { + if (led_classdev_register(&pdev->dev, &backlight_led)) + printk(KERN_ERR "led_classdev_register failed\n"); + else + lcd_backlight_registered = 1; + } +#endif + + pdev_list[pdev_list_cnt++] = pdev; + return 0; +} + +static int msm_fb_remove(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + MSM_FB_DEBUG("msm_fb_remove\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (msm_fb_suspend_sub(mfd)) + printk(KERN_ERR "msm_fb_remove: can't stop the device %d\n", mfd->index); + + if (mfd->channel_irq != 0) + free_irq(mfd->channel_irq, (void *)mfd); + + if (mfd->vsync_width_boundary) + vfree(mfd->vsync_width_boundary); + + if (mfd->vsync_resync_timer.function) + del_timer(&mfd->vsync_resync_timer); + + if (mfd->refresh_timer.function) + del_timer(&mfd->refresh_timer); + + if (mfd->dma_hrtimer.function) + hrtimer_cancel(&mfd->dma_hrtimer); + + /* remove /dev/fb* */ + unregister_framebuffer(mfd->fbi); + +#ifdef CONFIG_FB_BACKLIGHT + /* remove /sys/class/backlight */ + backlight_device_unregister(mfd->fbi->bl_dev); +#else + if (lcd_backlight_registered) { + lcd_backlight_registered = 0; + led_classdev_unregister(&backlight_led); + } +#endif + +#ifdef MSM_FB_ENABLE_DBGFS + if (mfd->sub_dir) + debugfs_remove(mfd->sub_dir); +#endif + + return 0; +} + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct msm_fb_data_type *mfd; + int ret = 0; + + MSM_FB_DEBUG("msm_fb_suspend\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + acquire_console_sem(); + fb_set_suspend(mfd->fbi, 1); + + ret = msm_fb_suspend_sub(mfd); + if (ret != 0) { + printk(KERN_ERR "msm_fb: failed to suspend! %d\n", ret); + fb_set_suspend(mfd->fbi, 0); + } else { + pdev->dev.power.power_state = state; + } + + release_console_sem(); + return ret; +} +#else +#define msm_fb_suspend NULL +#endif + +static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd) +{ + int ret = 0; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + /* + * suspend this channel + */ + mfd->suspend.sw_refreshing_enable = mfd->sw_refreshing_enable; + mfd->suspend.op_enable = mfd->op_enable; + mfd->suspend.panel_power_on = mfd->panel_power_on; + + if (mfd->op_enable) { + ret = + msm_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi, + mfd->suspend.op_enable); + if (ret) { + MSM_FB_INFO + ("msm_fb_suspend: can't turn off display!\n"); + return ret; + } + mfd->op_enable = FALSE; + } + /* + * try to power down + */ + mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + /* + * detach display channel irq if there's any + * or wait until vsync-resync completes + */ + if ((mfd->dest == DISPLAY_LCD)) { + if (mfd->panel_info.lcd.vsync_enable) { + if (mfd->panel_info.lcd.hw_vsync_mode) { + if (mfd->channel_irq != 0) + disable_irq(mfd->channel_irq); + } else { + volatile boolean vh_pending; + do { + vh_pending = mfd->vsync_handler_pending; + } while (vh_pending); + } + } + } + + return 0; +} + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int msm_fb_resume(struct platform_device *pdev) +{ + /* This resume function is called when interrupt is enabled. + */ + int ret = 0; + struct msm_fb_data_type *mfd; + + MSM_FB_DEBUG("msm_fb_resume\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + acquire_console_sem(); + ret = msm_fb_resume_sub(mfd); + pdev->dev.power.power_state = PMSG_ON; + fb_set_suspend(mfd->fbi, 1); + release_console_sem(); + + return ret; +} +#else +#define msm_fb_resume NULL +#endif + +static int msm_fb_resume_sub(struct msm_fb_data_type *mfd) +{ + int ret = 0; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + /* attach display channel irq if there's any */ + if (mfd->channel_irq != 0) + enable_irq(mfd->channel_irq); + + /* resume state var recover */ + mfd->sw_refreshing_enable = mfd->suspend.sw_refreshing_enable; + mfd->op_enable = mfd->suspend.op_enable; + + if (mfd->suspend.panel_power_on) { + ret = + msm_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi, + mfd->op_enable); + if (ret) + MSM_FB_INFO("msm_fb_resume: can't turn on display!\n"); + } + + return ret; +} + +static struct platform_driver msm_fb_driver = { + .probe = msm_fb_probe, + .remove = msm_fb_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = msm_fb_suspend, + .resume = msm_fb_resume, +#endif + .shutdown = NULL, + .driver = { + /* Driver name must match the device name added in platform.c. */ + .name = "msm_fb", + }, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void msmfb_early_suspend(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + early_suspend); + msm_fb_suspend_sub(mfd); +} + +static void msmfb_early_resume(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + early_suspend); + msm_fb_resume_sub(mfd); +} +#endif + +void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl, u32 save) +{ + struct msm_fb_panel_data *pdata; + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + if ((pdata) && (pdata->set_backlight)) { + down(&mfd->sem); + if ((bkl_lvl != mfd->bl_level) || (!save)) { + u32 old_lvl; + + old_lvl = mfd->bl_level; + mfd->bl_level = bkl_lvl; + pdata->set_backlight(mfd); + + if (!save) + mfd->bl_level = old_lvl; + } + up(&mfd->sem); + } +} + +static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, + boolean op_enable) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msm_fb_panel_data *pdata = NULL; + int ret = 0; + + if (!op_enable) + return -EPERM; + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + if ((!pdata) || (!pdata->on) || (!pdata->off)) { + printk(KERN_ERR "msm_fb_blank_sub: no panel operation detected!\n"); + return -ENODEV; + } + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + if (!mfd->panel_power_on) { + mdelay(100); + ret = pdata->on(mfd->pdev); + if (ret == 0) { + mfd->panel_power_on = TRUE; + + msm_fb_set_backlight(mfd, + mfd->bl_level, 0); + +/* ToDo: possible conflict with android which doesn't expect sw refresher */ +/* + if (!mfd->hw_refresh) + { + if ((ret = msm_fb_resume_sw_refresher(mfd)) != 0) + { + MSM_FB_INFO("msm_fb_blank_sub: msm_fb_resume_sw_refresher failed = %d!\n",ret); + } + } +*/ + } + } + break; + + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + case FB_BLANK_POWERDOWN: + default: + if (mfd->panel_power_on) { + int curr_pwr_state; + + mfd->op_enable = FALSE; + curr_pwr_state = mfd->panel_power_on; + mfd->panel_power_on = FALSE; + + mdelay(100); + ret = pdata->off(mfd->pdev); + if (ret) + mfd->panel_power_on = curr_pwr_state; + + msm_fb_set_backlight(mfd, 0, 0); + mfd->op_enable = TRUE; + } + break; + } + + return ret; +} + +static void msm_fb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + cfb_fillrect(info, rect); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (rect->dy << 16) | (rect->dx); + var.reserved[2] = ((rect->dy + rect->height) << 16) | + (rect->dx + rect->width); + + msm_fb_pan_display(&var, info); + } +} + +static void msm_fb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + cfb_copyarea(info, area); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (area->dy << 16) | (area->dx); + var.reserved[2] = ((area->dy + area->height) << 16) | + (area->dx + area->width); + + msm_fb_pan_display(&var, info); + } +} + +static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + cfb_imageblit(info, image); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (image->dy << 16) | (image->dx); + var.reserved[2] = ((image->dy + image->height) << 16) | + (image->dx + image->width); + + msm_fb_pan_display(&var, info); + } +} + +static int msm_fb_blank(int blank_mode, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + return msm_fb_blank_sub(blank_mode, info, mfd->op_enable); +} + +static int msm_fb_set_lut(struct fb_cmap *cmap, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (!mfd->lut_update) + return -ENODEV; + + mfd->lut_update(info, cmap); + return 0; +} + +/* + * Custom Framebuffer mmap() function for MSM driver. + * Differs from standard mmap() function by allowing for customized + * page-protection. + */ +static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma) +{ + /* Get frame buffer memory range. */ + unsigned long start = info->fix.smem_start; + u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); + unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + if (off >= len) { + /* memory mapped io */ + off -= len; + if (info->var.accel_flags) { + mutex_unlock(&info->lock); + return -EINVAL; + } + start = info->fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); + } + + /* Set VM flags. */ + start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + /* This is an IO map - tell maydump to skip this VMA */ + vma->vm_flags |= VM_IO | VM_RESERVED; + + /* Set VM page protection */ + if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE) + vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE) + vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE) + vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* Remap the frame buffer I/O range */ + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +static struct fb_ops msm_fb_ops = { + .owner = THIS_MODULE, + .fb_open = msm_fb_open, + .fb_release = msm_fb_release, + .fb_read = NULL, + .fb_write = NULL, + .fb_cursor = NULL, + .fb_check_var = msm_fb_check_var, /* vinfo check */ + .fb_set_par = msm_fb_set_par, /* set the video mode according to info->var */ + .fb_setcolreg = NULL, /* set color register */ + .fb_blank = msm_fb_blank, /* blank display */ + .fb_pan_display = msm_fb_pan_display, /* pan display */ + .fb_fillrect = msm_fb_fillrect, /* Draws a rectangle */ + .fb_copyarea = msm_fb_copyarea, /* Copy data from area to another */ + .fb_imageblit = msm_fb_imageblit, /* Draws a image to the display */ + .fb_rotate = NULL, + .fb_sync = NULL, /* wait for blit idle, optional */ + .fb_ioctl = msm_fb_ioctl, /* perform fb specific ioctl (optional) */ + .fb_mmap = msm_fb_mmap, +}; + +static int msm_fb_register(struct msm_fb_data_type *mfd) +{ + int ret = -ENODEV; + int bpp; + struct msm_panel_info *panel_info = &mfd->panel_info; + struct fb_info *fbi = mfd->fbi; + struct fb_fix_screeninfo *fix; + struct fb_var_screeninfo *var; + int *id; + int fbram_offset; + + /* + * fb info initialization + */ + fix = &fbi->fix; + var = &fbi->var; + + fix->type_aux = 0; /* if type == FB_TYPE_INTERLEAVED_PLANES */ + fix->visual = FB_VISUAL_TRUECOLOR; /* True Color */ + fix->ywrapstep = 0; /* No support */ + fix->mmio_start = 0; /* No MMIO Address */ + fix->mmio_len = 0; /* No MMIO Address */ + fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */ + + var->xoffset = 0, /* Offset from virtual to visible */ + var->yoffset = 0, /* resolution */ + var->grayscale = 0, /* No graylevels */ + var->nonstd = 0, /* standard pixel format */ + var->activate = FB_ACTIVATE_VBL, /* activate it at vsync */ + var->height = -1, /* height of picture in mm */ + var->width = -1, /* width of picture in mm */ + var->accel_flags = 0, /* acceleration flags */ + var->sync = 0, /* see FB_SYNC_* */ + var->rotate = 0, /* angle we rotate counter clockwise */ + mfd->op_enable = FALSE; + + switch (mfd->fb_imgType) { + case MDP_RGB_565: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 11; + var->blue.length = 5; + var->green.length = 6; + var->red.length = 5; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 2; + break; + + case MDP_RGB_888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 3; + break; + + case MDP_ARGB_8888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 24; + var->transp.length = 8; + bpp = 3; + break; + + case MDP_YCRYCB_H2V1: + /* ToDo: need to check TV-Out YUV422i framebuffer format */ + /* we might need to create new type define */ + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->xpanstep = 2; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + /* how about R/G/B offset? */ + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 11; + var->blue.length = 5; + var->green.length = 6; + var->red.length = 5; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 2; + break; + + default: + MSM_FB_ERR("msm_fb_init: fb %d unkown image type!\n", + mfd->index); + return ret; + } + + /* The adreno GPU hardware requires that the pitch be aligned to + 32 pixels for color buffers, so for the cases where the GPU + is writing directly to fb0, the framebuffer pitch + also needs to be 32 pixel aligned */ + + if (mfd->index == 0) + fix->line_length = ALIGN(panel_info->xres * bpp, 32); + else + fix->line_length = panel_info->xres * bpp; + + fix->smem_len = fix->line_length * panel_info->yres * mfd->fb_page; + + mfd->var_xres = panel_info->xres; + mfd->var_yres = panel_info->yres; + + var->pixclock = mfd->panel_info.clk_rate; + mfd->var_pixclock = var->pixclock; + + var->xres = panel_info->xres; + var->yres = panel_info->yres; + var->xres_virtual = panel_info->xres; + var->yres_virtual = panel_info->yres * mfd->fb_page; + var->bits_per_pixel = bpp * 8, /* FrameBuffer color depth */ + /* + * id field for fb app + */ + id = (int *)&mfd->panel; + +#if defined(CONFIG_FB_MSM_MDP22) + snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id); +#elif defined(CONFIG_FB_MSM_MDP30) + snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id); +#elif defined(CONFIG_FB_MSM_MDP31) + snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id); +#elif defined(CONFIG_FB_MSM_MDP40) + snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id); +#else + error CONFIG_FB_MSM_MDP undefined ! +#endif + fbi->fbops = &msm_fb_ops; + fbi->flags = FBINFO_FLAG_DEFAULT; + fbi->pseudo_palette = msm_fb_pseudo_palette; + + mfd->ref_cnt = 0; + mfd->sw_currently_refreshing = FALSE; + mfd->sw_refreshing_enable = TRUE; + mfd->panel_power_on = FALSE; + + mfd->pan_waiting = FALSE; + init_completion(&mfd->pan_comp); + init_completion(&mfd->refresher_comp); + init_MUTEX(&mfd->sem); + + fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram; + fbram += fbram_offset; + fbram_phys += fbram_offset; + fbram_size -= fbram_offset; + + if (fbram_size < fix->smem_len) { + printk(KERN_ERR "error: no more framebuffer memory!\n"); + return -ENOMEM; + } + + fbi->screen_base = fbram; + fbi->fix.smem_start = (unsigned long)fbram_phys; + + memset(fbi->screen_base, 0x0, fix->smem_len); + + mfd->op_enable = TRUE; + mfd->panel_power_on = FALSE; + + /* cursor memory allocation */ + if (mfd->cursor_update) { + mfd->cursor_buf = dma_alloc_coherent(NULL, + MDP_CURSOR_SIZE, + (dma_addr_t *) &mfd->cursor_buf_phys, + GFP_KERNEL); + if (!mfd->cursor_buf) + mfd->cursor_update = 0; + } + + if (mfd->lut_update) { + ret = fb_alloc_cmap(&fbi->cmap, 256, 0); + if (ret) + printk(KERN_ERR "%s: fb_alloc_cmap() failed!\n", + __func__); + } + + if (register_framebuffer(fbi) < 0) { + if (mfd->lut_update) + fb_dealloc_cmap(&fbi->cmap); + + if (mfd->cursor_buf) + dma_free_coherent(NULL, + MDP_CURSOR_SIZE, + mfd->cursor_buf, + (dma_addr_t) mfd->cursor_buf_phys); + + mfd->op_enable = FALSE; + return -EPERM; + } + + fbram += fix->smem_len; + fbram_phys += fix->smem_len; + fbram_size -= fix->smem_len; + + MSM_FB_INFO + ("FrameBuffer[%d] %dx%d size=%d bytes is registered successfully!\n", + mfd->index, fbi->var.xres, fbi->var.yres, fbi->fix.smem_len); + +#ifdef CONFIG_FB_MSM_LOGO + if (!load_565rle_image(INIT_IMAGE_FILE)) ; /* Flip buffer */ +#endif + ret = 0; + +#ifdef CONFIG_HAS_EARLYSUSPEND + mfd->early_suspend.suspend = msmfb_early_suspend; + mfd->early_suspend.resume = msmfb_early_resume; + mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2; + register_early_suspend(&mfd->early_suspend); +#endif + +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + struct dentry *sub_dir; + char sub_name[2]; + + root = msm_fb_get_debugfs_root(); + if (root != NULL) { + sub_name[0] = (char)(mfd->index + 0x30); + sub_name[1] = '\0'; + sub_dir = debugfs_create_dir(sub_name, root); + } else { + sub_dir = NULL; + } + + mfd->sub_dir = sub_dir; + + if (sub_dir) { + msm_fb_debugfs_file_create(sub_dir, "op_enable", + (u32 *) &mfd->op_enable); + msm_fb_debugfs_file_create(sub_dir, "panel_power_on", + (u32 *) &mfd-> + panel_power_on); + msm_fb_debugfs_file_create(sub_dir, "ref_cnt", + (u32 *) &mfd->ref_cnt); + msm_fb_debugfs_file_create(sub_dir, "fb_imgType", + (u32 *) &mfd->fb_imgType); + msm_fb_debugfs_file_create(sub_dir, + "sw_currently_refreshing", + (u32 *) &mfd-> + sw_currently_refreshing); + msm_fb_debugfs_file_create(sub_dir, + "sw_refreshing_enable", + (u32 *) &mfd-> + sw_refreshing_enable); + + msm_fb_debugfs_file_create(sub_dir, "xres", + (u32 *) &mfd->panel_info. + xres); + msm_fb_debugfs_file_create(sub_dir, "yres", + (u32 *) &mfd->panel_info. + yres); + msm_fb_debugfs_file_create(sub_dir, "bpp", + (u32 *) &mfd->panel_info. + bpp); + msm_fb_debugfs_file_create(sub_dir, "type", + (u32 *) &mfd->panel_info. + type); + msm_fb_debugfs_file_create(sub_dir, "wait_cycle", + (u32 *) &mfd->panel_info. + wait_cycle); + msm_fb_debugfs_file_create(sub_dir, "pdest", + (u32 *) &mfd->panel_info. + pdest); + msm_fb_debugfs_file_create(sub_dir, "backbuff", + (u32 *) &mfd->panel_info. + fb_num); + msm_fb_debugfs_file_create(sub_dir, "clk_rate", + (u32 *) &mfd->panel_info. + clk_rate); + msm_fb_debugfs_file_create(sub_dir, "frame_count", + (u32 *) &mfd->panel_info. + frame_count); + + + switch (mfd->dest) { + case DISPLAY_LCD: + msm_fb_debugfs_file_create(sub_dir, + "vsync_enable", + (u32 *)&mfd->panel_info.lcd.vsync_enable); + msm_fb_debugfs_file_create(sub_dir, + "refx100", + (u32 *) &mfd->panel_info.lcd. refx100); + msm_fb_debugfs_file_create(sub_dir, + "v_back_porch", + (u32 *) &mfd->panel_info.lcd.v_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_front_porch", + (u32 *) &mfd->panel_info.lcd.v_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_pulse_width", + (u32 *) &mfd->panel_info.lcd.v_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "hw_vsync_mode", + (u32 *) &mfd->panel_info.lcd.hw_vsync_mode); + msm_fb_debugfs_file_create(sub_dir, + "vsync_notifier_period", (u32 *) + &mfd->panel_info.lcd.vsync_notifier_period); + break; + + case DISPLAY_LCDC: + msm_fb_debugfs_file_create(sub_dir, + "h_back_porch", + (u32 *) &mfd->panel_info.lcdc.h_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "h_front_porch", + (u32 *) &mfd->panel_info.lcdc.h_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "h_pulse_width", + (u32 *) &mfd->panel_info.lcdc.h_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "v_back_porch", + (u32 *) &mfd->panel_info.lcdc.v_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_front_porch", + (u32 *) &mfd->panel_info.lcdc.v_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_pulse_width", + (u32 *) &mfd->panel_info.lcdc.v_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "border_clr", + (u32 *) &mfd->panel_info.lcdc.border_clr); + msm_fb_debugfs_file_create(sub_dir, + "underflow_clr", + (u32 *) &mfd->panel_info.lcdc.underflow_clr); + msm_fb_debugfs_file_create(sub_dir, + "hsync_skew", + (u32 *) &mfd->panel_info.lcdc.hsync_skew); + break; + + default: + break; + } + } + } +#endif /* MSM_FB_ENABLE_DBGFS */ + + return ret; +} + +static int msm_fb_open(struct fb_info *info, int user) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (!mfd->ref_cnt) { + mdp_set_dma_pan_info(info, NULL, TRUE); + + if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { + printk(KERN_ERR "msm_fb_open: can't turn on display!\n"); + return -1; + } + } + + mfd->ref_cnt++; + return 0; +} + +static int msm_fb_release(struct fb_info *info, int user) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int ret = 0; + + if (!mfd->ref_cnt) { + MSM_FB_INFO("msm_fb_release: try to close unopened fb %d!\n", + mfd->index); + return -EINVAL; + } + + mfd->ref_cnt--; + + if (!mfd->ref_cnt) { + if ((ret = + msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, + mfd->op_enable)) != 0) { + printk(KERN_ERR "msm_fb_release: can't turn off display!\n"); + return ret; + } + } + + return ret; +} + +DECLARE_MUTEX(msm_fb_pan_sem); + +static int msm_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct mdp_dirty_region dirty; + struct mdp_dirty_region *dirtyPtr = NULL; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if ((!mfd->op_enable) || (!mfd->panel_power_on)) + return -EPERM; + + if (var->xoffset > (info->var.xres_virtual - info->var.xres)) + return -EINVAL; + + if (var->yoffset > (info->var.yres_virtual - info->var.yres)) + return -EINVAL; + + if (info->fix.xpanstep) + info->var.xoffset = + (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep; + + if (info->fix.ypanstep) + info->var.yoffset = + (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep; + + /* "UPDT" */ + if (var->reserved[0] == 0x54445055) { + dirty.xoffset = var->reserved[1] & 0xffff; + dirty.yoffset = (var->reserved[1] >> 16) & 0xffff; + + if ((var->reserved[2] & 0xffff) <= dirty.xoffset) + return -EINVAL; + if (((var->reserved[2] >> 16) & 0xffff) <= dirty.yoffset) + return -EINVAL; + + dirty.width = (var->reserved[2] & 0xffff) - dirty.xoffset; + dirty.height = + ((var->reserved[2] >> 16) & 0xffff) - dirty.yoffset; + info->var.yoffset = var->yoffset; + + if (dirty.xoffset < 0) + return -EINVAL; + + if (dirty.yoffset < 0) + return -EINVAL; + + if ((dirty.xoffset + dirty.width) > info->var.xres) + return -EINVAL; + + if ((dirty.yoffset + dirty.height) > info->var.yres) + return -EINVAL; + + if ((dirty.width <= 0) || (dirty.height <= 0)) + return -EINVAL; + + dirtyPtr = &dirty; + } + + /* Flip */ + /* A constant value is used to indicate that we should change the DMA + output buffer instead of just panning */ + + if (var->reserved[0] == 0x466c6970) { + unsigned long length, address; + struct file *p_src_file; + struct mdp_img imgdata; + int bpp; + + if (mfd->allow_set_offset) { + imgdata.memory_id = var->reserved[1]; + imgdata.priv = var->reserved[2]; + + /* If there is no memory ID then we want to reset back + to the original fb visibility */ + if (var->reserved[1]) { + if (var->reserved[4] == MDP_BLIT_SRC_GEM) { + panic("waaaaaaaaaaaaaah"); + if ( /*get_gem_img(&imgdata, + (unsigned long *) &address, + &length)*/ -1 < 0) { + return -1; + } + } else { + /*get_img(&imgdata, info, &address, + &length, &p_src_file);*/ + panic("waaaaaah"); + } + mfd->ibuf.visible_swapped = TRUE; + } else { + /* Flip back to the original address + adjusted for xoffset and yoffset */ + + bpp = info->var.bits_per_pixel / 8; + address = (unsigned long) info->fix.smem_start; + address += info->var.xoffset * bpp + + info->var.yoffset * info->fix.line_length; + + mfd->ibuf.visible_swapped = FALSE; + } + + mdp_set_offset_info(info, address, + (var->activate == FB_ACTIVATE_VBL)); + + mfd->dma_fnc(mfd); + return 0; + } else + return -EINVAL; + } + + down(&msm_fb_pan_sem); + mdp_set_dma_pan_info(info, dirtyPtr, + (var->activate == FB_ACTIVATE_VBL)); + mdp_dma_pan_update(info); + up(&msm_fb_pan_sem); + + ++mfd->panel_info.frame_count; + return 0; +} + +static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (var->rotate != FB_ROTATE_UR) + return -EINVAL; + if (var->grayscale != info->var.grayscale) + return -EINVAL; + + switch (var->bits_per_pixel) { + case 16: + if ((var->green.offset != 5) || + !((var->blue.offset == 11) + || (var->blue.offset == 0)) || + !((var->red.offset == 11) + || (var->red.offset == 0)) || + (var->blue.length != 5) || + (var->green.length != 6) || + (var->red.length != 5) || + (var->blue.msb_right != 0) || + (var->green.msb_right != 0) || + (var->red.msb_right != 0) || + (var->transp.offset != 0) || + (var->transp.length != 0)) + return -EINVAL; + break; + + case 24: + if ((var->blue.offset != 0) || + (var->green.offset != 8) || + (var->red.offset != 16) || + (var->blue.length != 8) || + (var->green.length != 8) || + (var->red.length != 8) || + (var->blue.msb_right != 0) || + (var->green.msb_right != 0) || + (var->red.msb_right != 0) || + !(((var->transp.offset == 0) && + (var->transp.length == 0)) || + ((var->transp.offset == 24) && + (var->transp.length == 8)))) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0)) + return -EINVAL; + + if (info->fix.smem_len < + (var->xres_virtual*var->yres_virtual*(var->bits_per_pixel/8))) + return -EINVAL; + + if ((var->xres == 0) || (var->yres == 0)) + return -EINVAL; + + if ((var->xres > mfd->panel_info.xres) || + (var->yres > mfd->panel_info.yres)) + return -EINVAL; + + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; + + if (var->yoffset > (var->yres_virtual - var->yres)) + return -EINVAL; + + return 0; +} + +static int msm_fb_set_par(struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct fb_var_screeninfo *var = &info->var; + int old_imgType; + int blank = 0; + + old_imgType = mfd->fb_imgType; + switch (var->bits_per_pixel) { + case 16: + if (var->red.offset == 0) + mfd->fb_imgType = MDP_BGR_565; + else + mfd->fb_imgType = MDP_RGB_565; + break; + + case 24: + if ((var->transp.offset == 0) && (var->transp.length == 0)) + mfd->fb_imgType = MDP_RGB_888; + else if ((var->transp.offset == 24) && + (var->transp.length == 8)) { + mfd->fb_imgType = MDP_ARGB_8888; + info->var.bits_per_pixel = 32; + } + break; + + default: + return -EINVAL; + } + + if ((mfd->var_pixclock != var->pixclock) || + (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) || + (mfd->var_pixclock != var->pixclock) || + (mfd->var_xres != var->xres) || + (mfd->var_yres != var->yres)))) { + mfd->var_xres = var->xres; + mfd->var_yres = var->yres; + mfd->var_pixclock = var->pixclock; + blank = 1; + } + + if (blank) { + msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable); + msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable); + } + + return 0; +} + +static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd) +{ + if (mfd->hw_refresh) + return -EPERM; + + if (mfd->sw_currently_refreshing) { + down(&mfd->sem); + mfd->sw_currently_refreshing = FALSE; + up(&mfd->sem); + + /* wait until the refresher finishes the last job */ + wait_for_completion_killable(&mfd->refresher_comp); + } + + return 0; +} + +int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd) +{ + boolean do_refresh; + + if (mfd->hw_refresh) + return -EPERM; + + down(&mfd->sem); + if ((!mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) { + do_refresh = TRUE; + mfd->sw_currently_refreshing = TRUE; + } else { + do_refresh = FALSE; + } + up(&mfd->sem); + + if (do_refresh) + mdp_refresh_screen((unsigned long)mfd); + + return 0; +} + +void mdp_ppp_put_img(struct file *p_src_file, struct file *p_dst_file) +{ +#ifdef CONFIG_ANDROID_PMEM + if (p_src_file) + put_pmem_file(p_src_file); + if (p_dst_file) + put_pmem_file(p_dst_file); +#endif +} + +int mdp_blit(struct fb_info *info, struct mdp_blit_req *req) +{ + int ret; + struct file *p_src_file = 0, *p_dst_file = 0; + if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) { + printk(KERN_ERR "mpd_ppp: src img of zero size!\n"); + return -EINVAL; + } + if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0)) + return 0; + + ret = mdp_ppp_blit(info, req, &p_src_file, &p_dst_file); + mdp_ppp_put_img(p_src_file, p_dst_file); + return ret; +} + +typedef void (*msm_dma_barrier_function_pointer) (void *, size_t); + +static inline void msm_fb_dma_barrier_for_rect(struct fb_info *info, + struct mdp_img *img, struct mdp_rect *rect, + msm_dma_barrier_function_pointer dma_barrier_fp + ) +{ + /* + * Compute the start and end addresses of the rectangles. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. + */ + + char * const pmem_start = info->screen_base; +/* int bytes_per_pixel = mdp_get_bytes_per_pixel(img->format); + unsigned long start = (unsigned long)pmem_start + img->offset + + (img->width * rect->y + rect->x) * bytes_per_pixel; + size_t size = ((rect->h - 1) * img->width + rect->w) * bytes_per_pixel; + (*dma_barrier_fp) ((void *) start, size); +*/ + panic("waaaaah"); +} + +static inline void msm_dma_nc_pre(void) +{ + dmb(); +} +static inline void msm_dma_wt_pre(void) +{ + dmb(); +} +static inline void msm_dma_todevice_wb_pre(void *start, size_t size) +{ + #warning this +// dma_cache_pre_ops(start, size, DMA_TO_DEVICE); +} + +static inline void msm_dma_fromdevice_wb_pre(void *start, size_t size) +{ + #warning this +// dma_cache_pre_ops(start, size, DMA_FROM_DEVICE); +} + +static inline void msm_dma_nc_post(void) +{ + dmb(); +} + +static inline void msm_dma_fromdevice_wt_post(void *start, size_t size) +{ + #warning this +// dma_cache_post_ops(start, size, DMA_FROM_DEVICE); +} + +static inline void msm_dma_todevice_wb_post(void *start, size_t size) +{ + #warning this +// dma_cache_post_ops(start, size, DMA_TO_DEVICE); +} + +static inline void msm_dma_fromdevice_wb_post(void *start, size_t size) +{ + #warning this +// dma_cache_post_ops(start, size, DMA_FROM_DEVICE); +} + +/* + * Do the write barriers required to guarantee data is committed to RAM + * (from CPU cache or internal buffers) before a DMA operation starts. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. +*/ +static void msm_fb_ensure_memory_coherency_before_dma(struct fb_info *info, + struct mdp_blit_req *req_list, + int req_list_count) +{ +#ifdef CONFIG_ARCH_QSD8X50 + int i; + + /* + * Normally, do the requested barriers for each address + * range that corresponds to a rectangle. + * + * But if at least one write barrier is requested for data + * going to or from the device but no address range is + * needed for that barrier, then do the barrier, but do it + * only once, no matter how many requests there are. + */ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + switch (mfd->mdp_fb_page_protection) { + default: + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_START)) { + msm_dma_nc_pre(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_START)) { + msm_dma_wt_pre(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_START)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].src), + &(req_list[i].src_rect), + msm_dma_todevice_wb_pre + ); + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_todevice_wb_pre + ); + } + } + break; + } +#else + dmb(); +#endif +} + + +/* + * Do the write barriers required to guarantee data will be re-read from RAM by + * the CPU after a DMA operation ends. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. +*/ +static void msm_fb_ensure_memory_coherency_after_dma(struct fb_info *info, + struct mdp_blit_req *req_list, + int req_list_count) +{ +#ifdef CONFIG_ARCH_QSD8X50 + int i; + + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + switch (mfd->mdp_fb_page_protection) { + default: + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_END)) { + msm_dma_nc_post(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_END)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_fromdevice_wt_post + ); + } + } + break; + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_END)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_fromdevice_wb_post + ); + } + } + break; + } +#else + dmb(); +#endif +} + +#ifdef CONFIG_MDP_PPP_ASYNC_OP +void msm_fb_ensure_mem_coherency_after_dma(struct fb_info *info, + struct mdp_blit_req *req_list, int req_list_count) +{ + BUG_ON(!info); + + /* + * Ensure that CPU cache and other internal CPU state is + * updated to reflect any change in memory modified by MDP blit + * DMA. + */ + msm_fb_ensure_memory_coherency_after_dma(info, + req_list, req_list_count); +} + +static int msmfb_async_blit(struct fb_info *info, void __user *p) +{ + /* + * CAUTION: The names of the struct types intentionally *DON'T* match + * the names of the variables declared -- they appear to be swapped. + * Read the code carefully and you should see that the variable names + * make sense. + */ + const int MAX_LIST_WINDOW = 16; + struct mdp_blit_req req_list[MAX_LIST_WINDOW]; + struct mdp_blit_req_list req_list_header; + + int count, i, req_list_count; + + /* Get the count size for the total BLIT request. */ + if (copy_from_user(&req_list_header, p, sizeof(req_list_header))) + return -EFAULT; + p += sizeof(req_list_header); + count = req_list_header.count; + while (count > 0) { + /* + * Access the requests through a narrow window to decrease copy + * overhead and make larger requests accessible to the + * coherency management code. + * NOTE: The window size is intended to be larger than the + * typical request size, but not require more than 2 + * kbytes of stack storage. + */ + req_list_count = count; + if (req_list_count > MAX_LIST_WINDOW) + req_list_count = MAX_LIST_WINDOW; + if (copy_from_user(&req_list, p, + sizeof(struct mdp_blit_req)*req_list_count)) + return -EFAULT; + + /* + * Ensure that any data CPU may have previously written to + * internal state (but not yet committed to memory) is + * guaranteed to be committed to memory now. + */ + msm_fb_ensure_memory_coherency_before_dma(info, + req_list, req_list_count); + + /* + * Do the blit DMA, if required -- returning early only if + * there is a failure. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & MDP_NO_BLIT)) { + int ret = 0; + struct mdp_ppp_djob *job = NULL; + + if (unlikely(req_list[i].src_rect.h == 0 || + req_list[i].src_rect.w == 0)) { + MSM_FB_ERR("mpd_ppp: " + "src img of zero size!\n"); + return -EINVAL; + } + + if (unlikely(req_list[i].dst_rect.h == 0 || + req_list[i].dst_rect.w == 0)) + continue; + + /* create a new display job */ + job = mdp_ppp_new_djob(); + if (unlikely(!job)) + return -ENOMEM; + + job->info = info; + memcpy(&job->req, &req_list[i], + sizeof(struct mdp_blit_req)); + + /* Do the actual blit. */ + ret = mdp_ppp_blit(info, &job->req, + &job->p_src_file, &job->p_dst_file); + + /* + * Note that early returns don't guarantee + * memory coherency. + */ + if (ret || mdp_ppp_get_ret_code()) { + mdp_ppp_clear_curr_djob(); + return ret; + } + } + } + + /* Go to next window of requests. */ + count -= req_list_count; + p += sizeof(struct mdp_blit_req)*req_list_count; + } + return 0; +} +#else + +/* + * NOTE: The userspace issues blit operations in a sequence, the sequence + * start with a operation marked START and ends in an operation marked + * END. It is guranteed by the userspace that all the blit operations + * between START and END are only within the regions of areas designated + * by the START and END operations and that the userspace doesnt modify + * those areas. Hence it would be enough to perform barrier/cache operations + * only on the START and END operations. + */ +static int msmfb_blit(struct fb_info *info, void __user *p) +{ + /* + * CAUTION: The names of the struct types intentionally *DON'T* match + * the names of the variables declared -- they appear to be swapped. + * Read the code carefully and you should see that the variable names + * make sense. + */ + const int MAX_LIST_WINDOW = 16; + struct mdp_blit_req req_list[MAX_LIST_WINDOW]; + struct mdp_blit_req_list req_list_header; + + int count, i, req_list_count; + + /* Get the count size for the total BLIT request. */ + if (copy_from_user(&req_list_header, p, sizeof(req_list_header))) + return -EFAULT; + p += sizeof(req_list_header); + count = req_list_header.count; + while (count > 0) { + /* + * Access the requests through a narrow window to decrease copy + * overhead and make larger requests accessible to the + * coherency management code. + * NOTE: The window size is intended to be larger than the + * typical request size, but not require more than 2 + * kbytes of stack storage. + */ + req_list_count = count; + if (req_list_count > MAX_LIST_WINDOW) + req_list_count = MAX_LIST_WINDOW; + if (copy_from_user(&req_list, p, + sizeof(struct mdp_blit_req)*req_list_count)) + return -EFAULT; + + /* + * Ensure that any data CPU may have previously written to + * internal state (but not yet committed to memory) is + * guaranteed to be committed to memory now. + */ + msm_fb_ensure_memory_coherency_before_dma(info, + req_list, req_list_count); + + /* + * Do the blit DMA, if required -- returning early only if + * there is a failure. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & MDP_NO_BLIT)) { + /* Do the actual blit. */ + int ret = mdp_blit(info, &(req_list[i])); + + /* + * Note that early returns don't guarantee + * memory coherency. + */ + if (ret) + return ret; + } + } + + /* + * Ensure that CPU cache and other internal CPU state is + * updated to reflect any change in memory modified by MDP blit + * DMA. + */ + msm_fb_ensure_memory_coherency_after_dma(info, + req_list, + req_list_count); + + /* Go to next window of requests. */ + count -= req_list_count; + p += sizeof(struct mdp_blit_req)*req_list_count; + } + return 0; +} +#endif + +#ifdef CONFIG_FB_MSM_OVERLAY +static int msmfb_overlay_get(struct fb_info *info, void __user *p) +{ + struct mdp_overlay req; + int ret; + + if (copy_from_user(&req, p, sizeof(req))) + return -EFAULT; + + ret = mdp4_overlay_get(info, &req); + if (ret) { + printk(KERN_ERR "%s: ioctl failed \n", + __func__); + return ret; + } + if (copy_to_user(p, &req, sizeof(req))) { + printk(KERN_ERR "%s: copy2user failed \n", + __func__); + return -EFAULT; + } + + return 0; +} + +static int msmfb_overlay_set(struct fb_info *info, void __user *p) +{ + struct mdp_overlay req; + int ret; + + if (copy_from_user(&req, p, sizeof(req))) + return -EFAULT; + + ret = mdp4_overlay_set(info, &req); + if (ret) { + printk(KERN_ERR "%s:ioctl failed \n", + __func__); + return ret; + } + + if (copy_to_user(p, &req, sizeof(req))) { + printk(KERN_ERR "%s: copy2user failed \n", + __func__); + return -EFAULT; + } + + return 0; +} + +static int msmfb_overlay_unset(struct fb_info *info, unsigned long *argp) +{ + int ret, ndx; + + ret = copy_from_user(&ndx, argp, sizeof(ndx)); + if (ret) { + printk(KERN_ERR "%s:msmfb_overlay_unset ioctl failed \n", + __func__); + return ret; + } + + return mdp4_overlay_unset(info, ndx); +} + +static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_data req; + struct file *p_src_file = 0; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + printk(KERN_ERR "%s:msmfb_overlay_play ioctl failed \n", + __func__); + return ret; + } + + ret = mdp4_overlay_play(info, &req, &p_src_file); + + if (p_src_file) + put_pmem_file(p_src_file); + + return ret; +} + +#endif + +DECLARE_MUTEX(msm_fb_ioctl_ppp_sem); +DEFINE_MUTEX(msm_fb_ioctl_lut_sem); +DEFINE_MUTEX(msm_fb_ioctl_hist_sem); + +/* Set color conversion matrix from user space */ + +#ifndef CONFIG_FB_MSM_MDP40 +static void msmfb_set_color_conv(struct mdp_ccs *p) +{ + int i; + + if (p->direction == MDP_CCS_RGB2YUV) { + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* RGB->YUV primary forward matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(p->ccs[i], MDP_CSC_PFMVn(i)); + + #ifdef CONFIG_FB_MSM_MDP31 + for (i = 0; i < MDP_BV_SIZE; i++) + writel(p->bv[i], MDP_CSC_POST_BV2n(i)); + #endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } else { + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* YUV->RGB primary reverse matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(p->ccs[i], MDP_CSC_PRMVn(i)); + for (i = 0; i < MDP_BV_SIZE; i++) + writel(p->bv[i], MDP_CSC_PRE_BV1n(i)); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } +} +#endif + + +static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + void __user *argp = (void __user *)arg; + struct fb_cursor cursor; + struct fb_cmap cmap; + struct mdp_histogram hist; +#ifndef CONFIG_FB_MSM_MDP40 + struct mdp_ccs ccs_matrix; +#endif + struct mdp_page_protection fb_page_protection; + int ret = 0; + + if (!mfd->op_enable) + return -EPERM; + + switch (cmd) { +#ifdef CONFIG_FB_MSM_OVERLAY + case MSMFB_OVERLAY_GET: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_get(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_SET: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_set(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_UNSET: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_unset(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_PLAY: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_play(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; +#endif + case MSMFB_BLIT: + down(&msm_fb_ioctl_ppp_sem); +#ifdef CONFIG_MDP_PPP_ASYNC_OP + ret = msmfb_async_blit(info, argp); + mdp_ppp_wait(); /* Wait for all blits to be finished. */ +#else + ret = msmfb_blit(info, argp); +#endif + up(&msm_fb_ioctl_ppp_sem); + + break; + + /* Ioctl for setting ccs matrix from user space */ + case MSMFB_SET_CCS_MATRIX: +#ifndef CONFIG_FB_MSM_MDP40 + ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)); + if (ret) { + printk(KERN_ERR + "%s:MSMFB_SET_CCS_MATRIX ioctl failed \n", + __func__); + return ret; + } + + down(&msm_fb_ioctl_ppp_sem); + if (ccs_matrix.direction == MDP_CCS_RGB2YUV) + mdp_ccs_rgb2yuv = ccs_matrix; + else + mdp_ccs_yuv2rgb = ccs_matrix; + + msmfb_set_color_conv(&ccs_matrix) ; + up(&msm_fb_ioctl_ppp_sem); +#else + ret = -EINVAL; +#endif + + break; + + /* Ioctl for getting ccs matrix to user space */ + case MSMFB_GET_CCS_MATRIX: +#ifndef CONFIG_FB_MSM_MDP40 + ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)) ; + if (ret) { + printk(KERN_ERR + "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n", + __func__); + return ret; + } + + down(&msm_fb_ioctl_ppp_sem); + if (ccs_matrix.direction == MDP_CCS_RGB2YUV) + ccs_matrix = mdp_ccs_rgb2yuv; + else + ccs_matrix = mdp_ccs_yuv2rgb; + + ret = copy_to_user(argp, &ccs_matrix, sizeof(ccs_matrix)); + + if (ret) { + printk(KERN_ERR + "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n", + __func__); + return ret ; + } + up(&msm_fb_ioctl_ppp_sem); +#else + ret = -EINVAL; +#endif + + break; + +#ifdef CONFIG_MDP_PPP_ASYNC_OP + case MSMFB_ASYNC_BLIT: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_async_blit(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + + case MSMFB_BLIT_FLUSH: + down(&msm_fb_ioctl_ppp_sem); + mdp_ppp_wait(); + up(&msm_fb_ioctl_ppp_sem); + break; +#endif + + case MSMFB_GRP_DISP: +#ifdef CONFIG_FB_MSM_MDP22 + { + unsigned long grp_id; + + ret = copy_from_user(&grp_id, argp, sizeof(grp_id)); + if (ret) + return ret; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + writel(grp_id, MDP_FULL_BYPASS_WORD43); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, + FALSE); + break; + } +#else + return -EFAULT; +#endif + case MSMFB_SUSPEND_SW_REFRESHER: + if (!mfd->panel_power_on) + return -EPERM; + + mfd->sw_refreshing_enable = FALSE; + ret = msm_fb_stop_sw_refresher(mfd); + break; + + case MSMFB_RESUME_SW_REFRESHER: + if (!mfd->panel_power_on) + return -EPERM; + + mfd->sw_refreshing_enable = TRUE; + ret = msm_fb_resume_sw_refresher(mfd); + break; + + case MSMFB_CURSOR: + ret = copy_from_user(&cursor, argp, sizeof(cursor)); + if (ret) + return ret; + + ret = msm_fb_cursor(info, &cursor); + break; + + case MSMFB_SET_LUT: + ret = copy_from_user(&cmap, argp, sizeof(cmap)); + if (ret) + return ret; + + mutex_lock(&msm_fb_ioctl_lut_sem); + ret = msm_fb_set_lut(&cmap, info); + mutex_unlock(&msm_fb_ioctl_lut_sem); + break; + + case MSMFB_HISTOGRAM: + if (!mfd->do_histogram) + return -ENODEV; + + ret = copy_from_user(&hist, argp, sizeof(hist)); + if (ret) + return ret; + + mutex_lock(&msm_fb_ioctl_hist_sem); + ret = mfd->do_histogram(info, &hist); + mutex_unlock(&msm_fb_ioctl_hist_sem); + break; + + case MSMFB_GET_PAGE_PROTECTION: + fb_page_protection.page_protection + = mfd->mdp_fb_page_protection; + ret = copy_to_user(argp, &fb_page_protection, + sizeof(fb_page_protection)); + if (ret) + return ret; + break; + + case MSMFB_SET_PAGE_PROTECTION: +#ifdef CONFIG_ARCH_QSD8X50 + ret = copy_from_user(&fb_page_protection, argp, + sizeof(fb_page_protection)); + if (ret) + return ret; + + /* Validate the proposed page protection settings. */ + switch (fb_page_protection.page_protection) { + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + /* Write-back cache (read allocate) */ + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + /* Write-back cache (write allocate) */ + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + mfd->mdp_fb_page_protection = + fb_page_protection.page_protection; + break; + default: + ret = -EINVAL; + break; + } +#else + /* + * Don't allow caching until 7k DMA cache operations are + * available. + */ + ret = -EINVAL; +#endif + break; + + default: + MSM_FB_INFO("MDP: unknown ioctl (cmd=%d) received!\n", cmd); + ret = -EINVAL; + break; + } + + return ret; +} + +static int msm_fb_register_driver(void) +{ + return platform_driver_register(&msm_fb_driver); +} + +void msm_fb_add_device(struct platform_device *pdev) +{ + struct msm_fb_panel_data *pdata; + struct platform_device *this_dev = NULL; + struct fb_info *fbi; + struct msm_fb_data_type *mfd = NULL; + u32 type, id, fb_num; + + if (!pdev) + return; + id = pdev->id; + + pdata = pdev->dev.platform_data; + if (!pdata) + return; + type = pdata->panel_info.type; + fb_num = pdata->panel_info.fb_num; + + if (fb_num <= 0) + return; + + if (fbi_list_index >= MAX_FBI_LIST) { + printk(KERN_ERR "msm_fb: no more framebuffer info list!\n"); + return; + } + /* + * alloc panel device data + */ + this_dev = msm_fb_device_alloc(pdata, type, id); + + if (!this_dev) { + printk(KERN_ERR + "%s: msm_fb_device_alloc failed!\n", __func__); + return; + } + + /* + * alloc framebuffer info + par data + */ + fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL); + if (fbi == NULL) { + platform_device_put(this_dev); + printk(KERN_ERR "msm_fb: can't alloca framebuffer info data!\n"); + return; + } + + mfd = (struct msm_fb_data_type *)fbi->par; + mfd->key = MFD_KEY; + mfd->fbi = fbi; + mfd->panel.type = type; + mfd->panel.id = id; + mfd->fb_page = fb_num; + mfd->index = fbi_list_index; + mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE; + + /* link to the latest pdev */ + mfd->pdev = this_dev; + + mfd_list[mfd_list_index++] = mfd; + fbi_list[fbi_list_index++] = fbi; + + /* + * set driver data + */ + platform_set_drvdata(this_dev, mfd); + + if (platform_device_add(this_dev)) { + printk(KERN_ERR "msm_fb: platform_device_add failed!\n"); + platform_device_put(this_dev); + framebuffer_release(fbi); + fbi_list_index--; + return; + } +} +EXPORT_SYMBOL(msm_fb_add_device); + +int __init msm_fb_init(void) +{ + int rc = -ENODEV; + + if (msm_fb_register_driver()) + return rc; + +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + + if ((root = msm_fb_get_debugfs_root()) != NULL) { + msm_fb_debugfs_file_create(root, + "msm_fb_msg_printing_level", + (u32 *) &msm_fb_msg_level); + msm_fb_debugfs_file_create(root, + "mddi_msg_printing_level", + (u32 *) &mddi_msg_level); + msm_fb_debugfs_file_create(root, "msm_fb_debug_enabled", + (u32 *) &msm_fb_debug_enabled); + } + } +#endif + + return 0; +} + +module_init(msm_fb_init); diff --git a/drivers/staging/msm/msm_fb.h b/drivers/staging/msm/msm_fb.h new file mode 100644 index 000000000000..f93913800475 --- /dev/null +++ b/drivers/staging/msm/msm_fb.h @@ -0,0 +1,174 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * + */ + +#ifndef MSM_FB_H +#define MSM_FB_H + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include "linux/proc_fs.h" + +#include <mach/hardware.h> +#include <linux/io.h> +#include <mach/board.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <mach/memory.h> +#include <linux/semaphore.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/hrtimer.h> + +#include <linux/fb.h> + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif + +#include "msm_fb_panel.h" +#include "mdp.h" + +#define MSM_FB_DEFAULT_PAGE_SIZE 2 +#define MFD_KEY 0x11161126 +#define MSM_FB_MAX_DEV_LIST 32 + +struct disp_info_type_suspend { + boolean op_enable; + boolean sw_refreshing_enable; + boolean panel_power_on; +}; + +struct msm_fb_data_type { + __u32 key; + __u32 index; + __u32 ref_cnt; + __u32 fb_page; + + panel_id_type panel; + struct msm_panel_info panel_info; + + DISP_TARGET dest; + struct fb_info *fbi; + + boolean op_enable; + uint32 fb_imgType; + boolean sw_currently_refreshing; + boolean sw_refreshing_enable; + boolean hw_refresh; + + MDPIBUF ibuf; + boolean ibuf_flushed; + struct timer_list refresh_timer; + struct completion refresher_comp; + + boolean pan_waiting; + struct completion pan_comp; + + /* vsync */ + boolean use_mdp_vsync; + __u32 vsync_gpio; + __u32 total_lcd_lines; + __u32 total_porch_lines; + __u32 lcd_ref_usec_time; + __u32 refresh_timer_duration; + + struct hrtimer dma_hrtimer; + + boolean panel_power_on; + struct work_struct dma_update_worker; + struct semaphore sem; + + struct timer_list vsync_resync_timer; + boolean vsync_handler_pending; + struct work_struct vsync_resync_worker; + + ktime_t last_vsync_timetick; + + __u32 *vsync_width_boundary; + + unsigned int pmem_id; + struct disp_info_type_suspend suspend; + + __u32 channel_irq; + + struct mdp_dma_data *dma; + void (*dma_fnc) (struct msm_fb_data_type *mfd); + int (*cursor_update) (struct fb_info *info, + struct fb_cursor *cursor); + int (*lut_update) (struct fb_info *info, + struct fb_cmap *cmap); + int (*do_histogram) (struct fb_info *info, + struct mdp_histogram *hist); + void *cursor_buf; + void *cursor_buf_phys; + + void *cmd_port; + void *data_port; + void *data_port_phys; + + __u32 bl_level; + + struct platform_device *pdev; + + __u32 var_xres; + __u32 var_yres; + __u32 var_pixclock; + +#ifdef MSM_FB_ENABLE_DBGFS + struct dentry *sub_dir; +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; + struct early_suspend mddi_early_suspend; + struct early_suspend mddi_ext_early_suspend; +#endif + u32 mdp_fb_page_protection; + int allow_set_offset; +}; + +struct dentry *msm_fb_get_debugfs_root(void); +void msm_fb_debugfs_file_create(struct dentry *root, const char *name, + u32 *var); +void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl, + u32 save); + +void msm_fb_add_device(struct platform_device *pdev); + +int msm_fb_detect_client(const char *name); + +#ifdef CONFIG_FB_BACKLIGHT +void msm_fb_config_backlight(struct msm_fb_data_type *mfd); +#endif + +#endif /* MSM_FB_H */ diff --git a/drivers/staging/msm/msm_fb_bl.c b/drivers/staging/msm/msm_fb_bl.c new file mode 100644 index 000000000000..033fc9486e01 --- /dev/null +++ b/drivers/staging/msm/msm_fb_bl.c @@ -0,0 +1,79 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/string.h> +#include <linux/version.h> +#include <linux/backlight.h> + +#include "msm_fb.h" + +static int msm_fb_bl_get_brightness(struct backlight_device *pbd) +{ + return pbd->props.brightness; +} + +static int msm_fb_bl_update_status(struct backlight_device *pbd) +{ + struct msm_fb_data_type *mfd = bl_get_data(pbd); + __u32 bl_lvl; + + bl_lvl = pbd->props.brightness; + bl_lvl = mfd->fbi->bl_curve[bl_lvl]; + msm_fb_set_backlight(mfd, bl_lvl, 1); + return 0; +} + +static struct backlight_ops msm_fb_bl_ops = { + .get_brightness = msm_fb_bl_get_brightness, + .update_status = msm_fb_bl_update_status, +}; + +void msm_fb_config_backlight(struct msm_fb_data_type *mfd) +{ + struct msm_fb_panel_data *pdata; + struct backlight_device *pbd; + struct fb_info *fbi; + char name[16]; + + fbi = mfd->fbi; + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + if ((pdata) && (pdata->set_backlight)) { + snprintf(name, sizeof(name), "msmfb_bl%d", mfd->index); + pbd = + backlight_device_register(name, fbi->dev, mfd, + &msm_fb_bl_ops); + if (!IS_ERR(pbd)) { + fbi->bl_dev = pbd; + fb_bl_default_curve(fbi, + 0, + mfd->panel_info.bl_min, + mfd->panel_info.bl_max); + pbd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; + pbd->props.brightness = FB_BACKLIGHT_LEVELS - 1; + backlight_update_status(pbd); + } else { + fbi->bl_dev = NULL; + printk(KERN_ERR "msm_fb: backlight_device_register failed!\n"); + } + } +} diff --git a/drivers/staging/msm/msm_fb_def.h b/drivers/staging/msm/msm_fb_def.h new file mode 100644 index 000000000000..6de440937422 --- /dev/null +++ b/drivers/staging/msm/msm_fb_def.h @@ -0,0 +1,201 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * + */ + +#ifndef MSM_FB_DEF_H +#define MSM_FB_DEF_H + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/fb.h> +#include "msm_mdp.h" +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/uaccess.h> +#include <linux/workqueue.h> +#include <linux/string.h> +#include <linux/version.h> +#include <linux/proc_fs.h> +#include <linux/vmalloc.h> +#include <linux/debugfs.h> +#include <linux/console.h> + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include "linux/proc_fs.h" +#include <mach/hardware.h> +#include <linux/io.h> +#include <linux/fb.h> +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/platform_device.h> + +typedef s64 int64; +typedef s32 int32; +typedef s16 int16; +typedef s8 int8; + +typedef u64 uint64; +typedef u32 uint32; +typedef u16 uint16; +typedef u8 uint8; + +typedef s32 int4; +typedef s16 int2; +typedef s8 int1; + +typedef u32 uint4; +typedef u16 uint2; +typedef u8 uint1; + +typedef u32 dword; +typedef u16 word; +typedef u8 byte; + +typedef unsigned int boolean; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define MSM_FB_ENABLE_DBGFS +#define FEATURE_MDDI + +#define outp32(addr, val) writel(val, addr) +#define outp16(addr, val) writew(val, addr) +#define outp8(addr, val) writeb(val, addr) +#define outp(addr, val) outp32(addr, val) + +#ifndef MAX +#define MAX( x, y ) (((x) > (y)) ? (x) : (y)) +#endif + +#ifndef MIN +#define MIN( x, y ) (((x) < (y)) ? (x) : (y)) +#endif + +/*--------------------------------------------------------------------------*/ + +#define inp32(addr) readl(addr) +#define inp16(addr) readw(addr) +#define inp8(addr) readb(addr) +#define inp(addr) inp32(addr) + +#define inpw(port) readw(port) +#define outpw(port, val) writew(val, port) +#define inpdw(port) readl(port) +#define outpdw(port, val) writel(val, port) + + +#define clk_busy_wait(x) msleep_interruptible((x)/1000) + +#define memory_barrier() + +#define assert(expr) \ + if(!(expr)) { \ + printk(KERN_ERR "msm_fb: assertion failed! %s,%s,%s,line=%d\n",\ + #expr, __FILE__, __func__, __LINE__); \ + } + +#define ASSERT(x) assert(x) + +#define DISP_EBI2_LOCAL_DEFINE +#ifdef DISP_EBI2_LOCAL_DEFINE +#define LCD_PRIM_BASE_PHYS 0x98000000 +#define LCD_SECD_BASE_PHYS 0x9c000000 +#define EBI2_PRIM_LCD_RS_PIN 0x20000 +#define EBI2_SECD_LCD_RS_PIN 0x20000 + +#define EBI2_PRIM_LCD_CLR 0xC0 +#define EBI2_PRIM_LCD_SEL 0x40 + +#define EBI2_SECD_LCD_CLR 0x300 +#define EBI2_SECD_LCD_SEL 0x100 +#endif + +extern u32 msm_fb_msg_level; + +/* + * Message printing priorities: + * LEVEL 0 KERN_EMERG (highest priority) + * LEVEL 1 KERN_ALERT + * LEVEL 2 KERN_CRIT + * LEVEL 3 KERN_ERR + * LEVEL 4 KERN_WARNING + * LEVEL 5 KERN_NOTICE + * LEVEL 6 KERN_INFO + * LEVEL 7 KERN_DEBUG (Lowest priority) + */ +#define MSM_FB_EMERG(msg, ...) \ + if (msm_fb_msg_level > 0) \ + printk(KERN_EMERG msg, ## __VA_ARGS__); +#define MSM_FB_ALERT(msg, ...) \ + if (msm_fb_msg_level > 1) \ + printk(KERN_ALERT msg, ## __VA_ARGS__); +#define MSM_FB_CRIT(msg, ...) \ + if (msm_fb_msg_level > 2) \ + printk(KERN_CRIT msg, ## __VA_ARGS__); +#define MSM_FB_ERR(msg, ...) \ + if (msm_fb_msg_level > 3) \ + printk(KERN_ERR msg, ## __VA_ARGS__); +#define MSM_FB_WARNING(msg, ...) \ + if (msm_fb_msg_level > 4) \ + printk(KERN_WARNING msg, ## __VA_ARGS__); +#define MSM_FB_NOTICE(msg, ...) \ + if (msm_fb_msg_level > 5) \ + printk(KERN_NOTICE msg, ## __VA_ARGS__); +#define MSM_FB_INFO(msg, ...) \ + if (msm_fb_msg_level > 6) \ + printk(KERN_INFO msg, ## __VA_ARGS__); +#define MSM_FB_DEBUG(msg, ...) \ + if (msm_fb_msg_level > 7) \ + printk(KERN_DEBUG msg, ## __VA_ARGS__); + +#ifdef MSM_FB_C +unsigned char *msm_mdp_base; +unsigned char *msm_pmdh_base; +unsigned char *msm_emdh_base; +#else +extern unsigned char *msm_mdp_base; +extern unsigned char *msm_pmdh_base; +extern unsigned char *msm_emdh_base; +#endif + +#endif /* MSM_FB_DEF_H */ diff --git a/drivers/staging/msm/msm_fb_panel.c b/drivers/staging/msm/msm_fb_panel.c new file mode 100644 index 000000000000..b17a239a1bc7 --- /dev/null +++ b/drivers/staging/msm/msm_fb_panel.c @@ -0,0 +1,136 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/uaccess.h> +#include <linux/workqueue.h> +#include <linux/string.h> +#include <linux/version.h> +#include <linux/proc_fs.h> +#include <linux/vmalloc.h> +#include <linux/debugfs.h> + +#include "msm_fb_panel.h" + +int panel_next_on(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_panel_data *pdata; + struct msm_fb_panel_data *next_pdata; + struct platform_device *next_pdev; + + pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data; + + if (pdata) { + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = + (struct msm_fb_panel_data *)next_pdev->dev. + platform_data; + if ((next_pdata) && (next_pdata->on)) + ret = next_pdata->on(next_pdev); + } + } + + return ret; +} + +int panel_next_off(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_panel_data *pdata; + struct msm_fb_panel_data *next_pdata; + struct platform_device *next_pdev; + + pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data; + + if (pdata) { + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = + (struct msm_fb_panel_data *)next_pdev->dev. + platform_data; + if ((next_pdata) && (next_pdata->on)) + ret = next_pdata->off(next_pdev); + } + } + + return ret; +} + +struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata, + u32 type, u32 id) +{ + struct platform_device *this_dev = NULL; + char dev_name[16]; + + switch (type) { + case EBI2_PANEL: + snprintf(dev_name, sizeof(dev_name), "ebi2_lcd"); + break; + + case MDDI_PANEL: + snprintf(dev_name, sizeof(dev_name), "mddi"); + break; + + case EXT_MDDI_PANEL: + snprintf(dev_name, sizeof(dev_name), "mddi_ext"); + break; + + case TV_PANEL: + snprintf(dev_name, sizeof(dev_name), "tvenc"); + break; + + case HDMI_PANEL: + case LCDC_PANEL: + snprintf(dev_name, sizeof(dev_name), "lcdc"); + break; + + default: + return NULL; + } + + if (pdata != NULL) + pdata->next = NULL; + else + return NULL; + + this_dev = + platform_device_alloc(dev_name, ((u32) type << 16) | (u32) id); + + if (this_dev) { + if (platform_device_add_data + (this_dev, pdata, sizeof(struct msm_fb_panel_data))) { + printk + ("msm_fb_device_alloc: platform_device_add_data failed!\n"); + platform_device_put(this_dev); + return NULL; + } + } + + return this_dev; +} diff --git a/drivers/staging/msm/msm_fb_panel.h b/drivers/staging/msm/msm_fb_panel.h new file mode 100644 index 000000000000..ab458310c3a2 --- /dev/null +++ b/drivers/staging/msm/msm_fb_panel.h @@ -0,0 +1,145 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * + */ + +#ifndef MSM_FB_PANEL_H +#define MSM_FB_PANEL_H + +#include "msm_fb_def.h" + +struct msm_fb_data_type; + +typedef void (*msm_fb_vsync_handler_type) (void *arg); + +/* panel id type */ +typedef struct panel_id_s { + uint16 id; + uint16 type; +} panel_id_type; + +/* panel type list */ +#define NO_PANEL 0xffff /* No Panel */ +#define MDDI_PANEL 1 /* MDDI */ +#define EBI2_PANEL 2 /* EBI2 */ +#define LCDC_PANEL 3 /* internal LCDC type */ +#define EXT_MDDI_PANEL 4 /* Ext.MDDI */ +#define TV_PANEL 5 /* TV */ +#define HDMI_PANEL 6 /* HDMI TV */ + +/* panel class */ +typedef enum { + DISPLAY_LCD = 0, /* lcd = ebi2/mddi */ + DISPLAY_LCDC, /* lcdc */ + DISPLAY_TV, /* TV Out */ + DISPLAY_EXT_MDDI, /* External MDDI */ +} DISP_TARGET; + +/* panel device locaiton */ +typedef enum { + DISPLAY_1 = 0, /* attached as first device */ + DISPLAY_2, /* attached on second device */ + MAX_PHYS_TARGET_NUM, +} DISP_TARGET_PHYS; + +/* panel info type */ +struct lcd_panel_info { + __u32 vsync_enable; + __u32 refx100; + __u32 v_back_porch; + __u32 v_front_porch; + __u32 v_pulse_width; + __u32 hw_vsync_mode; + __u32 vsync_notifier_period; +}; + +struct lcdc_panel_info { + __u32 h_back_porch; + __u32 h_front_porch; + __u32 h_pulse_width; + __u32 v_back_porch; + __u32 v_front_porch; + __u32 v_pulse_width; + __u32 border_clr; + __u32 underflow_clr; + __u32 hsync_skew; +}; + +struct mddi_panel_info { + __u32 vdopkt; +}; + +struct msm_panel_info { + __u32 xres; + __u32 yres; + __u32 bpp; + __u32 type; + __u32 wait_cycle; + DISP_TARGET_PHYS pdest; + __u32 bl_max; + __u32 bl_min; + __u32 fb_num; + __u32 clk_rate; + __u32 clk_min; + __u32 clk_max; + __u32 frame_count; + + union { + struct mddi_panel_info mddi; + }; + + union { + struct lcd_panel_info lcd; + struct lcdc_panel_info lcdc; + }; +}; + +struct msm_fb_panel_data { + struct msm_panel_info panel_info; + void (*set_rect) (int x, int y, int xres, int yres); + void (*set_vsync_notifier) (msm_fb_vsync_handler_type, void *arg); + void (*set_backlight) (struct msm_fb_data_type *); + + /* function entry chain */ + int (*on) (struct platform_device *pdev); + int (*off) (struct platform_device *pdev); + struct platform_device *next; +}; + +/*=========================================================================== + FUNCTIONS PROTOTYPES +============================================================================*/ +struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata, + u32 type, u32 id); +int panel_next_on(struct platform_device *pdev); +int panel_next_off(struct platform_device *pdev); + +int lcdc_device_register(struct msm_panel_info *pinfo); + +int mddi_toshiba_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel); + +#endif /* MSM_FB_PANEL_H */ diff --git a/drivers/staging/msm/msm_mdp.h b/drivers/staging/msm/msm_mdp.h new file mode 100644 index 000000000000..2d5323f5b62d --- /dev/null +++ b/drivers/staging/msm/msm_mdp.h @@ -0,0 +1,245 @@ +/* include/linux/msm_mdp.h + * + * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _MSM_MDP_H_ +#define _MSM_MDP_H_ + +#include <linux/types.h> +#include <linux/fb.h> + +#define MSMFB_IOCTL_MAGIC 'm' +#define MSMFB_GRP_DISP _IOW(MSMFB_IOCTL_MAGIC, 1, unsigned int) +#define MSMFB_BLIT _IOW(MSMFB_IOCTL_MAGIC, 2, unsigned int) +#define MSMFB_SUSPEND_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 128, unsigned int) +#define MSMFB_RESUME_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 129, unsigned int) +#define MSMFB_CURSOR _IOW(MSMFB_IOCTL_MAGIC, 130, struct fb_cursor) +#define MSMFB_SET_LUT _IOW(MSMFB_IOCTL_MAGIC, 131, struct fb_cmap) +#define MSMFB_HISTOGRAM _IOWR(MSMFB_IOCTL_MAGIC, 132, struct mdp_histogram) +/* new ioctls's for set/get ccs matrix */ +#define MSMFB_GET_CCS_MATRIX _IOWR(MSMFB_IOCTL_MAGIC, 133, struct mdp_ccs) +#define MSMFB_SET_CCS_MATRIX _IOW(MSMFB_IOCTL_MAGIC, 134, struct mdp_ccs) +#define MSMFB_OVERLAY_SET _IOWR(MSMFB_IOCTL_MAGIC, 135, \ + struct mdp_overlay) +#define MSMFB_OVERLAY_UNSET _IOW(MSMFB_IOCTL_MAGIC, 136, unsigned int) +#define MSMFB_OVERLAY_PLAY _IOW(MSMFB_IOCTL_MAGIC, 137, \ + struct msmfb_overlay_data) +#define MSMFB_GET_PAGE_PROTECTION _IOR(MSMFB_IOCTL_MAGIC, 138, \ + struct mdp_page_protection) +#define MSMFB_SET_PAGE_PROTECTION _IOW(MSMFB_IOCTL_MAGIC, 139, \ + struct mdp_page_protection) +#define MSMFB_OVERLAY_GET _IOR(MSMFB_IOCTL_MAGIC, 140, \ + struct mdp_overlay) + +/* new ioctls for async MDP ops */ +#define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 141, unsigned int) +#define MSMFB_BLIT_FLUSH _IOR(MSMFB_IOCTL_MAGIC, 142, unsigned int) + +#define MDP_IMGTYPE2_START 0x10000 + +enum { + MDP_RGB_565, /* RGB 565 planer */ + MDP_XRGB_8888, /* RGB 888 padded */ + MDP_Y_CBCR_H2V2, /* Y and CbCr, pseudo planer w/ Cb is in MSB */ + MDP_ARGB_8888, /* ARGB 888 */ + MDP_RGB_888, /* RGB 888 planer */ + MDP_Y_CRCB_H2V2, /* Y and CrCb, pseudo planer w/ Cr is in MSB */ + MDP_YCRYCB_H2V1, /* YCrYCb interleave */ + MDP_Y_CRCB_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */ + MDP_Y_CBCR_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */ + MDP_RGBA_8888, /* ARGB 888 */ + MDP_BGRA_8888, /* ABGR 888 */ + MDP_Y_CRCB_H2V2_TILE, /* Y and CrCb, pseudo planer tile */ + MDP_Y_CBCR_H2V2_TILE, /* Y and CbCr, pseudo planer tile */ + MDP_IMGTYPE_LIMIT, + MDP_BGR_565 = MDP_IMGTYPE2_START, /* BGR 565 planer */ + MDP_FB_FORMAT, /* framebuffer format */ + MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */ +}; + +enum { + PMEM_IMG, + FB_IMG, +}; + +/* mdp_blit_req flag values */ +#define MDP_ROT_NOP 0 +#define MDP_FLIP_LR 0x1 +#define MDP_FLIP_UD 0x2 +#define MDP_ROT_90 0x4 +#define MDP_ROT_180 (MDP_FLIP_UD|MDP_FLIP_LR) +#define MDP_ROT_270 (MDP_ROT_90|MDP_FLIP_UD|MDP_FLIP_LR) +#define MDP_DITHER 0x8 +#define MDP_BLUR 0x10 +#define MDP_BLEND_FG_PREMULT 0x20000 + +#define MDP_DEINTERLACE 0x80000000 +#define MDP_SHARPENING 0x40000000 + +#define MDP_NO_DMA_BARRIER_START 0x20000000 +#define MDP_NO_DMA_BARRIER_END 0x10000000 +#define MDP_NO_BLIT 0x08000000 +#define MDP_BLIT_WITH_DMA_BARRIERS 0x000 +#define MDP_BLIT_WITH_NO_DMA_BARRIERS \ + (MDP_NO_DMA_BARRIER_START | MDP_NO_DMA_BARRIER_END) +#define MDP_TRANSP_NOP 0xffffffff +#define MDP_ALPHA_NOP 0xff + +#define MDP_BLIT_SRC_GEM 0x02000000 /* set for GEM, clear for PMEM */ +#define MDP_BLIT_DST_GEM 0x01000000 /* set for GEM, clear for PMEM */ + +#define MDP_FB_PAGE_PROTECTION_NONCACHED (0) +#define MDP_FB_PAGE_PROTECTION_WRITECOMBINE (1) +#define MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE (2) +#define MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE (3) +#define MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE (4) +/* Sentinel: Don't use! */ +#define MDP_FB_PAGE_PROTECTION_INVALID (5) +/* Count of the number of MDP_FB_PAGE_PROTECTION_... values. */ +#define MDP_NUM_FB_PAGE_PROTECTION_VALUES (5) + +struct mdp_rect { + uint32_t x; + uint32_t y; + uint32_t w; + uint32_t h; +}; + +struct mdp_img { + uint32_t width; + uint32_t height; + uint32_t format; + uint32_t offset; + int memory_id; /* the file descriptor */ + uint32_t priv; +}; + +/* + * {3x3} + {3} ccs matrix + */ + +#define MDP_CCS_RGB2YUV 0 +#define MDP_CCS_YUV2RGB 1 + +#define MDP_CCS_SIZE 9 +#define MDP_BV_SIZE 3 + +struct mdp_ccs { + int direction; /* MDP_CCS_RGB2YUV or YUV2RGB */ + uint16_t ccs[MDP_CCS_SIZE]; /* 3x3 color coefficients */ + uint16_t bv[MDP_BV_SIZE]; /* 1x3 bias vector */ +}; + +/* The version of the mdp_blit_req structure so that + * user applications can selectively decide which functionality + * to include + */ + +#define MDP_BLIT_REQ_VERSION 2 + +struct mdp_blit_req { + struct mdp_img src; + struct mdp_img dst; + struct mdp_rect src_rect; + struct mdp_rect dst_rect; + uint32_t alpha; + uint32_t transp_mask; + uint32_t flags; + int sharpening_strength; /* -127 <--> 127, default 64 */ +}; + +struct mdp_blit_req_list { + uint32_t count; + struct mdp_blit_req req[]; +}; + +struct msmfb_data { + uint32_t offset; + int memory_id; + int id; +}; + +#define MSMFB_NEW_REQUEST -1 + +struct msmfb_overlay_data { + uint32_t id; + struct msmfb_data data; +}; + +struct msmfb_img { + uint32_t width; + uint32_t height; + uint32_t format; +}; + +struct mdp_overlay { + struct msmfb_img src; + struct mdp_rect src_rect; + struct mdp_rect dst_rect; + uint32_t z_order; /* stage number */ + uint32_t is_fg; /* control alpha & transp */ + uint32_t alpha; + uint32_t transp_mask; + uint32_t flags; + uint32_t id; + uint32_t user_data[8]; +}; + +struct mdp_histogram { + uint32_t frame_cnt; + uint32_t bin_cnt; + uint32_t *r; + uint32_t *g; + uint32_t *b; +}; + +struct mdp_page_protection { + uint32_t page_protection; +}; + + +struct msm_panel_common_pdata { + int gpio; + int (*backlight_level)(int level, int max, int min); + int (*pmic_backlight)(int level); + int (*panel_num)(void); + void (*panel_config_gpio)(int); + int *gpio_num; +}; + +struct lcdc_platform_data { + int (*lcdc_gpio_config)(int on); + void (*lcdc_power_save)(int); +}; + +struct tvenc_platform_data { + int (*pm_vid_en)(int on); +}; + +struct mddi_platform_data { + void (*mddi_power_save)(int on); + int (*mddi_sel_clk)(u32 *clk_rate); +}; + +struct msm_fb_platform_data { + int (*detect_client)(const char *name); + int mddi_prescan; + int (*allow_set_offset)(void); +}; + +struct msm_hdmi_platform_data { + int irq; + int (*cable_detect)(int insert); +}; + +#endif /*_MSM_MDP_H_*/ diff --git a/drivers/staging/msm/staging-devices.c b/drivers/staging/msm/staging-devices.c new file mode 100644 index 000000000000..0f8ec3e26013 --- /dev/null +++ b/drivers/staging/msm/staging-devices.c @@ -0,0 +1,323 @@ +#include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/bootmem.h> +#include <linux/delay.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/io.h> +#include <asm/setup.h> + +#include <mach/board.h> +#include <mach/irqs.h> +#include <mach/sirc.h> +#include <mach/gpio.h> + +#include "msm_mdp.h" +#include "memory_ll.h" +//#include "android_pmem.h" +#include <mach/board.h> + +#ifdef CONFIG_MSM_SOC_REV_A +#define MSM_SMI_BASE 0xE0000000 +#else +#define MSM_SMI_BASE 0x00000000 +#endif + + +#define TOUCHPAD_SUSPEND 34 +#define TOUCHPAD_IRQ 38 + +#define MSM_PMEM_MDP_SIZE 0x1591000 + +#ifdef CONFIG_MSM_SOC_REV_A +#define SMEM_SPINLOCK_I2C "D:I2C02000021" +#else +#define SMEM_SPINLOCK_I2C "S:6" +#endif + +#define MSM_PMEM_ADSP_SIZE 0x1C00000 + +#define MSM_FB_SIZE 0x500000 +#define MSM_FB_SIZE_ST15 0x800000 +#define MSM_AUDIO_SIZE 0x80000 +#define MSM_GPU_PHYS_SIZE SZ_2M + +#ifdef CONFIG_MSM_SOC_REV_A +#define MSM_SMI_BASE 0xE0000000 +#else +#define MSM_SMI_BASE 0x00000000 +#endif + +#define MSM_SHARED_RAM_PHYS (MSM_SMI_BASE + 0x00100000) + +#define MSM_PMEM_SMI_BASE (MSM_SMI_BASE + 0x02B00000) +#define MSM_PMEM_SMI_SIZE 0x01500000 + +#define MSM_FB_BASE MSM_PMEM_SMI_BASE +#define MSM_GPU_PHYS_BASE (MSM_FB_BASE + MSM_FB_SIZE) +#define MSM_PMEM_SMIPOOL_BASE (MSM_GPU_PHYS_BASE + MSM_GPU_PHYS_SIZE) +#define MSM_PMEM_SMIPOOL_SIZE (MSM_PMEM_SMI_SIZE - MSM_FB_SIZE \ + - MSM_GPU_PHYS_SIZE) + +#if defined(CONFIG_FB_MSM_MDP40) +#define MDP_BASE 0xA3F00000 +#define PMDH_BASE 0xAD600000 +#define EMDH_BASE 0xAD700000 +#define TVENC_BASE 0xAD400000 +#else +#define MDP_BASE 0xAA200000 +#define PMDH_BASE 0xAA600000 +#define EMDH_BASE 0xAA700000 +#define TVENC_BASE 0xAA400000 +#endif + +#define PMEM_KERNEL_EBI1_SIZE (CONFIG_PMEM_KERNEL_SIZE * 1024 * 1024) + +static struct resource msm_fb_resources[] = { + { + .flags = IORESOURCE_DMA, + } +}; + +static struct resource msm_mdp_resources[] = { + { + .name = "mdp", + .start = MDP_BASE, + .end = MDP_BASE + 0x000F0000 - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device msm_mdp_device = { + .name = "mdp", + .id = 0, + .num_resources = ARRAY_SIZE(msm_mdp_resources), + .resource = msm_mdp_resources, +}; + +static struct platform_device msm_lcdc_device = { + .name = "lcdc", + .id = 0, +}; + +static int msm_fb_detect_panel(const char *name) +{ + int ret = -EPERM; + + if (machine_is_qsd8x50_ffa() || machine_is_qsd8x50a_ffa()) { + if (!strncmp(name, "mddi_toshiba_wvga_pt", 20)) + ret = 0; + else + ret = -ENODEV; + } else if ((machine_is_qsd8x50_surf() || machine_is_qsd8x50a_surf()) + && !strcmp(name, "lcdc_external")) + ret = 0; + else if (0 /*machine_is_qsd8x50_grapefruit() */) { + if (!strcmp(name, "lcdc_grapefruit_vga")) + ret = 0; + else + ret = -ENODEV; + } else if (machine_is_qsd8x50_st1()) { + if (!strcmp(name, "lcdc_st1_wxga")) + ret = 0; + else + ret = -ENODEV; + } else if (machine_is_qsd8x50a_st1_5()) { + if (!strcmp(name, "lcdc_st15") || + !strcmp(name, "hdmi_sii9022")) + ret = 0; + else + ret = -ENODEV; + } + + return ret; +} + +/* Only allow a small subset of machines to set the offset via + FB PAN_DISPLAY */ + +static int msm_fb_allow_set_offset(void) +{ + return (machine_is_qsd8x50_st1() || + machine_is_qsd8x50a_st1_5()) ? 1 : 0; +} + + +static struct msm_fb_platform_data msm_fb_pdata = { + .detect_client = msm_fb_detect_panel, + .allow_set_offset = msm_fb_allow_set_offset, +}; + +static struct platform_device msm_fb_device = { + .name = "msm_fb", + .id = 0, + .num_resources = ARRAY_SIZE(msm_fb_resources), + .resource = msm_fb_resources, + .dev = { + .platform_data = &msm_fb_pdata, + } +}; + +static void __init qsd8x50_allocate_memory_regions(void) +{ + void *addr; + unsigned long size; + if (machine_is_qsd8x50a_st1_5()) + size = MSM_FB_SIZE_ST15; + else + size = MSM_FB_SIZE; + + addr = alloc_bootmem(size); // (void *)MSM_FB_BASE; + if (!addr) + printk("Failed to allocate bootmem for framebuffer\n"); + + + msm_fb_resources[0].start = __pa(addr); + msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1; + pr_info(KERN_ERR "using %lu bytes of SMI at %lx physical for fb\n", + size, (unsigned long)addr); +} + +static int msm_fb_lcdc_gpio_config(int on) +{ +// return 0; + if (machine_is_qsd8x50_st1()) { + if (on) { + gpio_set_value(32, 1); + mdelay(100); + gpio_set_value(20, 1); + gpio_set_value(17, 1); + gpio_set_value(19, 1); + } else { + gpio_set_value(17, 0); + gpio_set_value(19, 0); + gpio_set_value(20, 0); + mdelay(100); + gpio_set_value(32, 0); + } + } else if (machine_is_qsd8x50a_st1_5()) { + if (on) { + gpio_set_value(17, 1); + gpio_set_value(19, 1); + gpio_set_value(20, 1); + gpio_set_value(22, 0); + gpio_set_value(32, 1); + gpio_set_value(155, 1); + //st15_hdmi_power(1); + gpio_set_value(22, 1); + + } else { + gpio_set_value(17, 0); + gpio_set_value(19, 0); + gpio_set_value(22, 0); + gpio_set_value(32, 0); + gpio_set_value(155, 0); + // st15_hdmi_power(0); + } + } + return 0; +} + + +static struct lcdc_platform_data lcdc_pdata = { + .lcdc_gpio_config = msm_fb_lcdc_gpio_config, +}; + +static struct msm_gpio msm_fb_st15_gpio_config_data[] = { + { GPIO_CFG(17, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lcdc_en0" }, + { GPIO_CFG(19, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "dat_pwr_sv" }, + { GPIO_CFG(20, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lvds_pwr_dn" }, + { GPIO_CFG(22, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lcdc_en1" }, + { GPIO_CFG(32, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lcdc_en2" }, + { GPIO_CFG(103, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), "hdmi_irq" }, + { GPIO_CFG(155, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "hdmi_3v3" }, +}; + +static struct msm_panel_common_pdata mdp_pdata = { + .gpio = 98, +}; + +static struct platform_device *devices[] __initdata = { + &msm_fb_device, +}; + + +static void __init msm_register_device(struct platform_device *pdev, void *data) +{ + int ret; + + pdev->dev.platform_data = data; + + ret = platform_device_register(pdev); + if (ret) + dev_err(&pdev->dev, + "%s: platform_device_register() failed = %d\n", + __func__, ret); +} + +void __init msm_fb_register_device(char *name, void *data) +{ + if (!strncmp(name, "mdp", 3)) + msm_register_device(&msm_mdp_device, data); +/* + else if (!strncmp(name, "pmdh", 4)) + msm_register_device(&msm_mddi_device, data); + else if (!strncmp(name, "emdh", 4)) + msm_register_device(&msm_mddi_ext_device, data); + else if (!strncmp(name, "ebi2", 4)) + msm_register_device(&msm_ebi2_lcd_device, data); + else if (!strncmp(name, "tvenc", 5)) + msm_register_device(&msm_tvenc_device, data); + else */ + + if (!strncmp(name, "lcdc", 4)) + msm_register_device(&msm_lcdc_device, data); + /*else + printk(KERN_ERR "%s: unknown device! %s\n", __func__, name); +*/ +} + +static void __init msm_fb_add_devices(void) +{ + int rc; + msm_fb_register_device("mdp", &mdp_pdata); +// msm_fb_register_device("pmdh", &mddi_pdata); +// msm_fb_register_device("emdh", &mddi_pdata); +// msm_fb_register_device("tvenc", 0); + + if (machine_is_qsd8x50a_st1_5()) { +/* rc = st15_hdmi_vreg_init(); + if (rc) + return; +*/ + rc = msm_gpios_request_enable( + msm_fb_st15_gpio_config_data, + ARRAY_SIZE(msm_fb_st15_gpio_config_data)); + if (rc) { + printk(KERN_ERR "%s: unable to init lcdc gpios\n", + __func__); + return; + } + msm_fb_register_device("lcdc", &lcdc_pdata); + } else + msm_fb_register_device("lcdc", 0); +} + +int __init staging_init_pmem(void) +{ + qsd8x50_allocate_memory_regions(); + return 0; +} + +int __init staging_init_devices(void) +{ + platform_add_devices(devices, ARRAY_SIZE(devices)); + msm_fb_add_devices(); + return 0; +} + +arch_initcall(staging_init_pmem); +arch_initcall(staging_init_devices); diff --git a/drivers/staging/msm/tv_ntsc.c b/drivers/staging/msm/tv_ntsc.c new file mode 100644 index 000000000000..5eb67611661a --- /dev/null +++ b/drivers/staging/msm/tv_ntsc.c @@ -0,0 +1,163 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <linux/clk.h> + +#include "msm_fb.h" +#include "tvenc.h" + +#define NTSC_TV_DIMENSION_WIDTH 720 +#define NTSC_TV_DIMENSION_HEIGHT 480 + +static int ntsc_off(struct platform_device *pdev); +static int ntsc_on(struct platform_device *pdev); + +static int ntsc_on(struct platform_device *pdev) +{ + uint32 reg = 0; + int ret = 0; + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */ + + if (mfd->panel.id == NTSC_M) { + /* Cr gain 11, Cb gain C6, y_gain 97 */ + TV_OUT(TV_GAIN, 0x0081B697); + } else { + /* Cr gain 11, Cb gain C6, y_gain 97 */ + TV_OUT(TV_GAIN, 0x008bc4a3); + reg |= TVENC_CTL_NTSCJ_MODE; + } + + TV_OUT(TV_CGMS, 0x0); + /* NTSC Timing */ + TV_OUT(TV_SYNC_1, 0x0020009e); + TV_OUT(TV_SYNC_2, 0x011306B4); + TV_OUT(TV_SYNC_3, 0x0006000C); + TV_OUT(TV_SYNC_4, 0x0028020D); + TV_OUT(TV_SYNC_5, 0x005E02FB); + TV_OUT(TV_SYNC_6, 0x0006000C); + TV_OUT(TV_SYNC_7, 0x00000012); + TV_OUT(TV_BURST_V1, 0x0013020D); + TV_OUT(TV_BURST_V2, 0x0014020C); + TV_OUT(TV_BURST_V3, 0x0013020D); + TV_OUT(TV_BURST_V4, 0x0014020C); + TV_OUT(TV_BURST_H, 0x00AE00F2); + TV_OUT(TV_SOL_REQ_ODD, 0x00280208); + TV_OUT(TV_SOL_REQ_EVEN, 0x00290209); + + reg |= TVENC_CTL_TV_MODE_NTSC_M_PAL60; + + reg |= TVENC_CTL_Y_FILTER_EN | + TVENC_CTL_CR_FILTER_EN | + TVENC_CTL_CB_FILTER_EN | TVENC_CTL_SINX_FILTER_EN; +#ifdef CONFIG_FB_MSM_TVOUT_SVIDEO + reg |= TVENC_CTL_S_VIDEO_EN; +#endif + + TV_OUT(TV_LEVEL, 0x00000000); /* DC offset to 0. */ + TV_OUT(TV_OFFSET, 0x008080f0); + +#ifdef CONFIG_FB_MSM_MDP31 + TV_OUT(TV_DAC_INTF, 0x29); +#endif + TV_OUT(TV_ENC_CTL, reg); + + reg |= TVENC_CTL_ENC_EN; + TV_OUT(TV_ENC_CTL, reg); + + return ret; +} + +static int ntsc_off(struct platform_device *pdev) +{ + TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */ + return 0; +} + +static int __init ntsc_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = ntsc_probe, + .driver = { + .name = "tv_ntsc", + }, +}; + +static struct msm_fb_panel_data ntsc_panel_data = { + .panel_info.xres = NTSC_TV_DIMENSION_WIDTH, + .panel_info.yres = NTSC_TV_DIMENSION_HEIGHT, + .panel_info.type = TV_PANEL, + .panel_info.pdest = DISPLAY_1, + .panel_info.wait_cycle = 0, + .panel_info.bpp = 16, + .panel_info.fb_num = 2, + .on = ntsc_on, + .off = ntsc_off, +}; + +static struct platform_device this_device = { + .name = "tv_ntsc", + .id = 0, + .dev = { + .platform_data = &ntsc_panel_data, + } +}; + +static int __init ntsc_init(void) +{ + int ret; + + ret = platform_driver_register(&this_driver); + if (!ret) { + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(ntsc_init); \ No newline at end of file diff --git a/drivers/staging/msm/tv_pal.c b/drivers/staging/msm/tv_pal.c new file mode 100644 index 000000000000..204da514660e --- /dev/null +++ b/drivers/staging/msm/tv_pal.c @@ -0,0 +1,213 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <linux/clk.h> + +#include "msm_fb.h" +#include "tvenc.h" + +#ifdef CONFIG_FB_MSM_TVOUT_PAL_M +#define PAL_TV_DIMENSION_WIDTH 720 +#define PAL_TV_DIMENSION_HEIGHT 480 +#else +#define PAL_TV_DIMENSION_WIDTH 720 +#define PAL_TV_DIMENSION_HEIGHT 576 +#endif + +static int pal_on(struct platform_device *pdev) +{ + uint32 reg = 0; + int ret = 0; + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */ + + switch (mfd->panel.id) { + case PAL_BDGHIN: + /* Cr gain 11, Cb gain C6, y_gain 97 */ + TV_OUT(TV_GAIN, 0x0088c1a0); + TV_OUT(TV_CGMS, 0x00012345); + TV_OUT(TV_TEST_MUX, 0x0); + /* PAL Timing */ + TV_OUT(TV_SYNC_1, 0x00180097); + TV_OUT(TV_SYNC_2, 0x011f06c0); + TV_OUT(TV_SYNC_3, 0x0005000a); + TV_OUT(TV_SYNC_4, 0x00320271); + TV_OUT(TV_SYNC_5, 0x005602f9); + TV_OUT(TV_SYNC_6, 0x0005000a); + TV_OUT(TV_SYNC_7, 0x0000000f); + TV_OUT(TV_BURST_V1, 0x0012026e); + TV_OUT(TV_BURST_V2, 0x0011026d); + TV_OUT(TV_BURST_V3, 0x00100270); + TV_OUT(TV_BURST_V4, 0x0013026f); + TV_OUT(TV_BURST_H, 0x00af00ea); + TV_OUT(TV_SOL_REQ_ODD, 0x0030026e); + TV_OUT(TV_SOL_REQ_EVEN, 0x0031026f); + + reg |= TVENC_CTL_TV_MODE_PAL_BDGHIN; + break; + case PAL_M: + /* Cr gain 11, Cb gain C6, y_gain 97 */ + TV_OUT(TV_GAIN, 0x0081b697); + TV_OUT(TV_CGMS, 0x000af317); + TV_OUT(TV_TEST_MUX, 0x000001c3); + TV_OUT(TV_TEST_MODE, 0x00000002); + /* PAL Timing */ + TV_OUT(TV_SYNC_1, 0x0020009e); + TV_OUT(TV_SYNC_2, 0x011306b4); + TV_OUT(TV_SYNC_3, 0x0006000c); + TV_OUT(TV_SYNC_4, 0x0028020D); + TV_OUT(TV_SYNC_5, 0x005e02fb); + TV_OUT(TV_SYNC_6, 0x0006000c); + TV_OUT(TV_SYNC_7, 0x00000012); + TV_OUT(TV_BURST_V1, 0x0012020b); + TV_OUT(TV_BURST_V2, 0x0016020c); + TV_OUT(TV_BURST_V3, 0x00150209); + TV_OUT(TV_BURST_V4, 0x0013020c); + TV_OUT(TV_BURST_H, 0x00bf010b); + TV_OUT(TV_SOL_REQ_ODD, 0x00280208); + TV_OUT(TV_SOL_REQ_EVEN, 0x00290209); + + reg |= TVENC_CTL_TV_MODE_PAL_M; + break; + case PAL_N: + /* Cr gain 11, Cb gain C6, y_gain 97 */ + TV_OUT(TV_GAIN, 0x0081b697); + TV_OUT(TV_CGMS, 0x000af317); + TV_OUT(TV_TEST_MUX, 0x000001c3); + TV_OUT(TV_TEST_MODE, 0x00000002); + /* PAL Timing */ + TV_OUT(TV_SYNC_1, 0x00180097); + TV_OUT(TV_SYNC_2, 0x12006c0); + TV_OUT(TV_SYNC_3, 0x0005000a); + TV_OUT(TV_SYNC_4, 0x00320271); + TV_OUT(TV_SYNC_5, 0x005602f9); + TV_OUT(TV_SYNC_6, 0x0005000a); + TV_OUT(TV_SYNC_7, 0x0000000f); + TV_OUT(TV_BURST_V1, 0x0012026e); + TV_OUT(TV_BURST_V2, 0x0011026d); + TV_OUT(TV_BURST_V3, 0x00100270); + TV_OUT(TV_BURST_V4, 0x0013026f); + TV_OUT(TV_BURST_H, 0x00af00fa); + TV_OUT(TV_SOL_REQ_ODD, 0x0030026e); + TV_OUT(TV_SOL_REQ_EVEN, 0x0031026f); + + reg |= TVENC_CTL_TV_MODE_PAL_N; + break; + + default: + return -ENODEV; + } + + reg |= TVENC_CTL_Y_FILTER_EN | + TVENC_CTL_CR_FILTER_EN | + TVENC_CTL_CB_FILTER_EN | TVENC_CTL_SINX_FILTER_EN; +#ifdef CONFIG_FB_MSM_TVOUT_SVIDEO + reg |= TVENC_CTL_S_VIDEO_EN; +#endif + + TV_OUT(TV_LEVEL, 0x00000000); /* DC offset to 0. */ + TV_OUT(TV_OFFSET, 0x008080f0); + +#ifdef CONFIG_FB_MSM_MDP31 + TV_OUT(TV_DAC_INTF, 0x29); +#endif + TV_OUT(TV_ENC_CTL, reg); + + reg |= TVENC_CTL_ENC_EN; + TV_OUT(TV_ENC_CTL, reg); + + return ret; +} + +static int pal_off(struct platform_device *pdev) +{ + TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */ + return 0; +} + +static int __init pal_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = pal_probe, + .driver = { + .name = "tv_pal", + }, +}; + +static struct msm_fb_panel_data pal_panel_data = { + .panel_info.xres = PAL_TV_DIMENSION_WIDTH, + .panel_info.yres = PAL_TV_DIMENSION_HEIGHT, + .panel_info.type = TV_PANEL, + .panel_info.pdest = DISPLAY_1, + .panel_info.wait_cycle = 0, + .panel_info.bpp = 16, + .panel_info.fb_num = 2, + .on = pal_on, + .off = pal_off, +}; + +static struct platform_device this_device = { + .name = "tv_pal", + .id = 0, + .dev = { + .platform_data = &pal_panel_data, + } +}; + +static int __init pal_init(void) +{ + int ret; + + ret = platform_driver_register(&this_driver); + if (!ret) { + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(pal_init); diff --git a/drivers/staging/msm/tvenc.c b/drivers/staging/msm/tvenc.c new file mode 100644 index 000000000000..f41c5ac22f25 --- /dev/null +++ b/drivers/staging/msm/tvenc.c @@ -0,0 +1,295 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/pm_qos_params.h> + +#define TVENC_C +#include "tvenc.h" +#include "msm_fb.h" + +static int tvenc_probe(struct platform_device *pdev); +static int tvenc_remove(struct platform_device *pdev); + +static int tvenc_off(struct platform_device *pdev); +static int tvenc_on(struct platform_device *pdev); + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +static struct clk *tvenc_clk; +static struct clk *tvdac_clk; + +static struct platform_driver tvenc_driver = { + .probe = tvenc_probe, + .remove = tvenc_remove, + .suspend = NULL, +// .suspend_late = NULL, +// .resume_early = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "tvenc", + }, +}; + +static struct tvenc_platform_data *tvenc_pdata; + +static int tvenc_off(struct platform_device *pdev) +{ + int ret = 0; + + ret = panel_next_off(pdev); + + clk_disable(tvenc_clk); + clk_disable(tvdac_clk); + + if (tvenc_pdata && tvenc_pdata->pm_vid_en) + ret = tvenc_pdata->pm_vid_en(0); + + //pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc", + // PM_QOS_DEFAULT_VALUE); + + if (ret) + printk(KERN_ERR "%s: pm_vid_en(off) failed! %d\n", + __func__, ret); + + return ret; +} + +static int tvenc_on(struct platform_device *pdev) +{ + int ret = 0; + +// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc", +// 128000); + if (tvenc_pdata && tvenc_pdata->pm_vid_en) + ret = tvenc_pdata->pm_vid_en(1); + + if (ret) { + printk(KERN_ERR "%s: pm_vid_en(on) failed! %d\n", + __func__, ret); + return ret; + } + + clk_enable(tvenc_clk); + clk_enable(tvdac_clk); + + ret = panel_next_on(pdev); + + return ret; +} + +void tvenc_gen_test_pattern(struct msm_fb_data_type *mfd) +{ + uint32 reg = 0, i; + + reg = readl(MSM_TV_ENC_CTL); + reg |= TVENC_CTL_TEST_PATT_EN; + + for (i = 0; i < 3; i++) { + TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */ + + switch (i) { + /* + * TV Encoder - Color Bar Test Pattern + */ + case 0: + reg |= TVENC_CTL_TPG_CLRBAR; + break; + /* + * TV Encoder - Red Frame Test Pattern + */ + case 1: + reg |= TVENC_CTL_TPG_REDCLR; + break; + /* + * TV Encoder - Modulated Ramp Test Pattern + */ + default: + reg |= TVENC_CTL_TPG_MODRAMP; + break; + } + + TV_OUT(TV_ENC_CTL, reg); + mdelay(5000); + + switch (i) { + /* + * TV Encoder - Color Bar Test Pattern + */ + case 0: + reg &= ~TVENC_CTL_TPG_CLRBAR; + break; + /* + * TV Encoder - Red Frame Test Pattern + */ + case 1: + reg &= ~TVENC_CTL_TPG_REDCLR; + break; + /* + * TV Encoder - Modulated Ramp Test Pattern + */ + default: + reg &= ~TVENC_CTL_TPG_MODRAMP; + break; + } + } +} + +static int tvenc_resource_initialized; + +static int tvenc_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc; + + if (pdev->id == 0) { + tvenc_base = ioremap(pdev->resource[0].start, + pdev->resource[0].end - + pdev->resource[0].start + 1); + if (!tvenc_base) { + printk(KERN_ERR + "tvenc_base ioremap failed!\n"); + return -ENOMEM; + } + tvenc_pdata = pdev->dev.platform_data; + tvenc_resource_initialized = 1; + return 0; + } + + if (!tvenc_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + if (tvenc_base == NULL) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_TV; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "tvenc_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = mdp_dev->dev.platform_data; + pdata->on = tvenc_on; + pdata->off = tvenc_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + mfd->fb_imgType = MDP_YCRYCB_H2V1; + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto tvenc_probe_err; + + pdev_list[pdev_list_cnt++] = pdev; + return 0; + +tvenc_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int tvenc_remove(struct platform_device *pdev) +{ +// pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc"); + return 0; +} + +static int tvenc_register_driver(void) +{ + return platform_driver_register(&tvenc_driver); +} + +static int __init tvenc_driver_init(void) +{ + tvenc_clk = clk_get(NULL, "tv_enc_clk"); + tvdac_clk = clk_get(NULL, "tv_dac_clk"); + + if (IS_ERR(tvenc_clk)) { + printk(KERN_ERR "error: can't get tvenc_clk!\n"); + return IS_ERR(tvenc_clk); + } + + if (IS_ERR(tvdac_clk)) { + printk(KERN_ERR "error: can't get tvdac_clk!\n"); + return IS_ERR(tvdac_clk); + } + +// pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc", +// PM_QOS_DEFAULT_VALUE); + return tvenc_register_driver(); +} + +module_init(tvenc_driver_init); diff --git a/drivers/staging/msm/tvenc.h b/drivers/staging/msm/tvenc.h new file mode 100644 index 000000000000..a682dbebcf7d --- /dev/null +++ b/drivers/staging/msm/tvenc.h @@ -0,0 +1,117 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * + */ + +#ifndef TVENC_H +#define TVENC_H + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/fb.h> + +#include <mach/hardware.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/mach-types.h> + +#include "msm_fb_panel.h" + +#define NTSC_M 0 /* North America, Korea */ +#define NTSC_J 1 /* Japan */ +#define PAL_BDGHIN 2 /* Non-argentina PAL-N */ +#define PAL_M 3 /* PAL-M */ +#define PAL_N 4 /* Argentina PAL-N */ + +/* 3.57954545 Mhz */ +#define TVENC_CTL_TV_MODE_NTSC_M_PAL60 0 +/* 3.57961149 Mhz */ +#define TVENC_CTL_TV_MODE_PAL_M BIT(0) +/*non-Argintina = 4.3361875 Mhz */ +#define TVENC_CTL_TV_MODE_PAL_BDGHIN BIT(1) +/*Argentina = 3.582055625 Mhz */ +#define TVENC_CTL_TV_MODE_PAL_N (BIT(1)|BIT(0)) + +#define TVENC_CTL_ENC_EN BIT(2) +#define TVENC_CTL_CC_EN BIT(3) +#define TVENC_CTL_CGMS_EN BIT(4) +#define TVENC_CTL_MACRO_EN BIT(5) +#define TVENC_CTL_Y_FILTER_W_NOTCH BIT(6) +#define TVENC_CTL_Y_FILTER_WO_NOTCH 0 +#define TVENC_CTL_Y_FILTER_EN BIT(7) +#define TVENC_CTL_CR_FILTER_EN BIT(8) +#define TVENC_CTL_CB_FILTER_EN BIT(9) +#define TVENC_CTL_SINX_FILTER_EN BIT(10) +#define TVENC_CTL_TEST_PATT_EN BIT(11) +#define TVENC_CTL_OUTPUT_INV BIT(12) +#define TVENC_CTL_PAL60_MODE BIT(13) +#define TVENC_CTL_NTSCJ_MODE BIT(14) +#define TVENC_CTL_TPG_CLRBAR 0 +#define TVENC_CTL_TPG_MODRAMP BIT(15) +#define TVENC_CTL_TPG_REDCLR BIT(16) +#define TVENC_CTL_S_VIDEO_EN BIT(19) + +#ifdef TVENC_C +void *tvenc_base; +#else +extern void *tvenc_base; +#endif + +#define TV_OUT(reg, v) writel(v, tvenc_base + MSM_##reg) + +#define MSM_TV_ENC_CTL 0x00 +#define MSM_TV_LEVEL 0x04 +#define MSM_TV_GAIN 0x08 +#define MSM_TV_OFFSET 0x0c +#define MSM_TV_CGMS 0x10 +#define MSM_TV_SYNC_1 0x14 +#define MSM_TV_SYNC_2 0x18 +#define MSM_TV_SYNC_3 0x1c +#define MSM_TV_SYNC_4 0x20 +#define MSM_TV_SYNC_5 0x24 +#define MSM_TV_SYNC_6 0x28 +#define MSM_TV_SYNC_7 0x2c +#define MSM_TV_BURST_V1 0x30 +#define MSM_TV_BURST_V2 0x34 +#define MSM_TV_BURST_V3 0x38 +#define MSM_TV_BURST_V4 0x3c +#define MSM_TV_BURST_H 0x40 +#define MSM_TV_SOL_REQ_ODD 0x44 +#define MSM_TV_SOL_REQ_EVEN 0x48 +#define MSM_TV_DAC_CTL 0x4c +#define MSM_TV_TEST_MUX 0x50 +#define MSM_TV_TEST_MODE 0x54 +#define MSM_TV_TEST_MISR_RESET 0x58 +#define MSM_TV_TEST_EXPORT_MISR 0x5c +#define MSM_TV_TEST_MISR_CURR_VAL 0x60 +#define MSM_TV_TEST_SOF_CFG 0x64 +#define MSM_TV_DAC_INTF 0x100 + +#endif /* TVENC_H */ -- GitLab From 5f411a90ee163801434775264b4f9932f1de9e4c Mon Sep 17 00:00:00 2001 From: Marek Lindner <lindner_marek@yahoo.de> Date: Sat, 22 May 2010 17:48:44 +0200 Subject: [PATCH 648/842] Staging: batman-adv: fix rogue packets on shutdown On module shutdown batman-adv would purge the internal packet queue by sending all remaining packets which could confuse other nodes. Now, the packets are silently discarded. Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/batman-adv/send.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c index d8536e277a26..ac69ed871a76 100644 --- a/drivers/staging/batman-adv/send.c +++ b/drivers/staging/batman-adv/send.c @@ -440,6 +440,9 @@ void send_outstanding_bcast_packet(struct work_struct *work) hlist_del(&forw_packet->list); spin_unlock_irqrestore(&forw_bcast_list_lock, flags); + if (atomic_read(&module_state) == MODULE_DEACTIVATING) + goto out; + /* rebroadcast packet */ rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) { @@ -453,15 +456,15 @@ void send_outstanding_bcast_packet(struct work_struct *work) forw_packet->num_packets++; - /* if we still have some more bcasts to send and we are not shutting - * down */ - if ((forw_packet->num_packets < 3) && - (atomic_read(&module_state) != MODULE_DEACTIVATING)) + /* if we still have some more bcasts to send */ + if (forw_packet->num_packets < 3) { _add_bcast_packet_to_list(forw_packet, ((5 * HZ) / 1000)); - else { - forw_packet_free(forw_packet); - atomic_inc(&bcast_queue_left); + return; } + +out: + forw_packet_free(forw_packet); + atomic_inc(&bcast_queue_left); } void send_outstanding_bat_packet(struct work_struct *work) @@ -476,6 +479,9 @@ void send_outstanding_bat_packet(struct work_struct *work) hlist_del(&forw_packet->list); spin_unlock_irqrestore(&forw_bat_list_lock, flags); + if (atomic_read(&module_state) == MODULE_DEACTIVATING) + goto out; + send_packet(forw_packet); /** @@ -483,10 +489,10 @@ void send_outstanding_bat_packet(struct work_struct *work) * to determine the queues wake up time unless we are * shutting down */ - if ((forw_packet->own) && - (atomic_read(&module_state) != MODULE_DEACTIVATING)) + if (forw_packet->own) schedule_own_packet(forw_packet->if_incoming); +out: /* don't count own packet */ if (!forw_packet->own) atomic_inc(&batman_queue_left); -- GitLab From 20c8a44b7cd5e56b62898a87f620b3a7269eb898 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann <sven.eckelmann@gmx.de> Date: Sat, 22 May 2010 17:48:45 +0200 Subject: [PATCH 649/842] Staging: batman-adv: Call unregister_netdev on failures to get rtnl lock We must call unregister_netdev when we couldn't initialise the batman-adv module and the soft_device was registered. There are two version of the function which we can use: * unregister_netdevice - removes device * unregister_netdev - takes rtnl semaphore and remove device We don't hold the semaphore in an error situation. So we must use unregister_netdev. Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/batman-adv/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index 9d13979c2d8e..50a66b42d476 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -127,7 +127,7 @@ int init_module(void) return 0; unreg_soft_device: - unregister_netdevice(soft_device); + unregister_netdev(soft_device); free_soft_device: free_netdev(soft_device); soft_device = NULL; -- GitLab From 3d9b2358930a3e5225b28ac1458236f3d667e368 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann <sven.eckelmann@gmx.de> Date: Sat, 22 May 2010 17:48:46 +0200 Subject: [PATCH 650/842] Staging: batman-adv: Don't call free_netdev twice Free_netdev is registered as destructor in interface_setup for every soft_device. This destructor is automatically called from unregister_netdev and we must not call it again for the freed net_device. Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/batman-adv/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index 50a66b42d476..74c70d589a93 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -128,6 +128,9 @@ int init_module(void) unreg_soft_device: unregister_netdev(soft_device); + soft_device = NULL; + return -ENOMEM; + free_soft_device: free_netdev(soft_device); soft_device = NULL; -- GitLab From 0375fc4d2748b7c7064d481b36e32ef19e43d8db Mon Sep 17 00:00:00 2001 From: Sven Eckelmann <sven.eckelmann@gmx.de> Date: Sat, 22 May 2010 17:48:47 +0200 Subject: [PATCH 651/842] Staging: batman-adv: Don't allocate icmp packet with GFP_KERNEL A new buffer for a packet is created when a icmp packet is received. This happens in a context with disabled irq. Thus we are not allowed to sleep or call function which might sleep. kmalloc must be called with GFP_ATOMIC instead of GFP_KERNEL to ensure that it does not sleep. Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/batman-adv/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/batman-adv/device.c b/drivers/staging/batman-adv/device.c index ad82ec4a4856..7eb6559e0315 100644 --- a/drivers/staging/batman-adv/device.c +++ b/drivers/staging/batman-adv/device.c @@ -309,7 +309,7 @@ void bat_device_add_packet(struct device_client *device_client, struct device_packet *device_packet; unsigned long flags; - device_packet = kmalloc(sizeof(struct device_packet), GFP_KERNEL); + device_packet = kmalloc(sizeof(struct device_packet), GFP_ATOMIC); if (!device_packet) return; -- GitLab From 08a16d9f0effe8b7fd31995a7bd418a45ef2d6e7 Mon Sep 17 00:00:00 2001 From: Mike Frysinger <vapier@gentoo.org> Date: Mon, 24 May 2010 00:55:41 -0400 Subject: [PATCH 652/842] Staging: adis16255: fix typo in Kconfig Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/adis16255/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/adis16255/Kconfig b/drivers/staging/adis16255/Kconfig index a642be66adea..a883c1f4478b 100644 --- a/drivers/staging/adis16255/Kconfig +++ b/drivers/staging/adis16255/Kconfig @@ -1,5 +1,5 @@ config ADIS16255 - tristate "Ananlog Devices ADIS16250/16255" + tristate "Analog Devices ADIS16250/16255" depends on SPI && SYSFS ---help--- If you say yes here you get support for the Analog Devices -- GitLab From c3dee74f52bb844db40865dae3c465212c6a09eb Mon Sep 17 00:00:00 2001 From: Mike Frysinger <vapier@gentoo.org> Date: Mon, 24 May 2010 00:55:42 -0400 Subject: [PATCH 653/842] Staging: adis16255: add proper section markings to hotplug funcs Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/adis16255/adis16255.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/adis16255/adis16255.c b/drivers/staging/adis16255/adis16255.c index 1ba11f00b2e7..55d66e290f7d 100644 --- a/drivers/staging/adis16255/adis16255.c +++ b/drivers/staging/adis16255/adis16255.c @@ -361,7 +361,7 @@ err: /*-------------------------------------------------------------------------*/ -static int spi_adis16255_probe(struct spi_device *spi) +static int __devinit spi_adis16255_probe(struct spi_device *spi) { struct adis16255_init_data *init_data = spi->dev.platform_data; @@ -421,7 +421,7 @@ err: return status; } -static int spi_adis16255_remove(struct spi_device *spi) +static int __devexit spi_adis16255_remove(struct spi_device *spi) { struct spi_adis16255_data *spiadis = dev_get_drvdata(&spi->dev); -- GitLab From b6ee30a27f8204d20aebe6e743e38d4b85ee753d Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Tue, 25 May 2010 17:40:04 +0800 Subject: [PATCH 654/842] Staging: iio-utils: fix memory overflow for dynamically allocateded memory to hold filename Signed-off-by: Barry Song <21cnbao@gmail.com> Acked-by: Jonathan Cameron <jic23@cam.ac.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/iio/Documentation/iio_utils.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h index a4555e6f133f..014f6684faba 100644 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ b/drivers/staging/iio/Documentation/iio_utils.h @@ -62,9 +62,8 @@ inline int find_type_by_name(const char *name, const char *type) 1) != 0) { filename = malloc(strlen(iio_dir) + strlen(type) - + 1 + numstrlen - + 1); + + 6); if (filename == NULL) return -ENOMEM; sprintf(filename, "%s%s%d/name", -- GitLab From c28040e515154462971ba97ec14a82c27fcfb683 Mon Sep 17 00:00:00 2001 From: Randy Dunlap <randy.dunlap@oracle.com> Date: Wed, 26 May 2010 10:30:02 -0700 Subject: [PATCH 655/842] Staging: phison: depends on ATA_BMDMA phison uses interfaces and data that are built only when ATA_BMDMA is enabled, so it should depend on that symbol. drivers/staging/phison/phison.c:43: error: implicit declaration of function 'ATA_BMDMA_SHT' drivers/staging/phison/phison.c:43: error: initializer element is not constant drivers/staging/phison/phison.c:43: error: (near initialization for 'phison_sht.module') drivers/staging/phison/phison.c:47: error: 'ata_bmdma_port_ops' undeclared here (not in a function) Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Cc: evan_ko@phison.com Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/phison/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/phison/Kconfig b/drivers/staging/phison/Kconfig index d3c65d315a2e..1b56119a7657 100644 --- a/drivers/staging/phison/Kconfig +++ b/drivers/staging/phison/Kconfig @@ -1,5 +1,5 @@ config IDE_PHISON tristate "PCIE ATA PS5000 IDE support" - depends on PCI && ATA && ATA_SFF + depends on PCI && ATA && ATA_SFF && ATA_BMDMA ---help--- This is an experimental driver for PS5000 IDE driver. -- GitLab From f502cb6eb28e55c19cea9c2005661c7898f2de99 Mon Sep 17 00:00:00 2001 From: Henk de Groot <henk.de.groot@hetnet.nl> Date: Wed, 2 Jun 2010 21:30:00 +0200 Subject: [PATCH 656/842] Staging: wlags49_h2, wlags49_h25: fixed Kconfig dependencies Fixes Kconfig so the wlags49_h2 and wlags49_h25 drivers can be selected from menuconfig without having to select another WLAN driver first. Before it could only be selected when another driver already selected WIRELESS_EXT. Also adds WEXT_PRIV on which the driver also depends. Align help text in Kconfig. Signed-off-by: Henk de Groot <pe1dnn@amsat.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/wlags49_h2/Kconfig | 12 +++++++----- drivers/staging/wlags49_h25/Kconfig | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/staging/wlags49_h2/Kconfig b/drivers/staging/wlags49_h2/Kconfig index b6fc2ca7d85c..3efcbf8afedf 100644 --- a/drivers/staging/wlags49_h2/Kconfig +++ b/drivers/staging/wlags49_h2/Kconfig @@ -1,9 +1,11 @@ config WLAGS49_H2 tristate "Agere Systems HERMES II Wireless PC Card Model 0110" - depends on WLAN && WIRELESS_EXT && PCMCIA + depends on WLAN && PCMCIA + select WIRELESS_EXT select WEXT_SPY + select WEXT_PRIV ---help--- - Driver for wireless cards using Agere's HERMES II chipset - which are identified with Manufacture ID: 0156,0003 - The software is a modified version of wl_lkm_722_abg.tar.gz - from the Agere Systems website, addapted for Ubuntu 9.04. + Driver for wireless cards using Agere's HERMES II chipset + which are identified with Manufacture ID: 0156,0003 + The software is a modified version of wl_lkm_722_abg.tar.gz + from the Agere Systems website, addapted for Ubuntu 9.04. diff --git a/drivers/staging/wlags49_h25/Kconfig b/drivers/staging/wlags49_h25/Kconfig index dcc170929c13..bf5664a51cd4 100644 --- a/drivers/staging/wlags49_h25/Kconfig +++ b/drivers/staging/wlags49_h25/Kconfig @@ -1,9 +1,11 @@ config WLAGS49_H25 tristate "Linksys HERMES II.5 WCF54G_Wireless-G_CompactFlash_Card" - depends on WLAN && WIRELESS_EXT && PCMCIA + depends on WLAN && PCMCIA + select WIRELESS_EXT select WEXT_SPY + select WEXT_PRIV ---help--- - Driver for wireless cards using Agere's HERMES II.5 chipset - which are identified with Manufacture ID: 0156,0004 - The software is a modified version of wl_lkm_722_abg.tar.gz - from the Agere Systems website, addapted for Ubuntu 9.04. + Driver for wireless cards using Agere's HERMES II.5 chipset + which are identified with Manufacture ID: 0156,0004 + The software is a modified version of wl_lkm_722_abg.tar.gz + from the Agere Systems website, addapted for Ubuntu 9.04. -- GitLab From 7f00b36e9e7d2026d546d61e0b1a62949617fee0 Mon Sep 17 00:00:00 2001 From: Alexander Kurz <linux@blala.de> Date: Thu, 3 Jun 2010 15:50:24 +0400 Subject: [PATCH 657/842] Staging: comedi: fixing ni_labpc to mite dependancy the dependancy of ni_labpc on mite was missing, Signed-off-by: Alexander Kurz <linux@kbdbabel.org> Acked-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> index 0aa2b0d..79f5f2e 100644 --- drivers/staging/comedi/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 2614c3f87244..aad47326d6dc 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -1281,6 +1281,7 @@ config COMEDI_NI_TIO config COMEDI_NI_LABPC tristate "NI Lab-PC and compatibles ISA and PCI support" + depends on COMEDI_MITE select COMEDI_8255 select COMEDI_FC default N -- GitLab From ebe8622342f12bed387f7de4b5fb7c52005ccb29 Mon Sep 17 00:00:00 2001 From: Martin Homuth-Rosemann <homuth-rosemann@gmx.net> Date: Mon, 31 May 2010 22:33:04 +0200 Subject: [PATCH 658/842] Staging: comedi - correct parameter gainlkup for DAQCard-6024E in driver ni_mio_cs.c Correct at least one of the incorrect specs for a national instrument data acquisition card DAQCard-6024E. This card has only four different gain settings (+-10V, +-5V, +-0.5V, +-0.05V). Signed-off-by: Martin Homuth-Rosemann <homuth-rosemann@gmx.net> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/drivers/ni_mio_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index cedb02d40f95..3a46f0c0bff9 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -123,7 +123,7 @@ static const struct ni_board_struct ni_boards[] = { .adbits = 12, .ai_fifo_depth = 1024, .alwaysdither = 0, - .gainlkup = ai_gain_16, + .gainlkup = ai_gain_4, .ai_speed = 5000, .n_aochan = 2, .aobits = 12, -- GitLab From 0aa3f139cd5123ffb8f397b91d777635e9761c24 Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Sun, 30 May 2010 22:27:46 +0200 Subject: [PATCH 659/842] staging: Use GFP_ATOMIC when a lock is held In each case, the containing function is only called from one place, where a spin lock is held. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // <smpl> @gfp exists@ identifier fn; position p; @@ fn(...) { ... when != spin_unlock when any GFP_KERNEL@p ... when any } @locked@ identifier gfp.fn; @@ spin_lock(...) ... when != spin_unlock fn(...) @depends on locked@ position gfp.p; @@ - GFP_KERNEL@p + GFP_ATOMIC // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Cc: Jonathan Cameron <jic23@cam.ac.uk> Cc: Marek Lindner <lindner_marek@yahoo.de> Cc: Martyn Welch <martyn.welch@ge.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/iio/ring_sw.c | 2 +- drivers/staging/vme/bridges/vme_ca91cx42.c | 2 +- drivers/staging/vme/bridges/vme_tsi148.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c index 1f14cd4770e7..294272d0619f 100644 --- a/drivers/staging/iio/ring_sw.c +++ b/drivers/staging/iio/ring_sw.c @@ -20,7 +20,7 @@ static inline int __iio_allocate_sw_ring_buffer(struct iio_sw_ring_buffer *ring, if ((length == 0) || (bytes_per_datum == 0)) return -EINVAL; __iio_update_ring_buffer(&ring->buf, bytes_per_datum, length); - ring->data = kmalloc(length*ring->buf.bpd, GFP_KERNEL); + ring->data = kmalloc(length*ring->buf.bpd, GFP_ATOMIC); ring->read_p = NULL; ring->write_p = NULL; ring->last_written_p = NULL; diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c index 0c82eb47a28d..0f9ea58ff717 100644 --- a/drivers/staging/vme/bridges/vme_ca91cx42.c +++ b/drivers/staging/vme/bridges/vme_ca91cx42.c @@ -523,7 +523,7 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image, } if (image->bus_resource.name == NULL) { - image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL); + image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC); if (image->bus_resource.name == NULL) { dev_err(ca91cx42_bridge->parent, "Unable to allocate " "memory for resource name\n"); diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index abe88a380b72..f09cac163139 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -828,7 +828,7 @@ static int tsi148_alloc_resource(struct vme_master_resource *image, return 0; if (image->bus_resource.name == NULL) { - image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL); + image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC); if (image->bus_resource.name == NULL) { dev_err(tsi148_bridge->parent, "Unable to allocate " "memory for resource name\n"); -- GitLab From c60e55f30a4dac15db51b398c3bd94e4cfbf743a Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Thu, 27 May 2010 14:37:19 +0200 Subject: [PATCH 660/842] Staging: Eliminate a NULL pointer dereference Eliminate a NULL or near NULL pointer dereference. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @r exists@ expression E,E1; identifier f; statement S1,S2,S3; @@ if ((E == NULL && ...) || ...) { ... when != if (...) S1 else S2 when != E = E1 * E->f ... when any return ...; } else S3 // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/comedi/drivers/usbdux.c | 3 +-- drivers/staging/dt3155/allocator.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 86f035d00675..27b4cb2e2ec2 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -351,8 +351,7 @@ static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink) int ret = 0; if (!this_usbduxsub) { - dev_err(&this_usbduxsub->interface->dev, - "comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n"); + pr_err("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n"); return -EFAULT; } dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_stop\n"); diff --git a/drivers/staging/dt3155/allocator.c b/drivers/staging/dt3155/allocator.c index bd5adbc2a238..d33947b0378f 100644 --- a/drivers/staging/dt3155/allocator.c +++ b/drivers/staging/dt3155/allocator.c @@ -176,9 +176,7 @@ int allocator_free_dma(unsigned long address) prev = ptr; ptr = ptr->next; if (!ptr) { - printk(KERN_ERR ALL_MSG - "free_dma(0x%08lx) but add. not allocated\n", - ptr->address); + pr_err(ALL_MSG "free_dma but add. not allocated\n"); return -EINVAL; } PDEBUGG("freeing: %08lx (%li) next %08lx\n", ptr->address, ptr->size, -- GitLab From 2d98bb22c33b033182edd3a3c6b4c4e1d091db4d Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Fri, 4 Jun 2010 12:39:51 +0200 Subject: [PATCH 661/842] Staging: rc2860: return -EFAULT on copy_to_user errors copy_to_user() returns the number of bytes remaining but we want to return a negative error code. This is in the ioctl handler and the error code gets passed to userspace. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/rt2860/sta_ioctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/rt2860/sta_ioctl.c b/drivers/staging/rt2860/sta_ioctl.c index 112da7a6c417..6b8268d3dc75 100644 --- a/drivers/staging/rt2860/sta_ioctl.c +++ b/drivers/staging/rt2860/sta_ioctl.c @@ -2522,6 +2522,8 @@ int rt28xx_sta_ioctl(IN struct net_device *net_dev, Status = copy_to_user(erq->pointer, pAd->nickname, erq->length); + if (Status) + Status = -EFAULT; break; } case SIOCGIWRATE: /*get default bit rate (bps) */ -- GitLab From 640f7dcfe047aa5859df5f5d41e7f6455a442b89 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Fri, 4 Jun 2010 12:38:40 +0200 Subject: [PATCH 662/842] Staging: sep: return -EFAULT on copy_to_user errors copy_to_user() returns the number of bytes remaining but we want to return a negative error code here. These functions are used in the ioctl handler and the error code gets returned to userspace. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/staging/sep/sep_driver.c | 52 ++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 0332c370fd82..ecbde3467b1b 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -594,8 +594,10 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, dbg("SEP Driver:--------> sep_allocate_data_pool_memory_handler start\n"); error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_alloc_t)); - if (error) + if (error) { + error = -EFAULT; goto end_function; + } /* allocate memory */ if ((sep->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { @@ -609,8 +611,10 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, /* write the memory back to the user space */ error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_alloc_t)); - if (error) + if (error) { + error = -EFAULT; goto end_function; + } /* set the allocation */ sep->data_pool_bytes_allocated += command_args.num_bytes; @@ -661,6 +665,8 @@ static int sep_write_into_data_pool_handler(struct sep_device *sep, unsigned lon } /* copy the application data */ error = copy_from_user(virt_address, (void *) app_in_address, num_bytes); + if (error) + error = -EFAULT; end_function: dbg("SEP Driver:<-------- sep_write_into_data_pool_handler end\n"); return error; @@ -711,6 +717,8 @@ static int sep_read_from_data_pool_handler(struct sep_device *sep, unsigned long /* copy the application data */ error = copy_to_user((void *) app_out_address, virt_address, num_bytes); + if (error) + error = -EFAULT; end_function: dbg("SEP Driver:<-------- sep_read_from_data_pool_handler end\n"); return error; @@ -1448,8 +1456,10 @@ static int sep_create_sync_dma_tables_handler(struct sep_device *sep, dbg("SEP Driver:--------> sep_create_sync_dma_tables_handler start\n"); error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_sync_table_t)); - if (error) + if (error) { + error = -EFAULT; goto end_function; + } edbg("app_in_address is %08lx\n", command_args.app_in_address); edbg("app_out_address is %08lx\n", command_args.app_out_address); @@ -1799,8 +1809,10 @@ static int sep_create_flow_dma_tables_handler(struct sep_device *sep, goto end_function; error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_flow_table_t)); - if (error) + if (error) { + error = -EFAULT; goto end_function; + } /* create flow tables */ error = sep_prepare_flow_dma_tables(sep, command_args.num_virtual_buffers, command_args.virt_buff_data_addr, flow_context_ptr, &first_table_data, &last_table_data, command_args.isKernelVirtualAddress); @@ -1819,8 +1831,10 @@ static int sep_create_flow_dma_tables_handler(struct sep_device *sep, /* send the parameters to user application */ error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_build_flow_table_t)); - if (error) + if (error) { + error = -EFAULT; goto end_function_with_error; + } /* all the flow created - update the flow entry with temp id */ flow_context_ptr->flow_id = SEP_TEMP_FLOW_ID; @@ -1861,8 +1875,10 @@ static int sep_add_flow_tables_handler(struct sep_device *sep, unsigned long arg /* get input parameters */ error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_flow_table_t)); - if (error) + if (error) { + error = -EFAULT; goto end_function; + } /* find the flow structure for the flow id */ flow_context_ptr = sep_find_flow_context(sep, command_args.flow_id); @@ -1933,6 +1949,8 @@ static int sep_add_flow_tables_handler(struct sep_device *sep, unsigned long arg /* send the parameters to user application */ error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_add_flow_table_t)); + if (error) + error = -EFAULT; end_function_with_error: /* free the allocated tables */ sep_deallocated_flow_tables(&first_table_data); @@ -1953,8 +1971,10 @@ static int sep_add_flow_tables_message_handler(struct sep_device *sep, unsigned dbg("SEP Driver:--------> sep_add_flow_tables_message_handler start\n"); error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_message_t)); - if (error) + if (error) { + error = -EFAULT; goto end_function; + } /* check input */ if (command_args.message_size_in_bytes > SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES) { @@ -1970,6 +1990,8 @@ static int sep_add_flow_tables_message_handler(struct sep_device *sep, unsigned /* copy the message into context */ flow_context_ptr->message_size_in_bytes = command_args.message_size_in_bytes; error = copy_from_user(flow_context_ptr->message, (void *) command_args.message_address, command_args.message_size_in_bytes); + if (error) + error = -EFAULT; end_function: dbg("SEP Driver:<-------- sep_add_flow_tables_message_handler end\n"); return error; @@ -1994,6 +2016,8 @@ static int sep_get_static_pool_addr_handler(struct sep_device *sep, unsigned lon /* send the parameters to user application */ error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_static_pool_addr_t)); + if (error) + error = -EFAULT; dbg("SEP Driver:<-------- sep_get_static_pool_addr_handler end\n"); return error; } @@ -2010,8 +2034,10 @@ static int sep_get_physical_mapped_offset_handler(struct sep_device *sep, unsign dbg("SEP Driver:--------> sep_get_physical_mapped_offset_handler start\n"); error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_get_mapped_offset_t)); - if (error) + if (error) { + error = -EFAULT; goto end_function; + } if (command_args.physical_address < sep->shared_bus) { error = -EINVAL; @@ -2025,6 +2051,8 @@ static int sep_get_physical_mapped_offset_handler(struct sep_device *sep, unsign /* send the parameters to user application */ error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_get_mapped_offset_t)); + if (error) + error = -EFAULT; end_function: dbg("SEP Driver:<-------- sep_get_physical_mapped_offset_handler end\n"); return error; @@ -2070,11 +2098,11 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg) error = 0; error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_init_t)); - - dbg("SEP Driver:--------> sep_init_handler - finished copy_from_user \n"); - - if (error) + if (error) { + error = -EFAULT; goto end_function; + } + dbg("SEP Driver:--------> sep_init_handler - finished copy_from_user\n"); /* PATCH - configure the DMA to single -burst instead of multi-burst */ /*sep_configure_dma_burst(); */ -- GitLab From 0abbb609ac511fc226b8b1082613193c8ecf8324 Mon Sep 17 00:00:00 2001 From: Al Viro <viro@zeniv.linux.org.uk> Date: Fri, 28 May 2010 19:06:15 -0400 Subject: [PATCH 663/842] mqueue doesn't need make_bad_inode() It never hashes them anyway and does final iput() immediately afterwards. With ->drop_inode() being generic_delete_inode()... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- ipc/mqueue.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 5108232f93d4..c93fd3faac2d 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -176,7 +176,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, } return inode; out_inode: - make_bad_inode(inode); iput(inode); return NULL; } -- GitLab From 971b2e8a3f5dc0cbef19ec1a77b6d20237aa751e Mon Sep 17 00:00:00 2001 From: Al Viro <viro@zeniv.linux.org.uk> Date: Fri, 28 May 2010 21:32:44 -0400 Subject: [PATCH 664/842] fix the deadlock in qib_fs get_sb_single() calls fill_super with superblock locked; calling deactivate_super() will deadlock immedately. Moreover, if fill_super callback returns an error, get_sb_single() will release the reference to superblock itself just fine. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- drivers/infiniband/hw/qib/qib_fs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index edef8527eb34..844954bf417b 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -542,10 +542,8 @@ static int qibfs_fill_super(struct super_block *sb, void *data, int silent) list_for_each_entry_safe(dd, tmp, &qib_dev_list, list) { spin_unlock_irqrestore(&qib_devs_lock, flags); ret = add_cntr_files(sb, dd); - if (ret) { - deactivate_super(sb); + if (ret) goto bail; - } spin_lock_irqsave(&qib_devs_lock, flags); } -- GitLab From 7d683a09990ff095a91b6e724ecee0ff8733274a Mon Sep 17 00:00:00 2001 From: Roberto Sassu <roberto.sassu@polito.it> Date: Thu, 3 Jun 2010 11:58:28 +0200 Subject: [PATCH 665/842] wrong type for 'magic' argument in simple_fill_super() It's used to superblock ->s_magic, which is unsigned long. Signed-off-by: Roberto Sassu <roberto.sassu@polito.it> Reviewed-by: Mimi Zohar <zohar@us.ibm.com> Signed-off-by: Eric Paris <eparis@redhat.com> CC: stable@kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- fs/libfs.c | 3 ++- include/linux/fs.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/libfs.c b/fs/libfs.c index 09e1016eb774..dcaf972cbf1b 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -489,7 +489,8 @@ int simple_write_end(struct file *file, struct address_space *mapping, * unique inode values later for this filesystem, then you must take care * to pass it an appropriate max_reserved value to avoid collisions. */ -int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files) +int simple_fill_super(struct super_block *s, unsigned long magic, + struct tree_descr *files) { struct inode *inode; struct dentry *root; diff --git a/include/linux/fs.h b/include/linux/fs.h index 3428393942a6..471e1ff5079a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2388,7 +2388,7 @@ extern const struct file_operations simple_dir_operations; extern const struct inode_operations simple_dir_inode_operations; struct tree_descr { char *name; const struct file_operations *ops; int mode; }; struct dentry *d_alloc_name(struct dentry *, const char *); -extern int simple_fill_super(struct super_block *, int, struct tree_descr *); +extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *); extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count); extern void simple_release_fs(struct vfsmount **mount, int *count); -- GitLab From 5b54470daded19d83ea2bbf5f6bc12662942cd63 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Thu, 3 Jun 2010 12:35:42 +0200 Subject: [PATCH 666/842] fcntl: return -EFAULT if copy_to_user fails copy_to_user() returns the number of bytes remaining, but we want to return -EFAULT. ret = fcntl(fd, F_SETOWN_EX, NULL); With the original code ret would be 8 here. V2: Takuya Yoshikawa pointed out a similar issue in f_getown_ex() Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- fs/fcntl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/fcntl.c b/fs/fcntl.c index f74d270ba155..51e11bf5708f 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -274,7 +274,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg) ret = copy_from_user(&owner, owner_p, sizeof(owner)); if (ret) - return ret; + return -EFAULT; switch (owner.type) { case F_OWNER_TID: @@ -332,8 +332,11 @@ static int f_getown_ex(struct file *filp, unsigned long arg) } read_unlock(&filp->f_owner.lock); - if (!ret) + if (!ret) { ret = copy_to_user(owner_p, &owner, sizeof(owner)); + if (ret) + ret = -EFAULT; + } return ret; } -- GitLab From 8718d36cf99f5acf0f37487557ec25aee54b930b Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Mon, 31 May 2010 17:58:02 +1000 Subject: [PATCH 667/842] fix setattr error handling in sysfs, configfs sysfs and configfs setattr functions have error cases after the generic inode's attributes have been changed. Fix consistency by changing the generic inode attributes only when it is guaranteed to succeed. Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- fs/configfs/inode.c | 9 ++++----- fs/sysfs/inode.c | 6 ++++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 41645142b88b..cf78d44a8d6a 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -72,10 +72,6 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr) if (!sd) return -EINVAL; - error = simple_setattr(dentry, iattr); - if (error) - return error; - sd_iattr = sd->s_iattr; if (!sd_iattr) { /* setting attributes for the first time, allocate now */ @@ -89,9 +85,12 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr) sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; sd->s_iattr = sd_iattr; } - /* attributes were changed atleast once in past */ + error = simple_setattr(dentry, iattr); + if (error) + return error; + if (ia_valid & ATTR_UID) sd_iattr->ia_uid = iattr->ia_uid; if (ia_valid & ATTR_GID) diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index bde1a4c3679a..0835a3b70e03 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -117,11 +117,13 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) if (error) goto out; + error = sysfs_sd_setattr(sd, iattr); + if (error) + goto out; + /* this ignores size changes */ generic_setattr(inode, iattr); - error = sysfs_sd_setattr(sd, iattr); - out: mutex_unlock(&sysfs_mutex); return error; -- GitLab From af5a30d8cfcfc561336f982b06345d6b815e0bb3 Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Thu, 3 Jun 2010 22:01:46 +1000 Subject: [PATCH 668/842] fix truncate inode time modification breakage mtime and ctime should be changed only if the file size has actually changed. Patches changing ext2 and tmpfs from vmtruncate to new truncate sequence has caused regressions where they always update timestamps. There is some strange cases in POSIX where truncate(2) must not update times unless the size has acutally changed, see 6e656be89. This area is all still rather buggy in different ways in a lot of filesystems and needs a cleanup and audit (ideally the vfs will provide a simple attribute or call to direct all filesystems exactly which attributes to change). But coming up with the best solution will take a while and is not appropriate for rc anyway. So fix recent regression for now. Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- fs/ext2/inode.c | 2 +- mm/shmem.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 19214435b752..3675088cb88c 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1552,7 +1552,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) if (error) return error; } - if (iattr->ia_valid & ATTR_SIZE) { + if (iattr->ia_valid & ATTR_SIZE && iattr->ia_size != inode->i_size) { error = ext2_setsize(inode, iattr->ia_size); if (error) return error; diff --git a/mm/shmem.c b/mm/shmem.c index 7e5030ae18ff..f65f84062db5 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -764,10 +764,11 @@ done2: static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; + loff_t newsize = attr->ia_size; int error; - if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { - loff_t newsize = attr->ia_size; + if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE) + && newsize != inode->i_size) { struct page *page = NULL; if (newsize < inode->i_size) { -- GitLab From 01afaf61983d08ed1c9e5e8f2fcf4f40e9008033 Mon Sep 17 00:00:00 2001 From: Andrew Hendry <andrew.hendry@gmail.com> Date: Fri, 4 Jun 2010 22:51:24 +1000 Subject: [PATCH 669/842] Minix: Clean up left over label Remove a left over fail label. Signed-off-by: Andrew Hendry <andrew.hendry@gmail.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- fs/minix/dir.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/minix/dir.c b/fs/minix/dir.c index 91969589131c..1dbf921ca44b 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -75,10 +75,6 @@ static struct page * dir_get_page(struct inode *dir, unsigned long n) if (!IS_ERR(page)) kmap(page); return page; - -fail: - dir_put_page(page); - return ERR_PTR(-EIO); } static inline void *minix_next_entry(void *de, struct minix_sb_info *sbi) -- GitLab From e893de59a4982791368b3ce412bc67dd601a88a0 Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere <mcuelenaere@gmail.com> Date: Fri, 4 Jun 2010 14:14:44 -0700 Subject: [PATCH 670/842] rtc: s3c: initialize driver data before using it s3c_rtc_setfreq() uses the platform driver data to derive struct rtc_device, so make sure drvdata is set _before_ s3c_rtc_setfreq() is called. Signed-off-by: Maurus Cuelenaere <mcuelenaere@gmail.com> Cc: Paul Gortmaker <p_gortmaker@yahoo.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Maurus Cuelenaere <mcuelenaere@gmail.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/rtc/rtc-s3c.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index e5972b2c17b7..6adebf31ea69 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -495,8 +495,6 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(s3c_rtc_base + S3C2410_RTCCON)); - s3c_rtc_setfreq(&pdev->dev, 1); - device_init_wakeup(&pdev->dev, 1); /* register RTC and exit */ @@ -518,6 +516,9 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; platform_set_drvdata(pdev, rtc); + + s3c_rtc_setfreq(&pdev->dev, 1); + return 0; err_nortc: -- GitLab From eaa6e4dd4bf243a357056448e54d7c673cd44acb Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere <mcuelenaere@gmail.com> Date: Fri, 4 Jun 2010 14:14:46 -0700 Subject: [PATCH 671/842] rtc: s3c: initialize s3c_rtc_cpu_type before using it Make sure s3c_rtc_cpu_type is initialised _before_ it's used in an if() check. Reported-by: Jiri Pinkava <jiri.pinkava@vscht.cz> Signed-off-by: Maurus Cuelenaere <mcuelenaere@gmail.com> Cc: Paul Gortmaker <p_gortmaker@yahoo.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Maurus Cuelenaere <mcuelenaere@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/rtc/rtc-s3c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 6adebf31ea69..70b68d35f969 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -508,13 +508,13 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) goto err_nortc; } + s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; + if (s3c_rtc_cpu_type == TYPE_S3C64XX) rtc->max_user_freq = 32768; else rtc->max_user_freq = 128; - s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; - platform_set_drvdata(pdev, rtc); s3c_rtc_setfreq(&pdev->dev, 1); -- GitLab From 7cbe17701a0379c7b05a79a6df4f24e41d2afde8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens <heiko.carstens@de.ibm.com> Date: Fri, 4 Jun 2010 14:14:47 -0700 Subject: [PATCH 672/842] fs/compat_rw_copy_check_uvector: add missing compat_ptr call A call to access_ok is missing a compat_ptr conversion. Introduced with b83733639a494d5f42fa00a2506563fbd2d3015d "compat: factor out compat_rw_copy_check_uvector from compat_do_readv_writev" fs/compat.c: In function 'compat_rw_copy_check_uvector': fs/compat.c:629: warning: passing argument 1 of '__access_ok' makes pointer from integer without a cast Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Reviewed-by: Jeff Moyer <jmoyer@redhat.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- fs/compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/compat.c b/fs/compat.c index f0b391c50552..6490d2134ff3 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -626,7 +626,7 @@ ssize_t compat_rw_copy_check_uvector(int type, tot_len += len; if (tot_len < tmp) /* maths overflow on the compat_ssize_t */ goto out; - if (!access_ok(vrfy_dir(type), buf, len)) { + if (!access_ok(vrfy_dir(type), compat_ptr(buf), len)) { ret = -EFAULT; goto out; } -- GitLab From b7e5d1f04104d98895945ecb463d750320dcd6cf Mon Sep 17 00:00:00 2001 From: Heiko Carstens <heiko.carstens@de.ibm.com> Date: Fri, 4 Jun 2010 14:14:48 -0700 Subject: [PATCH 673/842] ramoops: add HAS_IOMEM dependency The driver fails to compile on s390: drivers/char/ramoops.c: In function 'ramoops_init': drivers/char/ramoops.c:122: error: implicit declaration of function 'ioremap' Since we won't make use of the driver anyway on s390 just let it depend on HAS_IOMEM. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Marco Stornelli <marco.stornelli@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/char/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index f09fc0e2062d..7cfcc629a7fd 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -1123,6 +1123,7 @@ source "drivers/s390/char/Kconfig" config RAMOOPS tristate "Log panic/oops to a RAM buffer" + depends on HAS_IOMEM default n help This enables panic and oops messages to be logged to a circular -- GitLab From f9c497c4aea28be826b8450a5339952f2ffc705e Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Fri, 4 Jun 2010 14:14:49 -0700 Subject: [PATCH 674/842] frv: invoke oom-killer from page fault As explained in commit 1c0fe6e3bd ("mm: invoke oom-killer from page fault") , we want to call the architecture independent oom killer when getting an unexplained OOM from handle_mm_fault, rather than simply killing current. Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: David Howells <dhowells@redhat.com> Acked-by: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- arch/frv/mm/fault.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/frv/mm/fault.c b/arch/frv/mm/fault.c index 30f5d100a81c..a325d57a83d5 100644 --- a/arch/frv/mm/fault.c +++ b/arch/frv/mm/fault.c @@ -257,10 +257,10 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear */ out_of_memory: up_read(&mm->mmap_sem); - printk("VM: killing process %s\n", current->comm); - if (user_mode(__frame)) - do_group_exit(SIGKILL); - goto no_context; + if (!user_mode(__frame)) + goto no_context; + pagefault_out_of_memory(); + return; do_sigbus: up_read(&mm->mmap_sem); -- GitLab From 68db30ce609a8fc21b95f38f509c65dab0ecfa96 Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Fri, 4 Jun 2010 14:14:49 -0700 Subject: [PATCH 675/842] m32r: invoke oom-killer from page fault As explained in commit 1c0fe6e3bd ("mm: invoke oom-killer from page fault") , we want to call the architecture independent oom killer when getting an unexplained OOM from handle_mm_fault, rather than simply killing current. Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: David Rientjes <rientjes@google.com> Cc: Hirokazu Takata <takata@linux-m32r.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- arch/m32r/mm/fault.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c index 28ee389e5f5a..b8ec002aef8e 100644 --- a/arch/m32r/mm/fault.c +++ b/arch/m32r/mm/fault.c @@ -188,7 +188,6 @@ good_area: if ((error_code & ACE_INSTRUCTION) && !(vma->vm_flags & VM_EXEC)) goto bad_area; -survive: /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo @@ -271,15 +270,10 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - if (is_global_init(tsk)) { - yield(); - down_read(&mm->mmap_sem); - goto survive; - } - printk("VM: killing process %s\n", tsk->comm); - if (error_code & ACE_USERMODE) - do_group_exit(SIGKILL); - goto no_context; + if (!(error_code & ACE_USERMODE)) + goto no_context; + pagefault_out_of_memory(); + return; do_sigbus: up_read(&mm->mmap_sem); -- GitLab From c421b08ef52f38049c6f591c5d260a97af7b0000 Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Fri, 4 Jun 2010 14:14:51 -0700 Subject: [PATCH 676/842] mn10300: invoke oom-killer from page fault As explained in commit 1c0fe6e3bd ("mm: invoke oom-killer from page fault") , we want to call the architecture independent oom killer when getting an unexplained OOM from handle_mm_fault, rather than simply killing current. Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: David Rientjes <rientjes@google.com> Acked-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- arch/mn10300/mm/fault.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c index 53bb17d0f068..81f153fa51b4 100644 --- a/arch/mn10300/mm/fault.c +++ b/arch/mn10300/mm/fault.c @@ -338,11 +338,10 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - monitor_signal(regs); - printk(KERN_ALERT "VM: killing process %s\n", tsk->comm); - if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) - do_exit(SIGKILL); - goto no_context; + if ((fault_code & MMUFCR_xFC_ACCESS) != MMUFCR_xFC_ACCESS_USR) + goto no_context; + pagefault_out_of_memory(); + return; do_sigbus: up_read(&mm->mmap_sem); -- GitLab From f76f5d71048e116f76d2eb02226b01d50890e2f4 Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Fri, 4 Jun 2010 14:14:51 -0700 Subject: [PATCH 677/842] xtensa: invoke oom-killer from page fault As explained in commit 1c0fe6e3bd ("mm: invoke oom-killer from page fault") , we want to call the architecture independent oom killer when getting an unexplained OOM from handle_mm_fault, rather than simply killing current. Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: David Rientjes <rientjes@google.com> Cc: Chris Zankel <chris@zankel.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- arch/xtensa/mm/fault.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c index bc0733359a88..e367e3026436 100644 --- a/arch/xtensa/mm/fault.c +++ b/arch/xtensa/mm/fault.c @@ -105,7 +105,6 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ -survive: fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) @@ -146,15 +145,10 @@ bad_area: */ out_of_memory: up_read(&mm->mmap_sem); - if (is_global_init(current)) { - yield(); - down_read(&mm->mmap_sem); - goto survive; - } - printk("VM: killing process %s\n", current->comm); - if (user_mode(regs)) - do_group_exit(SIGKILL); - bad_page_fault(regs, address, SIGKILL); + if (!user_mode(regs)) + bad_page_fault(regs, address, SIGKILL); + else + pagefault_out_of_memory(); return; do_sigbus: -- GitLab From 55adaa495edc429be84399f83df80dfb7f36598b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov <dtor@vmware.com> Date: Fri, 4 Jun 2010 14:14:52 -0700 Subject: [PATCH 678/842] vmware balloon: clamp number of collected non-balloonable pages Limit number of accumulated non-balloonable pages during inflation cycle, otherwise there is a chance we will be spinning and growing the list forever. This happens during torture tests when balloon target changes while we are in the middle of inflation cycle and monitor starts refusing to lock pages (since they are not needed anymore). Signed-off-by: Dmitry Torokhov <dtor@vmware.com> Acked-by: Bhavesh Davda <bhavesh@vmware.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/misc/vmware_balloon.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/misc/vmware_balloon.c b/drivers/misc/vmware_balloon.c index db9cd0240c6f..2a1e804a71aa 100644 --- a/drivers/misc/vmware_balloon.c +++ b/drivers/misc/vmware_balloon.c @@ -45,7 +45,7 @@ MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); -MODULE_VERSION("1.2.1.0-K"); +MODULE_VERSION("1.2.1.1-k"); MODULE_ALIAS("dmi:*:svnVMware*:*"); MODULE_ALIAS("vmware_vmmemctl"); MODULE_LICENSE("GPL"); @@ -101,6 +101,8 @@ MODULE_LICENSE("GPL"); /* Maximum number of page allocations without yielding processor */ #define VMW_BALLOON_YIELD_THRESHOLD 1024 +/* Maximum number of refused pages we accumulate during inflation cycle */ +#define VMW_BALLOON_MAX_REFUSED 16 /* * Hypervisor communication port definitions. @@ -183,6 +185,7 @@ struct vmballoon { /* transient list of non-balloonable pages */ struct list_head refused_pages; + unsigned int n_refused_pages; /* balloon size in pages */ unsigned int size; @@ -428,14 +431,21 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) /* inform monitor */ locked = vmballoon_send_lock_page(b, page_to_pfn(page)); if (!locked) { + STATS_INC(b->stats.refused_alloc); + if (b->reset_required) { __free_page(page); return -EIO; } - /* place on list of non-balloonable pages, retry allocation */ + /* + * Place page on the list of non-balloonable pages + * and retry allocation, unless we already accumulated + * too many of them, in which case take a breather. + */ list_add(&page->lru, &b->refused_pages); - STATS_INC(b->stats.refused_alloc); + if (++b->n_refused_pages >= VMW_BALLOON_MAX_REFUSED) + return -EIO; } } while (!locked); @@ -483,6 +493,8 @@ static void vmballoon_release_refused_pages(struct vmballoon *b) __free_page(page); STATS_INC(b->stats.refused_free); } + + b->n_refused_pages = 0; } /* -- GitLab From 2e94de8acbe524d919f1ea8807913d7b005e1578 Mon Sep 17 00:00:00 2001 From: Mike Frysinger <vapier@gentoo.org> Date: Fri, 4 Jun 2010 14:14:53 -0700 Subject: [PATCH 679/842] fs/binfmt_flat.c: split the stack & data alignments The stack and data have different alignment requirements, so don't force them to wear the same shoe. Increase the data alignment to match that which the elf2flt linker script has always been using: 0x20 bytes. Not only does this bring the kernel loader in line with the toolchain, but it also fixes a swath of gcc tests which try to force larger alignment values but randomly fail when the FLAT loader fails to deliver. Signed-off-by: Mike Frysinger <vapier@gentoo.org> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: David Woodhouse <David.Woodhouse@intel.com> Cc: Pekka Enberg <penberg@cs.helsinki.fi> Acked-by: David McCullough <davidm@snapgear.com> Acked-by: Greg Ungerer <gerg@uclinux.org> Cc: Paul Mundt <lethal@linux-sh.org> Tested-by: Michal Simek <monstr@monstr.eu> Cc: Hirokazu Takata <takata@linux-m32r.org> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Jie Zhang <jie@codesourcery.com> Cc: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- fs/binfmt_flat.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 49566c1687d8..b8656225b34b 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -56,15 +56,22 @@ #endif /* - * User data (stack, data section and bss) needs to be aligned - * for the same reasons as SLAB memory is, and to the same amount. - * Avoid duplicating architecture specific code by using the same - * macro as with SLAB allocation: + * User data (data section and bss) needs to be aligned. + * We pick 0x20 here because it is the max value elf2flt has always + * used in producing FLAT files, and because it seems to be large + * enough to make all the gcc alignment related tests happy. + */ +#define FLAT_DATA_ALIGN (0x20) + +/* + * User data (stack) also needs to be aligned. + * Here we can be a bit looser than the data sections since this + * needs to only meet arch ABI requirements. */ #ifdef ARCH_SLAB_MINALIGN -#define FLAT_DATA_ALIGN (ARCH_SLAB_MINALIGN) +#define FLAT_STACK_ALIGN (ARCH_SLAB_MINALIGN) #else -#define FLAT_DATA_ALIGN (sizeof(void *)) +#define FLAT_STACK_ALIGN (sizeof(void *)) #endif #define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ @@ -129,7 +136,7 @@ static unsigned long create_flat_tables( sp = (unsigned long *)p; sp -= (envc + argc + 2) + 1 + (flat_argvp_envp_on_stack() ? 2 : 0); - sp = (unsigned long *) ((unsigned long)sp & -FLAT_DATA_ALIGN); + sp = (unsigned long *) ((unsigned long)sp & -FLAT_STACK_ALIGN); argv = sp + 1 + (flat_argvp_envp_on_stack() ? 2 : 0); envp = argv + (argc + 1); @@ -876,7 +883,7 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) stack_len = TOP_OF_ARGS - bprm->p; /* the strings */ stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */ stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */ - stack_len += FLAT_DATA_ALIGN - 1; /* reserve for upcoming alignment */ + stack_len += FLAT_STACK_ALIGN - 1; /* reserve for upcoming alignment */ res = load_flat_file(bprm, &libinfo, 0, &stack_len); if (IS_ERR_VALUE(res)) -- GitLab From 1da083c9b23dafd6bcb08dcfec443e66e90efff0 Mon Sep 17 00:00:00 2001 From: Mike Frysinger <vapier@gentoo.org> Date: Fri, 4 Jun 2010 14:14:55 -0700 Subject: [PATCH 680/842] flat: fix unmap len in load error path The data chunk is mmaped with 'len' which remains unchanged, so use that when unmapping in the error path rather than trying to recalculate (and incorrectly so) the value used originally. Signed-off-by: Mike Frysinger <vapier@gentoo.org> Acked-by: David McCullough <davidm@snapgear.com> Acked-by: Greg Ungerer <gerg@uclinux.org> Cc: Paul Mundt <lethal@linux-sh.org> Cc: Michal Simek <monstr@monstr.eu> Cc: Hirokazu Takata <takata@linux-m32r.org> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Acked-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- fs/binfmt_flat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index b8656225b34b..b6ab27ccf214 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -596,7 +596,7 @@ static int load_flat_file(struct linux_binprm * bprm, if (IS_ERR_VALUE(result)) { printk("Unable to read data+bss, errno %d\n", (int)-result); do_munmap(current->mm, textpos, text_len); - do_munmap(current->mm, realdatastart, data_len + extra); + do_munmap(current->mm, realdatastart, len); ret = result; goto err; } -- GitLab From 3f505ca45735c35576dab4ceb3e3736d528b6672 Mon Sep 17 00:00:00 2001 From: Albert Herranz <albert_herranz@yahoo.es> Date: Fri, 4 Jun 2010 14:14:56 -0700 Subject: [PATCH 681/842] Revert "fb_defio: fix for non-dirty ptes" This reverts commit 49bbd815fd8ba26d0354900b783b767c7f47c816 ("fb_defio: fix for non-dirty ptes"). Although the fix provided is correct, it's been suggested to avoid the underlying race in the same way as it is currently done in filesystems like NFS, for maintainability. A following patch "fb_defio: redo fix for non-dirty ptes" will provide such an alternate fix. Signed-off-by: Albert Herranz <albert_herranz@yahoo.es> Cc: Jaya Kumar <jayakumar.lkml@gmail.com> Cc: Nick Piggin <nickpiggin@yahoo.com.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/video/fb_defio.c | 40 ++++++++-------------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 073c9b408cf7..137100ea8ad7 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -155,41 +155,25 @@ static void fb_deferred_io_work(struct work_struct *work) { struct fb_info *info = container_of(work, struct fb_info, deferred_work.work); + struct list_head *node, *next; + struct page *cur; struct fb_deferred_io *fbdefio = info->fbdefio; - struct page *page, *tmp_page; - struct list_head *node, *tmp_node; - struct list_head non_dirty; - - INIT_LIST_HEAD(&non_dirty); /* here we mkclean the pages, then do all deferred IO */ mutex_lock(&fbdefio->lock); - list_for_each_entry_safe(page, tmp_page, &fbdefio->pagelist, lru) { - lock_page(page); - /* - * The workqueue callback can be triggered after a - * ->page_mkwrite() call but before the PTE has been marked - * dirty. In this case page_mkclean() won't "rearm" the page. - * - * To avoid this, remove those "non-dirty" pages from the - * pagelist before calling the driver's callback, then add - * them back to get processed on the next work iteration. - * At that time, their PTEs will hopefully be dirty for real. - */ - if (!page_mkclean(page)) - list_move_tail(&page->lru, &non_dirty); - unlock_page(page); + list_for_each_entry(cur, &fbdefio->pagelist, lru) { + lock_page(cur); + page_mkclean(cur); + unlock_page(cur); } /* driver's callback with pagelist */ fbdefio->deferred_io(info, &fbdefio->pagelist); - /* clear the list... */ - list_for_each_safe(node, tmp_node, &fbdefio->pagelist) { + /* clear the list */ + list_for_each_safe(node, next, &fbdefio->pagelist) { list_del(node); } - /* ... and add back the "non-dirty" pages to the list */ - list_splice_tail(&non_dirty, &fbdefio->pagelist); mutex_unlock(&fbdefio->lock); } @@ -218,7 +202,6 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_open); void fb_deferred_io_cleanup(struct fb_info *info) { struct fb_deferred_io *fbdefio = info->fbdefio; - struct list_head *node, *tmp_node; struct page *page; int i; @@ -226,13 +209,6 @@ void fb_deferred_io_cleanup(struct fb_info *info) cancel_delayed_work(&info->deferred_work); flush_scheduled_work(); - /* the list may have still some non-dirty pages at this point */ - mutex_lock(&fbdefio->lock); - list_for_each_safe(node, tmp_node, &fbdefio->pagelist) { - list_del(node); - } - mutex_unlock(&fbdefio->lock); - /* clear out the mapping that we setup */ for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { page = fb_deferred_io_page(info, i); -- GitLab From d6d03f9158516b50d0d343158e3f33bcff1e4ca5 Mon Sep 17 00:00:00 2001 From: Albert Herranz <albert_herranz@yahoo.es> Date: Fri, 4 Jun 2010 14:14:57 -0700 Subject: [PATCH 682/842] fb_defio: redo fix for non-dirty ptes As pointed by Nick Piggin, ->page_mkwrite provides a way to keep a page locked until the associated PTE is marked dirty. Re-implement the fix by using this mechanism. Signed-off-by: Albert Herranz <albert_herranz@yahoo.es> Acked-by: Jaya Kumar <jayakumar.lkml@gmail.com> Acked-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/video/fb_defio.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 137100ea8ad7..6b93ef93cb12 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -100,6 +100,16 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma, /* protect against the workqueue changing the page list */ mutex_lock(&fbdefio->lock); + /* + * We want the page to remain locked from ->page_mkwrite until + * the PTE is marked dirty to avoid page_mkclean() being called + * before the PTE is updated, which would leave the page ignored + * by defio. + * Do this by locking the page here and informing the caller + * about it with VM_FAULT_LOCKED. + */ + lock_page(page); + /* we loop through the pagelist before adding in order to keep the pagelist sorted */ list_for_each_entry(cur, &fbdefio->pagelist, lru) { @@ -121,7 +131,7 @@ page_already_added: /* come back after delay to process the deferred IO */ schedule_delayed_work(&info->deferred_work, fbdefio->delay); - return 0; + return VM_FAULT_LOCKED; } static const struct vm_operations_struct fb_deferred_io_vm_ops = { -- GitLab From 485d527686850d68a0e9006dd9904f19f122485e Mon Sep 17 00:00:00 2001 From: Oleg Nesterov <oleg@redhat.com> Date: Fri, 4 Jun 2010 14:14:58 -0700 Subject: [PATCH 683/842] sys_personality: change sys_personality() to accept "unsigned int" instead of u_long task_struct->pesonality is "unsigned int", but sys_personality() paths use "unsigned long pesonality". This means that every assignment or comparison is not right. In particular, if this argument does not fit into "unsigned int" __set_personality() changes the caller's personality and then sys_personality() returns -EINVAL. Turn this argument into "unsigned int" and avoid overflows. Obviously, this is the user-visible change, we just ignore the upper bits. But this can't break the sane application. There is another thing which can confuse the poorly written applications. User-space thinks that this syscall returns int, not long. This means that the returned value can be negative and look like the error code. But note that libc won't be confused and thus errno won't be set, and with this patch the user-space can never get -1 unless sys_personality() really fails. And, most importantly, the negative RET != -1 is only possible if that app previously called personality(RET). Pointed-out-by: Wenming Zhang <wezhang@redhat.com> Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Oleg Nesterov <oleg@redhat.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- include/linux/personality.h | 2 +- include/linux/syscalls.h | 2 +- kernel/exec_domain.c | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/linux/personality.h b/include/linux/personality.h index 126120819a0d..eec3bae164d4 100644 --- a/include/linux/personality.h +++ b/include/linux/personality.h @@ -12,7 +12,7 @@ struct pt_regs; extern int register_exec_domain(struct exec_domain *); extern int unregister_exec_domain(struct exec_domain *); -extern int __set_personality(unsigned long); +extern int __set_personality(unsigned int); #endif /* __KERNEL__ */ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index a1a86a53bc73..7f614ce274a9 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -289,7 +289,7 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr); asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data); -asmlinkage long sys_personality(u_long personality); +asmlinkage long sys_personality(unsigned int personality); asmlinkage long sys_sigpending(old_sigset_t __user *set); asmlinkage long sys_sigprocmask(int how, old_sigset_t __user *set, diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c index c35452cadded..dd62f8e714ca 100644 --- a/kernel/exec_domain.c +++ b/kernel/exec_domain.c @@ -27,7 +27,7 @@ static struct exec_domain *exec_domains = &default_exec_domain; static DEFINE_RWLOCK(exec_domains_lock); -static u_long ident_map[32] = { +static unsigned long ident_map[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, @@ -56,10 +56,10 @@ default_handler(int segment, struct pt_regs *regp) } static struct exec_domain * -lookup_exec_domain(u_long personality) +lookup_exec_domain(unsigned int personality) { - struct exec_domain * ep; - u_long pers = personality(personality); + unsigned int pers = personality(personality); + struct exec_domain *ep; read_lock(&exec_domains_lock); for (ep = exec_domains; ep; ep = ep->next) { @@ -70,7 +70,7 @@ lookup_exec_domain(u_long personality) #ifdef CONFIG_MODULES read_unlock(&exec_domains_lock); - request_module("personality-%ld", pers); + request_module("personality-%d", pers); read_lock(&exec_domains_lock); for (ep = exec_domains; ep; ep = ep->next) { @@ -135,7 +135,7 @@ unregister: } int -__set_personality(u_long personality) +__set_personality(unsigned int personality) { struct exec_domain *ep, *oep; @@ -188,9 +188,9 @@ static int __init proc_execdomains_init(void) module_init(proc_execdomains_init); #endif -SYSCALL_DEFINE1(personality, u_long, personality) +SYSCALL_DEFINE1(personality, unsigned int, personality) { - u_long old = current->personality; + unsigned int old = current->personality; if (personality != 0xffffffff) { set_personality(personality); @@ -198,7 +198,7 @@ SYSCALL_DEFINE1(personality, u_long, personality) return -EINVAL; } - return (long)old; + return old; } -- GitLab From fc0ccfceb8aa6800040ba4f37a36ee306aa71c9f Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros <cesarb@cesarb.net> Date: Fri, 4 Jun 2010 14:14:58 -0700 Subject: [PATCH 684/842] arch/um: fix kunmap_atomic() call in skas/uaccess.c kunmap_atomic() takes a pointer to within the page, not the struct page. Signed-off-by: Cesar Eduardo Barros <cesarb@cesarb.net> Cc: Jeff Dike <jdike@addtoit.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- arch/um/kernel/skas/uaccess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index e22c96993db3..696634214dc6 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -81,7 +81,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write, current->thread.fault_catcher = NULL; - kunmap_atomic(page, KM_UML_USERCOPY); + kunmap_atomic((void *)addr, KM_UML_USERCOPY); return n; } -- GitLab From b1413357d924792e2e332dcb6b712a7fb2a5fb25 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com> Date: Fri, 4 Jun 2010 14:15:00 -0700 Subject: [PATCH 685/842] fbdev: fix frame buffer devices menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit f601441916d1e19291d0b4f044b4a7551e2924d0 ("imxfb: add support for i.MX25:) has inserted the symbol HAVE_FB_IMX, which does not depend on FB after the menuconfig FB. This breaks the menu, presenting most of the drivers outside of it, when using menuconfig. Moving the symbol to the start of the file, just like HAVE_FB_ATMEL, fixes the problem without breaking it for iMX25 configurations (tested with ARCH=arm, no build). Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com> Cc: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Acked-by: Baruch Siach <baruch@tkos.co.il> Cc: "David S. Miller" <davem@davemloft.net> Cc: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/video/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 1e6fec487973..3d94a1471724 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -8,6 +8,9 @@ menu "Graphics support" config HAVE_FB_ATMEL bool +config HAVE_FB_IMX + bool + source "drivers/char/agp/Kconfig" source "drivers/gpu/vga/Kconfig" @@ -400,9 +403,6 @@ config FB_SA1100 If you plan to use the LCD display with your SA-1100 system, say Y here. -config HAVE_FB_IMX - bool - config FB_IMX tristate "Motorola i.MX LCD support" depends on FB && (HAVE_FB_IMX || ARCH_MX1 || ARCH_MX2) -- GitLab From 007d08678eb87478b65b3f229960c81dd7c7b8f3 Mon Sep 17 00:00:00 2001 From: Heiko Carstens <heiko.carstens@de.ibm.com> Date: Fri, 4 Jun 2010 14:15:02 -0700 Subject: [PATCH 686/842] lib: add s390 to atomic64_dec_if_positive archs Add s390 to list of architectures that have atomic64_dec_if_positive implemented so we get rid of this warning: lib/atomic64_test.c:129:2: warning: #warning Please implement atomic64_dec_if_positive for your architecture, and add it to the IF above Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Luca Barbieri <luca@luca-barbieri.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- lib/atomic64_test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c index 9087d71537dd..250ed11d3ed2 100644 --- a/lib/atomic64_test.c +++ b/lib/atomic64_test.c @@ -113,7 +113,8 @@ static __init int test_atomic64(void) r += one; BUG_ON(v.counter != r); -#if defined(CONFIG_X86) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(_ASM_GENERIC_ATOMIC64_H) +#if defined(CONFIG_X86) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || \ + defined(CONFIG_S390) || defined(_ASM_GENERIC_ATOMIC64_H) INIT(onestwos); BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1)); r -= one; -- GitLab From 94b3dd0f7bb393d93e84a173b1df9b8b64c83ac4 Mon Sep 17 00:00:00 2001 From: Greg Thelen <gthelen@google.com> Date: Fri, 4 Jun 2010 14:15:03 -0700 Subject: [PATCH 687/842] cgroups: alloc_css_id() increments hierarchy depth Child groups should have a greater depth than their parents. Prior to this change, the parent would incorrectly report zero memory usage for child cgroups when use_hierarchy is enabled. test script: mount -t cgroup none /cgroups -o memory cd /cgroups mkdir cg1 echo 1 > cg1/memory.use_hierarchy mkdir cg1/cg11 echo $$ > cg1/cg11/tasks dd if=/dev/zero of=/tmp/foo bs=1M count=1 echo echo CHILD grep cache cg1/cg11/memory.stat echo echo PARENT grep cache cg1/memory.stat echo $$ > tasks rmdir cg1/cg11 cg1 cd / umount /cgroups Using fae9c79, a recent patch that changed alloc_css_id() depth computation, the parent incorrectly reports zero usage: root@ubuntu:~# ./test 1+0 records in 1+0 records out 1048576 bytes (1.0 MB) copied, 0.0151844 s, 69.1 MB/s CHILD cache 1048576 total_cache 1048576 PARENT cache 0 total_cache 0 With this patch, the parent correctly includes child usage: root@ubuntu:~# ./test 1+0 records in 1+0 records out 1048576 bytes (1.0 MB) copied, 0.0136827 s, 76.6 MB/s CHILD cache 1052672 total_cache 1052672 PARENT cache 0 total_cache 1052672 Signed-off-by: Greg Thelen <gthelen@google.com> Acked-by: Paul Menage <menage@google.com> Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Acked-by: Li Zefan <lizf@cn.fujitsu.com> Cc: <stable@kernel.org> [2.6.34.x] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- kernel/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 422cb19f156e..3ac6f5b0a64b 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -4598,7 +4598,7 @@ static int alloc_css_id(struct cgroup_subsys *ss, struct cgroup *parent, parent_css = parent->subsys[subsys_id]; child_css = child->subsys[subsys_id]; parent_id = parent_css->id; - depth = parent_id->depth; + depth = parent_id->depth + 1; child_id = get_new_cssid(ss, depth); if (IS_ERR(child_id)) -- GitLab From 9e506f7adce8e6165a104d3d78fddd8ff0cdccf8 Mon Sep 17 00:00:00 2001 From: Akinobu Mita <akinobu.mita@gmail.com> Date: Fri, 4 Jun 2010 14:15:04 -0700 Subject: [PATCH 688/842] kernel/: fix BUG_ON checks for cpu notifier callbacks direct call The commit 80b5184cc537718122e036afe7e62d202b70d077 ("kernel/: convert cpu notifier to return encapsulate errno value") changed the return value of cpu notifier callbacks. Those callbacks don't return NOTIFY_BAD on failures anymore. But there are a few callbacks which are called directly at init time and checking the return value. I forgot to change BUG_ON checking by the direct callers in the commit. Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- kernel/softirq.c | 2 +- kernel/timer.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index 825e1126008f..07b4f1b1a73a 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -850,7 +850,7 @@ static __init int spawn_ksoftirqd(void) void *cpu = (void *)(long)smp_processor_id(); int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu); - BUG_ON(err == NOTIFY_BAD); + BUG_ON(err != NOTIFY_OK); cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); register_cpu_notifier(&cpu_nfb); return 0; diff --git a/kernel/timer.c b/kernel/timer.c index 2454172a80d3..ee305c8d4e18 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1717,7 +1717,7 @@ void __init init_timers(void) init_timer_stats(); - BUG_ON(err == NOTIFY_BAD); + BUG_ON(err != NOTIFY_OK); register_cpu_notifier(&timers_nb); open_softirq(TIMER_SOFTIRQ, run_timer_softirq); } -- GitLab From bb21c7ce18eff8e6e7877ca1d06c6db719376e3c Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Date: Fri, 4 Jun 2010 14:15:05 -0700 Subject: [PATCH 689/842] vmscan: fix do_try_to_free_pages() return value when priority==0 reclaim failure Greg Thelen reported recent Johannes's stack diet patch makes kernel hang. His test is following. mount -t cgroup none /cgroups -o memory mkdir /cgroups/cg1 echo $$ > /cgroups/cg1/tasks dd bs=1024 count=1024 if=/dev/null of=/data/foo echo $$ > /cgroups/tasks echo 1 > /cgroups/cg1/memory.force_empty Actually, This OOM hard to try logic have been corrupted since following two years old patch. commit a41f24ea9fd6169b147c53c2392e2887cc1d9247 Author: Nishanth Aravamudan <nacc@us.ibm.com> Date: Tue Apr 29 00:58:25 2008 -0700 page allocator: smarter retry of costly-order allocations Original intention was "return success if the system have shrinkable zones though priority==0 reclaim was failure". But the above patch changed to "return nr_reclaimed if .....". Oh, That forgot nr_reclaimed may be 0 if priority==0 reclaim failure. And Johannes's patch 0aeb2339e54e ("vmscan: remove all_unreclaimable scan control") made it more corrupt. Originally, priority==0 reclaim failure on memcg return 0, but this patch changed to return 1. It totally confused memcg. This patch fixes it completely. Reported-by: Greg Thelen <gthelen@google.com> Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Acked-by: Johannes Weiner <hannes@cmpxchg.org> Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Tested-by: Greg Thelen <gthelen@google.com> Acked-by: Balbir Singh <balbir@linux.vnet.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- mm/vmscan.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 915dceb487c1..9c7e57cc63a3 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1724,13 +1724,13 @@ static void shrink_zone(int priority, struct zone *zone, * If a zone is deemed to be full of pinned pages then just give it a light * scan then give up on it. */ -static int shrink_zones(int priority, struct zonelist *zonelist, +static bool shrink_zones(int priority, struct zonelist *zonelist, struct scan_control *sc) { enum zone_type high_zoneidx = gfp_zone(sc->gfp_mask); struct zoneref *z; struct zone *zone; - int progress = 0; + bool all_unreclaimable = true; for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx, sc->nodemask) { @@ -1757,9 +1757,9 @@ static int shrink_zones(int priority, struct zonelist *zonelist, } shrink_zone(priority, zone, sc); - progress = 1; + all_unreclaimable = false; } - return progress; + return all_unreclaimable; } /* @@ -1782,7 +1782,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, struct scan_control *sc) { int priority; - unsigned long ret = 0; + bool all_unreclaimable; unsigned long total_scanned = 0; struct reclaim_state *reclaim_state = current->reclaim_state; unsigned long lru_pages = 0; @@ -1813,7 +1813,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, sc->nr_scanned = 0; if (!priority) disable_swap_token(); - ret = shrink_zones(priority, zonelist, sc); + all_unreclaimable = shrink_zones(priority, zonelist, sc); /* * Don't shrink slabs when reclaiming memory from * over limit cgroups @@ -1826,10 +1826,8 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, } } total_scanned += sc->nr_scanned; - if (sc->nr_reclaimed >= sc->nr_to_reclaim) { - ret = sc->nr_reclaimed; + if (sc->nr_reclaimed >= sc->nr_to_reclaim) goto out; - } /* * Try to write back as many pages as we just scanned. This @@ -1849,9 +1847,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, priority < DEF_PRIORITY - 2) congestion_wait(BLK_RW_ASYNC, HZ/10); } - /* top priority shrink_zones still had more to do? don't OOM, then */ - if (ret && scanning_global_lru(sc)) - ret = sc->nr_reclaimed; + out: /* * Now that we've scanned all the zones at this priority level, note @@ -1877,7 +1873,14 @@ out: delayacct_freepages_end(); put_mems_allowed(); - return ret; + if (sc->nr_reclaimed) + return sc->nr_reclaimed; + + /* top priority shrink_zones still had more to do? don't OOM, then */ + if (scanning_global_lru(sc) && !all_unreclaimable) + return 1; + + return 0; } unsigned long try_to_free_pages(struct zonelist *zonelist, int order, -- GitLab From 683eb94777c3c67b9b258765b9cb03641344c418 Mon Sep 17 00:00:00 2001 From: Cory Maccarrone <darkstar6262@gmail.com> Date: Fri, 4 Jun 2010 14:15:07 -0700 Subject: [PATCH 690/842] omap: remove BUG_ON for disabled interrupts Remove a BUG_ON for when interrupts are disabled during an MMC request. During boot, interrupts can be disabled when a request is made, causing this bug to be triggered. In reality, there's no reason this should halt the kernel, as the driver has proved reliable in spite of disabled interrupts, and additionally, there's nothing in this code that would require interrupts to be enabled. The only setup I've managed to make it trigger on is on the HTC Herald during bootup when the driver is built into the kernel (mostly because that's all I have). I believe it's related to the fact that on bootup I get many timeout errors on "CMD5" while initializing the card. Each CMD5 timeout triggers that bug (I changed it to a WARN_ON to get it to boot in) due to the fact that part of the timeout code involves sending the request again. With interrupts turned off, that BUG would be triggered. Signed-off-by: Cory Maccarrone <darkstar6262@gmail.com> Acked-by: Tony Lindgren <tony@atomide.com> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/mmc/host/omap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 2b281680e320..d98ddcfac5e5 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1157,7 +1157,6 @@ static void mmc_omap_start_request(struct mmc_omap_host *host, mmc_omap_start_command(host, req->cmd); if (host->dma_in_use) omap_start_dma(host->dma_ch); - BUG_ON(irqs_disabled()); } static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req) -- GitLab From 8764ab2ca7ab5055e1ca80f9cfa4970c34acb804 Mon Sep 17 00:00:00 2001 From: Steffen Klassert <steffen.klassert@secunet.com> Date: Fri, 4 Jun 2010 01:57:38 +0000 Subject: [PATCH 691/842] net: check for refcount if pop a stacked dst_entry xfrm triggers a warning if dst_pop() drops a refcount on a noref dst. This patch changes dst_pop() to skb_dst_pop(). skb_dst_pop() drops the refcnt only on a refcounted dst. Also we don't clone the child dst_entry, so it is not refcounted and we can use skb_dst_set_noref() in xfrm_output_one(). Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- include/net/dst.h | 6 +++--- net/xfrm/xfrm_output.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index 612069beda73..81d1413a8701 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -250,11 +250,11 @@ static inline void skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev) * Linux networking. Thus, destinations are stackable. */ -static inline struct dst_entry *dst_pop(struct dst_entry *dst) +static inline struct dst_entry *skb_dst_pop(struct sk_buff *skb) { - struct dst_entry *child = dst_clone(dst->child); + struct dst_entry *child = skb_dst(skb)->child; - dst_release(dst); + skb_dst_drop(skb); return child; } diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 6a329158bdfa..a3cca0a94346 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -95,13 +95,13 @@ resume: goto error_nolock; } - dst = dst_pop(dst); + dst = skb_dst_pop(skb); if (!dst) { XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); err = -EHOSTUNREACH; goto error_nolock; } - skb_dst_set(skb, dst); + skb_dst_set_noref(skb, dst); x = dst->xfrm; } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL)); -- GitLab From ca739481662137b8f717bc21f16719cda3c33d6b Mon Sep 17 00:00:00 2001 From: John Fastabend <john.r.fastabend@intel.com> Date: Thu, 3 Jun 2010 17:03:45 +0000 Subject: [PATCH 692/842] ixgbe: only check pfc bits in hang logic if pfc is enabled Only check pfc bits in hang logic if PFC is enabled. Previously, if DCB was enabled but PFC was disabled the incorrect pause bits would be checked. Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Acked-by: Don Skidmore <donald.c.skidmore@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/ixgbe/ixgbe_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d571d101de08..b2af2f67f604 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -642,7 +642,7 @@ static inline bool ixgbe_tx_xon_state(struct ixgbe_adapter *adapter, u32 txoff = IXGBE_TFCS_TXOFF; #ifdef CONFIG_IXGBE_DCB - if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + if (adapter->dcb_cfg.pfc_mode_enable) { int tc; int reg_idx = tx_ring->reg_idx; int dcb_i = adapter->ring_feature[RING_F_DCB].indices; -- GitLab From 57f1553ee5d9f093660cc49098f494e17ed11668 Mon Sep 17 00:00:00 2001 From: Florian Westphal <fw@strlen.de> Date: Thu, 3 Jun 2010 00:42:30 +0000 Subject: [PATCH 693/842] syncookies: remove Kconfig text line about disabled-by-default syncookies default to on since e994b7c901ded7200b525a707c6da71f2cf6d4bb (tcp: Don't make syn cookies initial setting depend on CONFIG_SYSCTL). Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv4/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 8e3a1fd938ab..7c3a7d191249 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -303,7 +303,7 @@ config ARPD If unsure, say N. config SYN_COOKIES - bool "IP: TCP syncookie support (disabled per default)" + bool "IP: TCP syncookie support" ---help--- Normal TCP/IP networking is open to an attack known as "SYN flooding". This denial-of-service attack prevents legitimate remote @@ -328,13 +328,13 @@ config SYN_COOKIES server is really overloaded. If this happens frequently better turn them off. - If you say Y here, note that SYN cookies aren't enabled by default; - you can enable them by saying Y to "/proc file system support" and + If you say Y here, you can disable SYN cookies at run time by + saying Y to "/proc file system support" and "Sysctl support" below and executing the command - echo 1 >/proc/sys/net/ipv4/tcp_syncookies + echo 0 > /proc/sys/net/ipv4/tcp_syncookies - at boot time after the /proc file system has been mounted. + after the /proc file system has been mounted. If unsure, say N. -- GitLab From 536e00e570c87f258554e919c444b81a7002e46d Mon Sep 17 00:00:00 2001 From: Ben McKeegan <ben@netservers.co.uk> Date: Wed, 2 Jun 2010 23:14:33 +0000 Subject: [PATCH 694/842] ppp_generic: fix multilink fragment sizes Fix bug in multilink fragment size calculation introduced by commit 9c705260feea6ae329bc6b6d5f6d2ef0227eda0a "ppp: ppp_mp_explode() redesign" Signed-off-by: Ben McKeegan <ben@netservers.co.uk> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/ppp_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index c5f8eb102bf7..1b2c29150202 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1422,7 +1422,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) flen = len; if (nfree > 0) { if (pch->speed == 0) { - flen = totlen/nfree; + flen = len/nfree; if (nbigger > 0) { flen++; nbigger--; -- GitLab From ca55158c6ecb7832a6ad80ac44a14d23bab8cdfc Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Thu, 3 Jun 2010 09:03:58 +0000 Subject: [PATCH 695/842] rps: tcp: fix rps_sock_flow_table table updates I believe a moderate SYN flood attack can corrupt RFS flow table (rps_sock_flow_table), making RPS/RFS much less effective. Even in a normal situation, server handling short lived sessions suffer from bad steering for the first data packet of a session, if another SYN packet is received for another session. We do following action in tcp_v4_rcv() : sock_rps_save_rxhash(sk, skb->rxhash); We should _not_ do this if sk is a LISTEN socket, as about each packet received on a LISTEN socket has a different rxhash than previous one. -> RPS_NO_CPU markers are spread all over rps_sock_flow_table. Also, it makes sense to protect sk->rxhash field changes with socket lock (We currently can change it even if user thread owns the lock and might use rxhash) This patch moves sock_rps_save_rxhash() to a sock locked section, and only for non LISTEN sockets. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv4/tcp_ipv4.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 202cf09c4cd4..fe193e53af44 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1555,6 +1555,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) #endif if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ + sock_rps_save_rxhash(sk, skb->rxhash); TCP_CHECK_TIMER(sk); if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) { rsk = sk; @@ -1579,7 +1580,9 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) } return 0; } - } + } else + sock_rps_save_rxhash(sk, skb->rxhash); + TCP_CHECK_TIMER(sk); if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) { @@ -1672,8 +1675,6 @@ process: skb->dev = NULL; - sock_rps_save_rxhash(sk, skb->rxhash); - bh_lock_sock_nested(sk); ret = 0; if (!sock_owned_by_user(sk)) { -- GitLab From c44649216522cd607a4027d2ebf4a8147d3fa94c Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Thu, 3 Jun 2010 05:45:47 +0000 Subject: [PATCH 696/842] tcp: use correct net ns in cookie_v4_check() Its better to make a route lookup in appropriate namespace. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv4/syncookies.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 5c24db4a3c91..9f6b22206c52 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -347,7 +347,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, { .sport = th->dest, .dport = th->source } } }; security_req_classify_flow(req, &fl); - if (ip_route_output_key(&init_net, &rt, &fl)) { + if (ip_route_output_key(sock_net(sk), &rt, &fl)) { reqsk_free(req); goto out; } -- GitLab From ca7335948e294faf8adf65f2c95ca18ea78540db Mon Sep 17 00:00:00 2001 From: Huang Weiyi <weiyi.huang@gmail.com> Date: Fri, 4 Jun 2010 16:14:15 -0700 Subject: [PATCH 697/842] X25: remove duplicated #include Remove duplicated #include('s) in drivers/net/wan/x25_asy.c Signed-off-by: Huang Weiyi <weiyi.huang@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/wan/x25_asy.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 166e77dfffda..e47f5a986b1c 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -37,8 +37,6 @@ #include <net/x25device.h> #include "x25_asy.h" -#include <net/x25device.h> - static struct net_device **x25_asy_devs; static int x25_asy_maxdev = SL_NRUNIT; -- GitLab From 2c02dfe7fe3fba97a5665d329d039d2415ea5607 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Mon, 31 May 2010 12:19:37 -0700 Subject: [PATCH 698/842] module: Make the 'usage' lists be two-way When adding a module that depends on another one, we used to create a one-way list of "modules_which_use_me", so that module unloading could see who needs a module. It's actually quite simple to make that list go both ways: so that we not only can see "who uses me", but also see a list of modules that are "used by me". In fact, we always wanted that list in "module_unload_free()": when we unload a module, we want to also release all the other modules that are used by that module. But because we didn't have that list, we used to first iterate over all modules, and then iterate over each "used by me" list of that module. By making the list two-way, we simplify module_unload_free(), and it allows for some trivial fixes later too. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (cleaned & rebased) --- include/linux/module.h | 4 ++- kernel/module.c | 79 +++++++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index 6914fcad4673..680db9e2ac36 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -359,7 +359,9 @@ struct module #ifdef CONFIG_MODULE_UNLOAD /* What modules depend on me? */ - struct list_head modules_which_use_me; + struct list_head source_list; + /* What modules do I depend on? */ + struct list_head target_list; /* Who is waiting for us to be unloaded */ struct task_struct *waiter; diff --git a/kernel/module.c b/kernel/module.c index 0129769301e3..be18c3e34684 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -523,7 +523,8 @@ static void module_unload_init(struct module *mod) { int cpu; - INIT_LIST_HEAD(&mod->modules_which_use_me); + INIT_LIST_HEAD(&mod->source_list); + INIT_LIST_HEAD(&mod->target_list); for_each_possible_cpu(cpu) { per_cpu_ptr(mod->refptr, cpu)->incs = 0; per_cpu_ptr(mod->refptr, cpu)->decs = 0; @@ -538,8 +539,9 @@ static void module_unload_init(struct module *mod) /* modules using other modules */ struct module_use { - struct list_head list; - struct module *module_which_uses; + struct list_head source_list; + struct list_head target_list; + struct module *source, *target; }; /* Does a already use b? */ @@ -547,8 +549,8 @@ static int already_uses(struct module *a, struct module *b) { struct module_use *use; - list_for_each_entry(use, &b->modules_which_use_me, list) { - if (use->module_which_uses == a) { + list_for_each_entry(use, &b->source_list, source_list) { + if (use->source == a) { DEBUGP("%s uses %s!\n", a->name, b->name); return 1; } @@ -557,6 +559,33 @@ static int already_uses(struct module *a, struct module *b) return 0; } +/* + * Module a uses b + * - we add 'a' as a "source", 'b' as a "target" of module use + * - the module_use is added to the list of 'b' sources (so + * 'b' can walk the list to see who sourced them), and of 'a' + * targets (so 'a' can see what modules it targets). + */ +static int add_module_usage(struct module *a, struct module *b) +{ + int no_warn; + struct module_use *use; + + DEBUGP("Allocating new usage for %s.\n", a->name); + use = kmalloc(sizeof(*use), GFP_ATOMIC); + if (!use) { + printk(KERN_WARNING "%s: out of memory loading\n", a->name); + return -ENOMEM; + } + + use->source = a; + use->target = b; + list_add(&use->source_list, &b->source_list); + list_add(&use->target_list, &a->target_list); + no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name); + return 0; +} + /* Module a uses b */ int use_module(struct module *a, struct module *b) { @@ -578,17 +607,11 @@ int use_module(struct module *a, struct module *b) if (err) return 0; - DEBUGP("Allocating new usage for %s.\n", a->name); - use = kmalloc(sizeof(*use), GFP_ATOMIC); - if (!use) { - printk("%s: out of memory loading\n", a->name); + err = add_module_usage(a, b); + if (err) { module_put(b); return 0; } - - use->module_which_uses = a; - list_add(&use->list, &b->modules_which_use_me); - no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name); return 1; } EXPORT_SYMBOL_GPL(use_module); @@ -596,22 +619,16 @@ EXPORT_SYMBOL_GPL(use_module); /* Clear the unload stuff of the module. */ static void module_unload_free(struct module *mod) { - struct module *i; - - list_for_each_entry(i, &modules, list) { - struct module_use *use; + struct module_use *use, *tmp; - list_for_each_entry(use, &i->modules_which_use_me, list) { - if (use->module_which_uses == mod) { - DEBUGP("%s unusing %s\n", mod->name, i->name); - module_put(i); - list_del(&use->list); - kfree(use); - sysfs_remove_link(i->holders_dir, mod->name); - /* There can be at most one match. */ - break; - } - } + list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) { + struct module *i = use->target; + DEBUGP("%s unusing %s\n", mod->name, i->name); + module_put(i); + list_del(&use->source_list); + list_del(&use->target_list); + kfree(use); + sysfs_remove_link(i->holders_dir, mod->name); } } @@ -735,7 +752,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, goto out; } - if (!list_empty(&mod->modules_which_use_me)) { + if (!list_empty(&mod->source_list)) { /* Other modules depend on us: get rid of them first. */ ret = -EWOULDBLOCK; goto out; @@ -799,9 +816,9 @@ static inline void print_unload_info(struct seq_file *m, struct module *mod) /* Always include a trailing , so userspace can differentiate between this and the old multi-field proc format. */ - list_for_each_entry(use, &mod->modules_which_use_me, list) { + list_for_each_entry(use, &mod->source_list, source_list) { printed_something = 1; - seq_printf(m, "%s,", use->module_which_uses->name); + seq_printf(m, "%s,", use->source->name); } if (mod->init != NULL && mod->exit == NULL) { -- GitLab From c8e21ced08b39ef8dfe7236fb2a923a95f645262 Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Sat, 5 Jun 2010 11:17:35 -0600 Subject: [PATCH 699/842] module: fix kdb's illicit use of struct module_use. Linus changed the structure, and luckily this didn't compile any more. Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Cc: Jason Wessel <jason.wessel@windriver.com> Cc: Martin Hicks <mort@sgi.com> --- include/linux/module.h | 7 +++++++ kernel/debug/kdb/kdb_main.c | 12 +++--------- kernel/module.c | 11 +---------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index 680db9e2ac36..5d8fca5dcff5 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -181,6 +181,13 @@ void *__symbol_get(const char *symbol); void *__symbol_get_gpl(const char *symbol); #define symbol_get(x) ((typeof(&x))(__symbol_get(MODULE_SYMBOL_PREFIX #x))) +/* modules using other modules: kdb wants to see this. */ +struct module_use { + struct list_head source_list; + struct list_head target_list; + struct module *source, *target; +}; + #ifndef __GENKSYMS__ #ifdef CONFIG_MODVERSIONS /* Mark the CRC weak since genksyms apparently decides not to diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index b724c791b6d4..184cd8209c36 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -1857,12 +1857,6 @@ static int kdb_ef(int argc, const char **argv) } #if defined(CONFIG_MODULES) -/* modules using other modules */ -struct module_use { - struct list_head list; - struct module *module_which_uses; -}; - /* * kdb_lsmod - This function implements the 'lsmod' command. Lists * currently loaded kernel modules. @@ -1894,9 +1888,9 @@ static int kdb_lsmod(int argc, const char **argv) { struct module_use *use; kdb_printf(" [ "); - list_for_each_entry(use, &mod->modules_which_use_me, - list) - kdb_printf("%s ", use->module_which_uses->name); + list_for_each_entry(use, &mod->source_list, + source_list) + kdb_printf("%s ", use->target->name); kdb_printf("]\n"); } #endif diff --git a/kernel/module.c b/kernel/module.c index be18c3e34684..bbb1d812c79c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -536,14 +536,6 @@ static void module_unload_init(struct module *mod) mod->waiter = current; } -/* modules using other modules */ -struct module_use -{ - struct list_head source_list; - struct list_head target_list; - struct module *source, *target; -}; - /* Does a already use b? */ static int already_uses(struct module *a, struct module *b) { @@ -589,8 +581,7 @@ static int add_module_usage(struct module *a, struct module *b) /* Module a uses b */ int use_module(struct module *a, struct module *b) { - struct module_use *use; - int no_warn, err; + int err; if (b == NULL || already_uses(a, b)) return 1; -- GitLab From 80a3d1bb410e000e176931a076cdf19a1e89a955 Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Sat, 5 Jun 2010 11:17:36 -0600 Subject: [PATCH 700/842] module: move sysfs exposure to end of load_module This means a little extra work, but is more logical: we don't put anything in sysfs until we're about to put the module into the global list an parse its parameters. This also gives us a logical place to put duplicate module detection in the next patch. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> --- kernel/module.c | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index bbb1d812c79c..c690d9885797 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -560,7 +560,6 @@ static int already_uses(struct module *a, struct module *b) */ static int add_module_usage(struct module *a, struct module *b) { - int no_warn; struct module_use *use; DEBUGP("Allocating new usage for %s.\n", a->name); @@ -574,7 +573,6 @@ static int add_module_usage(struct module *a, struct module *b) use->target = b; list_add(&use->source_list, &b->source_list); list_add(&use->target_list, &a->target_list); - no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name); return 0; } @@ -619,7 +617,6 @@ static void module_unload_free(struct module *mod) list_del(&use->source_list); list_del(&use->target_list); kfree(use); - sysfs_remove_link(i->holders_dir, mod->name); } } @@ -1303,6 +1300,29 @@ static inline void remove_notes_attrs(struct module *mod) #endif #ifdef CONFIG_SYSFS +static void add_usage_links(struct module *mod) +{ +#ifdef CONFIG_MODULE_UNLOAD + struct module_use *use; + int nowarn; + + list_for_each_entry(use, &mod->target_list, target_list) { + nowarn = sysfs_create_link(use->target->holders_dir, + &mod->mkobj.kobj, mod->name); + } +#endif +} + +static void del_usage_links(struct module *mod) +{ +#ifdef CONFIG_MODULE_UNLOAD + struct module_use *use; + + list_for_each_entry(use, &mod->target_list, target_list) + sysfs_remove_link(use->target->holders_dir, mod->name); +#endif +} + int module_add_modinfo_attrs(struct module *mod) { struct module_attribute *attr; @@ -1385,6 +1405,10 @@ int mod_sysfs_setup(struct module *mod, { int err; + err = mod_sysfs_init(mod); + if (err) + goto out; + mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj); if (!mod->holders_dir) { err = -ENOMEM; @@ -1399,6 +1423,8 @@ int mod_sysfs_setup(struct module *mod, if (err) goto out_unreg_param; + add_usage_links(mod); + kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD); return 0; @@ -1408,6 +1434,7 @@ out_unreg_holders: kobject_put(mod->holders_dir); out_unreg: kobject_put(&mod->mkobj.kobj); +out: return err; } @@ -1422,10 +1449,15 @@ static void mod_sysfs_fini(struct module *mod) { } +static void del_usage_links(struct module *mod) +{ +} + #endif /* CONFIG_SYSFS */ static void mod_kobject_remove(struct module *mod) { + del_usage_links(mod); module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); kobject_put(mod->mkobj.drivers_dir); @@ -2242,11 +2274,6 @@ static noinline struct module *load_module(void __user *umod, /* Now we've moved module, initialize linked lists, etc. */ module_unload_init(mod); - /* add kobject, so we can reference it. */ - err = mod_sysfs_init(mod); - if (err) - goto free_unload; - /* Set up license info based on the info section */ set_license(mod, get_modinfo(sechdrs, infoindex, "license")); @@ -2443,6 +2470,7 @@ static noinline struct module *load_module(void __user *umod, err = mod_sysfs_setup(mod, mod->kp, mod->num_kp); if (err < 0) goto unlink; + add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs); @@ -2461,9 +2489,6 @@ static noinline struct module *load_module(void __user *umod, module_arch_cleanup(mod); cleanup: free_modinfo(mod); - kobject_del(&mod->mkobj.kobj); - kobject_put(&mod->mkobj.kobj); - free_unload: module_unload_free(mod); #if defined(CONFIG_MODULE_UNLOAD) free_percpu(mod->refptr); -- GitLab From 6407ebb271fc34440b306f305e1efb7685eece26 Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Sat, 5 Jun 2010 11:17:36 -0600 Subject: [PATCH 701/842] module: Make module sysfs functions private. These were placed in the header in ef665c1a06 to get the various SYSFS/MODULE config combintations to compile. That may have been necessary then, but it's not now. These functions are all local to module.c. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Cc: Randy Dunlap <randy.dunlap@oracle.com> --- include/linux/module.h | 33 --------------------------------- kernel/module.c | 29 +++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index 5d8fca5dcff5..8a6b9fdc7ffa 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -672,43 +672,10 @@ static inline int module_get_iter_tracepoints(struct tracepoint_iter *iter) #endif /* CONFIG_MODULES */ -struct device_driver; #ifdef CONFIG_SYSFS -struct module; - extern struct kset *module_kset; extern struct kobj_type module_ktype; extern int module_sysfs_initialized; - -int mod_sysfs_init(struct module *mod); -int mod_sysfs_setup(struct module *mod, - struct kernel_param *kparam, - unsigned int num_params); -int module_add_modinfo_attrs(struct module *mod); -void module_remove_modinfo_attrs(struct module *mod); - -#else /* !CONFIG_SYSFS */ - -static inline int mod_sysfs_init(struct module *mod) -{ - return 0; -} - -static inline int mod_sysfs_setup(struct module *mod, - struct kernel_param *kparam, - unsigned int num_params) -{ - return 0; -} - -static inline int module_add_modinfo_attrs(struct module *mod) -{ - return 0; -} - -static inline void module_remove_modinfo_attrs(struct module *mod) -{ } - #endif /* CONFIG_SYSFS */ #define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x) diff --git a/kernel/module.c b/kernel/module.c index c690d9885797..808aa18dd661 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1323,7 +1323,7 @@ static void del_usage_links(struct module *mod) #endif } -int module_add_modinfo_attrs(struct module *mod) +static int module_add_modinfo_attrs(struct module *mod) { struct module_attribute *attr; struct module_attribute *temp_attr; @@ -1349,7 +1349,7 @@ int module_add_modinfo_attrs(struct module *mod) return error; } -void module_remove_modinfo_attrs(struct module *mod) +static void module_remove_modinfo_attrs(struct module *mod) { struct module_attribute *attr; int i; @@ -1365,7 +1365,7 @@ void module_remove_modinfo_attrs(struct module *mod) kfree(mod->modinfo_attrs); } -int mod_sysfs_init(struct module *mod) +static int mod_sysfs_init(struct module *mod) { int err; struct kobject *kobj; @@ -1399,7 +1399,7 @@ out: return err; } -int mod_sysfs_setup(struct module *mod, +static int mod_sysfs_setup(struct module *mod, struct kernel_param *kparam, unsigned int num_params) { @@ -1445,6 +1445,27 @@ static void mod_sysfs_fini(struct module *mod) #else /* CONFIG_SYSFS */ +static inline int mod_sysfs_init(struct module *mod) +{ + return 0; +} + +static inline int mod_sysfs_setup(struct module *mod, + struct kernel_param *kparam, + unsigned int num_params) +{ + return 0; +} + +static inline int module_add_modinfo_attrs(struct module *mod) +{ + return 0; +} + +static inline void module_remove_modinfo_attrs(struct module *mod) +{ +} + static void mod_sysfs_fini(struct module *mod) { } -- GitLab From 75676500f8298f0ee89db12db97294883c4b768e Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Sat, 5 Jun 2010 11:17:36 -0600 Subject: [PATCH 702/842] module: make locking more fine-grained. Kay Sievers <kay.sievers@vrfy.org> reports that we still have some contention over module loading which is slowing boot. Linus also disliked a previous "drop lock and regrab" patch to fix the bne2 "gave up waiting for init of module libcrc32c" message. This is more ambitious: we only grab the lock where we need it. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Cc: Brandon Philips <brandon@ifup.org> Cc: Kay Sievers <kay.sievers@vrfy.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> --- kernel/module.c | 65 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index 808aa18dd661..d293c213c22c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -72,7 +72,11 @@ /* If this is set, the section belongs in the init part of the module */ #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) -/* List of modules, protected by module_mutex or preempt_disable +/* + * Mutex protects: + * 1) List of modules (also safely readable with preempt_disable), + * 2) module_use links, + * 3) module_addr_min/module_addr_max. * (delete uses stop_machine/add uses RCU list operations). */ DEFINE_MUTEX(module_mutex); EXPORT_SYMBOL_GPL(module_mutex); @@ -90,7 +94,8 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq); static BLOCKING_NOTIFIER_HEAD(module_notify_list); -/* Bounds of module allocation, for speeding __module_address */ +/* Bounds of module allocation, for speeding __module_address. + * Protected by module_mutex. */ static unsigned long module_addr_min = -1UL, module_addr_max = 0; int register_module_notifier(struct notifier_block * nb) @@ -329,7 +334,7 @@ static bool find_symbol_in_section(const struct symsearch *syms, } /* Find a symbol and return it, along with, (optional) crc and - * (optional) module which owns it */ + * (optional) module which owns it. Needs preempt disabled or module_mutex. */ const struct kernel_symbol *find_symbol(const char *name, struct module **owner, const unsigned long **crc, @@ -576,7 +581,7 @@ static int add_module_usage(struct module *a, struct module *b) return 0; } -/* Module a uses b */ +/* Module a uses b: caller needs module_mutex() */ int use_module(struct module *a, struct module *b) { int err; @@ -610,6 +615,7 @@ static void module_unload_free(struct module *mod) { struct module_use *use, *tmp; + mutex_lock(&module_mutex); list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) { struct module *i = use->target; DEBUGP("%s unusing %s\n", mod->name, i->name); @@ -618,6 +624,7 @@ static void module_unload_free(struct module *mod) list_del(&use->target_list); kfree(use); } + mutex_unlock(&module_mutex); } #ifdef CONFIG_MODULE_FORCE_UNLOAD @@ -784,13 +791,14 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GOING, mod); async_synchronize_full(); - mutex_lock(&module_mutex); + /* Store the name of the last unloaded module for diagnostic purposes */ strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module)); ddebug_remove_module(mod->name); - free_module(mod); - out: + free_module(mod); + return 0; +out: mutex_unlock(&module_mutex); return ret; } @@ -1006,6 +1014,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, { const unsigned long *crc; + /* Since this should be found in kernel (which can't be removed), + * no locking is necessary. */ if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, &crc, true, false)) BUG(); @@ -1048,8 +1058,7 @@ static inline int same_magic(const char *amagic, const char *bmagic, } #endif /* CONFIG_MODVERSIONS */ -/* Resolve a symbol for this module. I.e. if we find one, record usage. - Must be holding module_mutex. */ +/* Resolve a symbol for this module. I.e. if we find one, record usage. */ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, unsigned int versindex, const char *name, @@ -1059,6 +1068,7 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, const struct kernel_symbol *sym; const unsigned long *crc; + mutex_lock(&module_mutex); sym = find_symbol(name, &owner, &crc, !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true); /* use_module can fail due to OOM, @@ -1068,6 +1078,7 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, || !use_module(mod, owner)) sym = NULL; } + mutex_unlock(&module_mutex); return sym; } @@ -1306,10 +1317,12 @@ static void add_usage_links(struct module *mod) struct module_use *use; int nowarn; + mutex_lock(&module_mutex); list_for_each_entry(use, &mod->target_list, target_list) { nowarn = sysfs_create_link(use->target->holders_dir, &mod->mkobj.kobj, mod->name); } + mutex_unlock(&module_mutex); #endif } @@ -1318,8 +1331,10 @@ static void del_usage_links(struct module *mod) #ifdef CONFIG_MODULE_UNLOAD struct module_use *use; + mutex_lock(&module_mutex); list_for_each_entry(use, &mod->target_list, target_list) sysfs_remove_link(use->target->holders_dir, mod->name); + mutex_unlock(&module_mutex); #endif } @@ -1497,13 +1512,15 @@ static int __unlink_module(void *_mod) return 0; } -/* Free a module, remove from lists, etc (must hold module_mutex). */ +/* Free a module, remove from lists, etc. */ static void free_module(struct module *mod) { trace_module_free(mod); /* Delete from various lists */ + mutex_lock(&module_mutex); stop_machine(__unlink_module, mod, NULL); + mutex_unlock(&module_mutex); remove_notes_attrs(mod); remove_sect_attrs(mod); mod_kobject_remove(mod); @@ -1575,7 +1592,14 @@ static int verify_export_symbols(struct module *mod) for (i = 0; i < ARRAY_SIZE(arr); i++) { for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { - if (find_symbol(s->name, &owner, NULL, true, false)) { + const struct kernel_symbol *sym; + + /* Stopping preemption makes find_symbol safe. */ + preempt_disable(); + sym = find_symbol(s->name, &owner, NULL, true, false); + preempt_enable(); + + if (sym) { printk(KERN_ERR "%s: exports duplicate symbol %s" " (owned by %s)\n", @@ -2021,11 +2045,13 @@ static void *module_alloc_update_bounds(unsigned long size) void *ret = module_alloc(size); if (ret) { + mutex_lock(&module_mutex); /* Update module bounds. */ if ((unsigned long)ret < module_addr_min) module_addr_min = (unsigned long)ret; if ((unsigned long)ret + size > module_addr_max) module_addr_max = (unsigned long)ret + size; + mutex_unlock(&module_mutex); } return ret; } @@ -2482,7 +2508,9 @@ static noinline struct module *load_module(void __user *umod, * function to insert in a way safe to concurrent readers. * The mutex protects against concurrent writers. */ + mutex_lock(&module_mutex); list_add_rcu(&mod->list, &modules); + mutex_unlock(&module_mutex); err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL); if (err < 0) @@ -2504,8 +2532,10 @@ static noinline struct module *load_module(void __user *umod, return mod; unlink: + mutex_lock(&module_mutex); /* Unlink carefully: kallsyms could be walking list. */ list_del_rcu(&mod->list); + mutex_unlock(&module_mutex); synchronize_sched(); module_arch_cleanup(mod); cleanup: @@ -2556,19 +2586,10 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, if (!capable(CAP_SYS_MODULE) || modules_disabled) return -EPERM; - /* Only one module load at a time, please */ - if (mutex_lock_interruptible(&module_mutex) != 0) - return -EINTR; - /* Do all the hard work */ mod = load_module(umod, len, uargs); - if (IS_ERR(mod)) { - mutex_unlock(&module_mutex); + if (IS_ERR(mod)) return PTR_ERR(mod); - } - - /* Drop lock so they can recurse */ - mutex_unlock(&module_mutex); blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); @@ -2585,9 +2606,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, module_put(mod); blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GOING, mod); - mutex_lock(&module_mutex); free_module(mod); - mutex_unlock(&module_mutex); wake_up(&module_wq); return ret; } -- GitLab From 3bafeb6247042dcbb72b0141ec7c7107de9f0b99 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Sat, 5 Jun 2010 11:17:36 -0600 Subject: [PATCH 703/842] module: move find_module check to end I think Rusty may have made the lock a bit _too_ finegrained there, and didn't add it to some places that needed it. It looks, for example, like PATCH 1/2 actually drops the lock in places where it's needed ("find_module()" is documented to need it, but now load_module() didn't hold it at all when it did the find_module()). Rather than adding a new "module_loading" list, I think we should be able to just use the existing "modules" list, and just fix up the locking a bit. In fact, maybe we could just move the "look up existing module" a bit later - optimistically assuming that the module doesn't exist, and then just undoing the work if it turns out that we were wrong, just before adding ourselves to the list. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> --- kernel/module.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index d293c213c22c..28450047852a 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2226,11 +2226,6 @@ static noinline struct module *load_module(void __user *umod, goto free_mod; } - if (find_module(mod->name)) { - err = -EEXIST; - goto free_mod; - } - mod->state = MODULE_STATE_COMING; /* Allow arches to frob section contents and sizes. */ @@ -2509,6 +2504,12 @@ static noinline struct module *load_module(void __user *umod, * The mutex protects against concurrent writers. */ mutex_lock(&module_mutex); + if (find_module(mod->name)) { + err = -EEXIST; + /* This will also unlock the mutex */ + goto already_exists; + } + list_add_rcu(&mod->list, &modules); mutex_unlock(&module_mutex); @@ -2535,6 +2536,7 @@ static noinline struct module *load_module(void __user *umod, mutex_lock(&module_mutex); /* Unlink carefully: kallsyms could be walking list. */ list_del_rcu(&mod->list); + already_exists: mutex_unlock(&module_mutex); synchronize_sched(); module_arch_cleanup(mod); -- GitLab From be593f4ce4eb1bd40e38fdc403371f149f6f12eb Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Sat, 5 Jun 2010 11:17:37 -0600 Subject: [PATCH 704/842] module: verify_export_symbols under the lock It disabled preempt so it was "safe", but nothing stops another module slipping in before this module is added to the global list now we don't hold the lock the whole time. So we check this just after we check for duplicate modules, and just before we put the module in the global list. (find_symbol finds symbols in coming and going modules, too). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> --- kernel/module.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index 28450047852a..f99558e1945a 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1571,6 +1571,8 @@ EXPORT_SYMBOL_GPL(__symbol_get); /* * Ensure that an exported symbol [global namespace] does not already exist * in the kernel or in some other module's exported symbol table. + * + * You must hold the module_mutex. */ static int verify_export_symbols(struct module *mod) { @@ -1592,14 +1594,7 @@ static int verify_export_symbols(struct module *mod) for (i = 0; i < ARRAY_SIZE(arr); i++) { for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { - const struct kernel_symbol *sym; - - /* Stopping preemption makes find_symbol safe. */ - preempt_disable(); - sym = find_symbol(s->name, &owner, NULL, true, false); - preempt_enable(); - - if (sym) { + if (find_symbol(s->name, &owner, NULL, true, false)) { printk(KERN_ERR "%s: exports duplicate symbol %s" " (owned by %s)\n", @@ -2440,11 +2435,6 @@ static noinline struct module *load_module(void __user *umod, goto cleanup; } - /* Find duplicate symbols */ - err = verify_export_symbols(mod); - if (err < 0) - goto cleanup; - /* Set up and sort exception table */ mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table", sizeof(*mod->extable), &mod->num_exentries); @@ -2506,10 +2496,14 @@ static noinline struct module *load_module(void __user *umod, mutex_lock(&module_mutex); if (find_module(mod->name)) { err = -EEXIST; - /* This will also unlock the mutex */ - goto already_exists; + goto unlock; } + /* Find duplicate symbols */ + err = verify_export_symbols(mod); + if (err < 0) + goto unlock; + list_add_rcu(&mod->list, &modules); mutex_unlock(&module_mutex); @@ -2536,7 +2530,7 @@ static noinline struct module *load_module(void __user *umod, mutex_lock(&module_mutex); /* Unlink carefully: kallsyms could be walking list. */ list_del_rcu(&mod->list); - already_exists: + unlock: mutex_unlock(&module_mutex); synchronize_sched(); module_arch_cleanup(mod); -- GitLab From 9bea7f23952d5948f8e5dfdff4de09bb9981fb5f Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Sat, 5 Jun 2010 11:17:37 -0600 Subject: [PATCH 705/842] module: fix bne2 "gave up waiting for init of module libcrc32c" Problem: it's hard to avoid an init routine stumbling over a request_module these days. And it's not clear it's always a bad idea: for example, a module like kvm with dynamic dependencies on kvm-intel or kvm-amd would be neater if it could simply request_module the right one. In this particular case, it's libcrc32c: libcrc32c_mod_init crypto_alloc_shash crypto_alloc_tfm crypto_find_alg crypto_alg_mod_lookup crypto_larval_lookup request_module If another module is waiting inside resolve_symbol() for libcrc32c to finish initializing (ie. bne2 depends on libcrc32c) then it does so holding the module lock, and our request_module() can't make progress until that is released. Waiting inside resolve_symbol() without the lock isn't all that hard: we just need to pass the -EBUSY up the call chain so we can sleep where we don't hold the lock. Error reporting is a bit trickier: we need to copy the name of the unfinished module before releasing the lock. Other notes: 1) This also fixes a theoretical issue where a weak dependency would allow symbol version mismatches to be ignored. 2) We rename use_module to ref_module to make life easier for the only external user (the out-of-tree ksplice patches). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Tim Abbot <tabbott@ksplice.com> Tested-by: Brandon Philips <bphilips@suse.de> --- kernel/module.c | 91 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 32 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index f99558e1945a..8c6b42840dd1 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -582,33 +582,26 @@ static int add_module_usage(struct module *a, struct module *b) } /* Module a uses b: caller needs module_mutex() */ -int use_module(struct module *a, struct module *b) +int ref_module(struct module *a, struct module *b) { int err; - if (b == NULL || already_uses(a, b)) return 1; - - /* If we're interrupted or time out, we fail. */ - if (wait_event_interruptible_timeout( - module_wq, (err = strong_try_module_get(b)) != -EBUSY, - 30 * HZ) <= 0) { - printk("%s: gave up waiting for init of module %s.\n", - a->name, b->name); + if (b == NULL || already_uses(a, b)) return 0; - } - /* If strong_try_module_get() returned a different error, we fail. */ + /* If module isn't available, we fail. */ + err = strong_try_module_get(b); if (err) - return 0; + return err; err = add_module_usage(a, b); if (err) { module_put(b); - return 0; + return err; } - return 1; + return 0; } -EXPORT_SYMBOL_GPL(use_module); +EXPORT_SYMBOL_GPL(ref_module); /* Clear the unload stuff of the module. */ static void module_unload_free(struct module *mod) @@ -893,11 +886,11 @@ static inline void module_unload_free(struct module *mod) { } -int use_module(struct module *a, struct module *b) +int ref_module(struct module *a, struct module *b) { - return strong_try_module_get(b) == 0; + return strong_try_module_get(b); } -EXPORT_SYMBOL_GPL(use_module); +EXPORT_SYMBOL_GPL(ref_module); static inline void module_unload_init(struct module *mod) { @@ -1062,26 +1055,58 @@ static inline int same_magic(const char *amagic, const char *bmagic, static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, unsigned int versindex, const char *name, - struct module *mod) + struct module *mod, + char ownername[]) { struct module *owner; const struct kernel_symbol *sym; const unsigned long *crc; + int err; mutex_lock(&module_mutex); sym = find_symbol(name, &owner, &crc, !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true); - /* use_module can fail due to OOM, - or module initialization or unloading */ - if (sym) { - if (!check_version(sechdrs, versindex, name, mod, crc, owner) - || !use_module(mod, owner)) - sym = NULL; + if (!sym) + goto unlock; + + if (!check_version(sechdrs, versindex, name, mod, crc, owner)) { + sym = ERR_PTR(-EINVAL); + goto getname; } + + err = ref_module(mod, owner); + if (err) { + sym = ERR_PTR(err); + goto getname; + } + +getname: + /* We must make copy under the lock if we failed to get ref. */ + strncpy(ownername, module_name(owner), MODULE_NAME_LEN); +unlock: mutex_unlock(&module_mutex); return sym; } +static const struct kernel_symbol *resolve_symbol_wait(Elf_Shdr *sechdrs, + unsigned int versindex, + const char *name, + struct module *mod) +{ + const struct kernel_symbol *ksym; + char ownername[MODULE_NAME_LEN]; + + if (wait_event_interruptible_timeout(module_wq, + !IS_ERR(ksym = resolve_symbol(sechdrs, versindex, name, + mod, ownername)) || + PTR_ERR(ksym) != -EBUSY, + 30 * HZ) <= 0) { + printk(KERN_WARNING "%s: gave up waiting for init of module %s.\n", + mod->name, ownername); + } + return ksym; +} + /* * /sys/module/foo/sections stuff * J. Corbet <corbet@lwn.net> @@ -1638,21 +1663,23 @@ static int simplify_symbols(Elf_Shdr *sechdrs, break; case SHN_UNDEF: - ksym = resolve_symbol(sechdrs, versindex, - strtab + sym[i].st_name, mod); + ksym = resolve_symbol_wait(sechdrs, versindex, + strtab + sym[i].st_name, + mod); /* Ok if resolved. */ - if (ksym) { + if (ksym && !IS_ERR(ksym)) { sym[i].st_value = ksym->value; break; } /* Ok if weak. */ - if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK) + if (!ksym && ELF_ST_BIND(sym[i].st_info) == STB_WEAK) break; - printk(KERN_WARNING "%s: Unknown symbol %s\n", - mod->name, strtab + sym[i].st_name); - ret = -ENOENT; + printk(KERN_WARNING "%s: Unknown symbol %s (err %li)\n", + mod->name, strtab + sym[i].st_name, + PTR_ERR(ksym)); + ret = PTR_ERR(ksym) ?: -ENOENT; break; default: -- GitLab From 72e09ad107e78d69ff4d3b97a69f0aad2b77280f Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Sat, 5 Jun 2010 03:03:30 -0700 Subject: [PATCH 706/842] ipv6: avoid high order allocations With mtu=9000, mld_newpack() use order-2 GFP_ATOMIC allocations, that are very unreliable, on machines where PAGE_SIZE=4K Limit allocated skbs to be at most one page. (order-0 allocations) Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv6/mcast.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 59f1881968c7..ab1622d7d409 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1356,7 +1356,10 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) IPV6_TLV_PADN, 0 }; /* we assume size > sizeof(ra) here */ - skb = sock_alloc_send_skb(sk, size + LL_ALLOCATED_SPACE(dev), 1, &err); + size += LL_ALLOCATED_SPACE(dev); + /* limit our allocations to order-0 page */ + size = min_t(int, size, SKB_MAX_ORDER(0, 0)); + skb = sock_alloc_send_skb(sk, size, 1, &err); if (!skb) return NULL; -- GitLab From 84a8dce2710cc425089a2b92acc354d4fbb5788d Mon Sep 17 00:00:00 2001 From: Dmitry Monakhov <dmonakhov@openvz.org> Date: Sat, 5 Jun 2010 11:51:27 -0400 Subject: [PATCH 707/842] ext4: Fix remaining racy updates of EXT4_I(inode)->i_flags A few functions were still modifying i_flags in a racy manner. Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> --- fs/ext4/inode.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 19df61c321fd..42272d67955a 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4942,20 +4942,26 @@ void ext4_set_inode_flags(struct inode *inode) /* Propagate flags from i_flags to EXT4_I(inode)->i_flags */ void ext4_get_inode_flags(struct ext4_inode_info *ei) { - unsigned int flags = ei->vfs_inode.i_flags; - - ei->i_flags &= ~(EXT4_SYNC_FL|EXT4_APPEND_FL| - EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL|EXT4_DIRSYNC_FL); - if (flags & S_SYNC) - ei->i_flags |= EXT4_SYNC_FL; - if (flags & S_APPEND) - ei->i_flags |= EXT4_APPEND_FL; - if (flags & S_IMMUTABLE) - ei->i_flags |= EXT4_IMMUTABLE_FL; - if (flags & S_NOATIME) - ei->i_flags |= EXT4_NOATIME_FL; - if (flags & S_DIRSYNC) - ei->i_flags |= EXT4_DIRSYNC_FL; + unsigned int vfs_fl; + unsigned long old_fl, new_fl; + + do { + vfs_fl = ei->vfs_inode.i_flags; + old_fl = ei->i_flags; + new_fl = old_fl & ~(EXT4_SYNC_FL|EXT4_APPEND_FL| + EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL| + EXT4_DIRSYNC_FL); + if (vfs_fl & S_SYNC) + new_fl |= EXT4_SYNC_FL; + if (vfs_fl & S_APPEND) + new_fl |= EXT4_APPEND_FL; + if (vfs_fl & S_IMMUTABLE) + new_fl |= EXT4_IMMUTABLE_FL; + if (vfs_fl & S_NOATIME) + new_fl |= EXT4_NOATIME_FL; + if (vfs_fl & S_DIRSYNC) + new_fl |= EXT4_DIRSYNC_FL; + } while (cmpxchg(&ei->i_flags, old_fl, new_fl) != old_fl); } static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, @@ -5191,7 +5197,7 @@ static int ext4_inode_blocks_set(handle_t *handle, */ raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); raw_inode->i_blocks_high = 0; - ei->i_flags &= ~EXT4_HUGE_FILE_FL; + ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE); return 0; } if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) @@ -5204,9 +5210,9 @@ static int ext4_inode_blocks_set(handle_t *handle, */ raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32); - ei->i_flags &= ~EXT4_HUGE_FILE_FL; + ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE); } else { - ei->i_flags |= EXT4_HUGE_FILE_FL; + ext4_set_inode_flag(inode, EXT4_INODE_HUGE_FILE); /* i_block is stored in file system block size */ i_blocks = i_blocks >> (inode->i_blkbits - 9); raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); -- GitLab From e7b526bb852cdd67b24e174da6850222f8da41b1 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 2 Jun 2010 08:30:48 +0100 Subject: [PATCH 708/842] drm/i915: Move non-phys cursors into the GTT Cursors need to be in the GTT domain when being accessed by the GPU. Previously this was a fortuitous byproduct of userspace using pwrite() to upload the image data into the cursor. The redundant clflush was removed in commit 9b8c4a and so the image was no longer being flushed out of the caches into main memory. One could also devise a scenario where the cursor was rendered by the GPU, prior to being attached as the cursor, resulting in similar corruption due to the missing MI_FLUSH. Fixes: Bug 28335 - Cursor corruption caused by commit 9b8c4a0b21 https://bugs.freedesktop.org/show_bug.cgi?id=28335 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reported-and-tested-by: Jeff Chua <jeff.chua.linux@gmail.com> Tested-by: Linus Torvalds <torvalds@linux-foundation.org> Reported-by: Andy Isaacson <adi@hexapodia.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/gpu/drm/i915/intel_display.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 88a1ab7c05ce..04e1bb499ff8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3973,6 +3973,13 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, DRM_ERROR("failed to pin cursor bo\n"); goto fail_locked; } + + ret = i915_gem_object_set_to_gtt_domain(bo, 0); + if (ret) { + DRM_ERROR("failed to move cursor bo into the GTT\n"); + goto fail_unpin; + } + addr = obj_priv->gtt_offset; } else { ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1); @@ -4016,6 +4023,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, intel_crtc->cursor_bo = bo; return 0; +fail_unpin: + i915_gem_object_unpin(bo); fail_locked: mutex_unlock(&dev->struct_mutex); fail: -- GitLab From e44a21b7268a022c7749f521c06214145bd161e4 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Sat, 5 Jun 2010 20:43:24 -0700 Subject: [PATCH 709/842] Linux 2.6.35-rc2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index efdc3d0d8e60..654c31aaec64 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 35 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = Sheep on Meth # *DOCUMENTATION* -- GitLab From a6866ac93e6cb68091326e80b4fa4619a5957644 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> Date: Thu, 20 May 2010 10:54:40 -0700 Subject: [PATCH 710/842] iwl3945: enable stuck queue detection on 3945 We learn from http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=1834 and https://bugzilla.redhat.com/show_bug.cgi?id=589777 that 3945 can also suffer from a stuck command queue. Enable stuck queue detection for iwl3945 to enable recovery in this case. Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> --- drivers/net/wireless/iwlwifi/iwl-3945.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 068f7f8435c5..c44a303e62ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2852,6 +2852,7 @@ static struct iwl_lib_ops iwl3945_lib = { .isr = iwl_isr_legacy, .config_ap = iwl3945_config_ap, .manage_ibss_station = iwl3945_manage_ibss_station, + .recover_from_tx_stall = iwl_bg_monitor_recover, .check_plcp_health = iwl3945_good_plcp_health, .debugfs_ops = { -- GitLab From 1402364162afbaac1b8a74ee21aeb013e817ac7d Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar <abhijeet.kolekar@intel.com> Date: Wed, 2 Jun 2010 21:15:10 -0700 Subject: [PATCH 711/842] iwl3945: fix internal scan Port of internal scan to iwl3945 missed introduction of iwl3945_get_single_channel_for_scan. Fix the following bug by introducing the iwl3945_get_single_channel_for_scan http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2208 Signed-off-by: Abhijeet Kolekar <abhijeet.kolekar@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 30 +---------- drivers/net/wireless/iwlwifi/iwl-core.c | 39 ++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 + drivers/net/wireless/iwlwifi/iwl3945-base.c | 56 +++++++++++++++++++-- 4 files changed, 96 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 1004cfc403b1..0f292a210ed9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1119,10 +1119,9 @@ static int iwl_get_single_channel_for_scan(struct iwl_priv *priv, struct iwl_scan_channel *scan_ch) { const struct ieee80211_supported_band *sband; - const struct iwl_channel_info *ch_info; u16 passive_dwell = 0; u16 active_dwell = 0; - int i, added = 0; + int added = 0; u16 channel = 0; sband = iwl_get_hw_mode(priv, band); @@ -1137,32 +1136,7 @@ static int iwl_get_single_channel_for_scan(struct iwl_priv *priv, if (passive_dwell <= active_dwell) passive_dwell = active_dwell + 1; - /* only scan single channel, good enough to reset the RF */ - /* pick the first valid not in-use channel */ - if (band == IEEE80211_BAND_5GHZ) { - for (i = 14; i < priv->channel_count; i++) { - if (priv->channel_info[i].channel != - le16_to_cpu(priv->staging_rxon.channel)) { - channel = priv->channel_info[i].channel; - ch_info = iwl_get_channel_info(priv, - band, channel); - if (is_channel_valid(ch_info)) - break; - } - } - } else { - for (i = 0; i < 14; i++) { - if (priv->channel_info[i].channel != - le16_to_cpu(priv->staging_rxon.channel)) { - channel = - priv->channel_info[i].channel; - ch_info = iwl_get_channel_info(priv, - band, channel); - if (is_channel_valid(ch_info)) - break; - } - } - } + channel = iwl_get_single_channel_number(priv, band); if (channel) { scan_ch->channel = cpu_to_le16(channel); scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5a7eca8fb789..426e95567de3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -854,6 +854,45 @@ void iwl_set_rxon_chain(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_set_rxon_chain); +/* Return valid channel */ +u8 iwl_get_single_channel_number(struct iwl_priv *priv, + enum ieee80211_band band) +{ + const struct iwl_channel_info *ch_info; + int i; + u8 channel = 0; + + /* only scan single channel, good enough to reset the RF */ + /* pick the first valid not in-use channel */ + if (band == IEEE80211_BAND_5GHZ) { + for (i = 14; i < priv->channel_count; i++) { + if (priv->channel_info[i].channel != + le16_to_cpu(priv->staging_rxon.channel)) { + channel = priv->channel_info[i].channel; + ch_info = iwl_get_channel_info(priv, + band, channel); + if (is_channel_valid(ch_info)) + break; + } + } + } else { + for (i = 0; i < 14; i++) { + if (priv->channel_info[i].channel != + le16_to_cpu(priv->staging_rxon.channel)) { + channel = + priv->channel_info[i].channel; + ch_info = iwl_get_channel_info(priv, + band, channel); + if (is_channel_valid(ch_info)) + break; + } + } + } + + return channel; +} +EXPORT_SYMBOL(iwl_get_single_channel_number); + /** * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7e5a5ba41fd2..31775bd9c361 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -343,6 +343,8 @@ int iwl_check_rxon_cmd(struct iwl_priv *priv); int iwl_full_rxon_required(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); +u8 iwl_get_single_channel_number(struct iwl_priv *priv, + enum ieee80211_band band); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf); u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, struct ieee80211_sta_ht_cap *sta_ht_inf); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 3e5bffb6034f..6c353cacc8d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1844,6 +1844,49 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) #endif } +static int iwl3945_get_single_channel_for_scan(struct iwl_priv *priv, + struct ieee80211_vif *vif, + enum ieee80211_band band, + struct iwl3945_scan_channel *scan_ch) +{ + const struct ieee80211_supported_band *sband; + u16 passive_dwell = 0; + u16 active_dwell = 0; + int added = 0; + u8 channel = 0; + + sband = iwl_get_hw_mode(priv, band); + if (!sband) { + IWL_ERR(priv, "invalid band\n"); + return added; + } + + active_dwell = iwl_get_active_dwell_time(priv, band, 0); + passive_dwell = iwl_get_passive_dwell_time(priv, band, vif); + + if (passive_dwell <= active_dwell) + passive_dwell = active_dwell + 1; + + + channel = iwl_get_single_channel_number(priv, band); + + if (channel) { + scan_ch->channel = channel; + scan_ch->type = 0; /* passive */ + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + /* Set txpower levels to defaults */ + scan_ch->tpc.dsp_atten = 110; + if (band == IEEE80211_BAND_5GHZ) + scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; + else + scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); + added++; + } else + IWL_ERR(priv, "no valid channel found\n"); + return added; +} + static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, enum ieee80211_band band, u8 is_active, u8 n_probes, @@ -2992,9 +3035,16 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) /* select Rx antennas */ scan->flags |= iwl3945_get_antenna_flags(priv); - scan->channel_count = - iwl3945_get_channels_for_scan(priv, band, is_active, n_probes, - (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)], vif); + if (priv->is_internal_short_scan) { + scan->channel_count = + iwl3945_get_single_channel_for_scan(priv, vif, band, + (void *)&scan->data[le16_to_cpu( + scan->tx_cmd.len)]); + } else { + scan->channel_count = + iwl3945_get_channels_for_scan(priv, band, is_active, n_probes, + (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)], vif); + } if (scan->channel_count == 0) { IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); -- GitLab From 9edc71b746efeaadc40e668964b76cda81fef386 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy <wey-yi.w.guy@intel.com> Date: Wed, 2 Jun 2010 15:17:49 -0700 Subject: [PATCH 712/842] iwlwifi: add name to Maintainers list Add "Wey-Yi Guy" to maintainers list for iwlwifi. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 22a49e68c8b9..8d51903a6627 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3009,6 +3009,7 @@ F: include/linux/wimax/i2400m.h INTEL WIRELESS WIFI LINK (iwlwifi) M: Zhu Yi <yi.zhu@intel.com> M: Reinette Chatre <reinette.chatre@intel.com> +M: Wey-Yi Guy <wey-yi.w.guy@intel.com> M: Intel Linux Wireless <ilw@linux.intel.com> L: linux-wireless@vger.kernel.org W: http://intellinuxwireless.org -- GitLab From 7d47618a2ade0cb6d8a0b2597029c383c1662fa0 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Date: Sun, 23 May 2010 00:14:08 -0700 Subject: [PATCH 713/842] iwlwifi: move sysfs_create_group to post request firmware Move the sysfs_create_group to iwl_ucode_callback after we have safely got the firmware. The motivation to do this comes from a warning from lockdep which detected that we request priv->mutex while holding s_active during a sysfs request (show_statistics in the example copy pasted). The reverse order exists upon request_firmware: request_firmware which is a sysfs operation that requires s_active is run under priv->mutex. This ensures that we don't get sysfs request before we finish to request the firmware, avoiding this deadlock. ======================================================= [ INFO: possible circular locking dependency detected ] ------------------------------------------------------- cat/2595 is trying to acquire lock: (&priv->mutex){+.+.+.}, at: [<facfa598>] show_statistics+0x48/0x100 [iwlagn] but task is already holding lock: (s_active){++++.+}, at: [<c0580ebd>] sysfs_get_active_two+0x1d/0x50 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (s_active){++++.+}: [<c0489b74>] __lock_acquire+0xc44/0x1230 [<c048a1ed>] lock_acquire+0x8d/0x110 [<c0581499>] sysfs_addrm_finish+0xe9/0x180 [<c057f64a>] sysfs_hash_and_remove+0x4a/0x80 [<c05829d4>] sysfs_remove_group+0x44/0xd0 [<c0714b75>] dpm_sysfs_remove+0x15/0x20 [<c070dac8>] device_del+0x38/0x170 [<c070dc1e>] device_unregister+0x1e/0x60 [<c071838d>] _request_firmware+0x29d/0x550 [<c07186c7>] request_firmware+0x17/0x20 [<fad01bf1>] iwl_mac_start+0xb1/0x1230 [iwlagn] [<fa46ba06>] ieee80211_open+0x436/0x6f0 [mac80211] [<c0808cd2>] dev_open+0x92/0xf0 [<c0808b2b>] dev_change_flags+0x7b/0x190 [<c08148e8>] do_setlink+0x178/0x3b0 [<c0815169>] rtnl_setlink+0xf9/0x130 [<c081453b>] rtnetlink_rcv_msg+0x1bb/0x1f0 [<c0827ce6>] netlink_rcv_skb+0x86/0xa0 [<c081436c>] rtnetlink_rcv+0x1c/0x30 [<c08279c3>] netlink_unicast+0x263/0x290 [<c0828768>] netlink_sendmsg+0x1c8/0x2a0 [<c07f85fd>] sock_sendmsg+0xcd/0x100 [<c07f964d>] sys_sendmsg+0x15d/0x290 [<c07f9e6b>] sys_socketcall+0xeb/0x2a0 [<c040ad9f>] sysenter_do_call+0x12/0x38 -> #0 (&priv->mutex){+.+.+.}: [<c0489f84>] __lock_acquire+0x1054/0x1230 [<c048a1ed>] lock_acquire+0x8d/0x110 [<c08bb358>] __mutex_lock_common+0x58/0x470 [<c08bb84a>] mutex_lock_nested+0x3a/0x50 [<facfa598>] show_statistics+0x48/0x100 [iwlagn] [<c070d219>] dev_attr_show+0x29/0x50 [<c057fecd>] sysfs_read_file+0xdd/0x190 [<c052880f>] vfs_read+0x9f/0x190 [<c0528d22>] sys_read+0x42/0x70 [<c040ad9f>] sysenter_do_call+0x12/0x38 other info that might help us debug this: 3 locks held by cat/2595: #0: (&buffer->mutex){+.+.+.}, at: [<c057fe25>] sysfs_read_file+0x35/0x190 #1: (s_active){++++.+}, at: [<c0580ecd>] sysfs_get_active_two+0x2d/0x50 #2: (s_active){++++.+}, at: [<c0580ebd>] sysfs_get_active_two+0x1d/0x50 stack backtrace: Pid: 2595, comm: cat Not tainted 2.6.33-tp-rc4 #2 Call Trace: [<c08b99ab>] ? printk+0x1d/0x22 [<c0487752>] print_circular_bug+0xc2/0xd0 [<c0489f84>] __lock_acquire+0x1054/0x1230 [<c0478d81>] ? sched_clock_cpu+0x121/0x180 [<c048a1ed>] lock_acquire+0x8d/0x110 [<facfa598>] ? show_statistics+0x48/0x100 [iwlagn] [<c08bb358>] __mutex_lock_common+0x58/0x470 [<facfa598>] ? show_statistics+0x48/0x100 [iwlagn] [<c08bb84a>] mutex_lock_nested+0x3a/0x50 [<facfa598>] ? show_statistics+0x48/0x100 [iwlagn] [<facfa598>] show_statistics+0x48/0x100 [iwlagn] [<c0580cf9>] ? sysfs_get_active+0x69/0xb0 [<facfa550>] ? show_statistics+0x0/0x100 [iwlagn] [<c070d219>] dev_attr_show+0x29/0x50 [<c057fecd>] sysfs_read_file+0xdd/0x190 [<c05ff314>] ? security_file_permission+0x14/0x20 [<c0528242>] ? rw_verify_area+0x62/0xd0 [<c052880f>] vfs_read+0x9f/0x190 [<c047745b>] ? up_read+0x1b/0x30 [<c057fdf0>] ? sysfs_read_file+0x0/0x190 [<c04af3b4>] ? audit_syscall_entry+0x1f4/0x220 [<c0528d22>] sys_read+0x42/0x70 [<c040ad9f>] sysenter_do_call+0x12/0x38 Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> --- drivers/net/wireless/iwlwifi/iwl-agn.c | 318 ++++++++++++------------- 1 file changed, 159 insertions(+), 159 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index aef4f71f1981..7726e67044c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1484,6 +1484,156 @@ bool iwl_good_ack_health(struct iwl_priv *priv, } +/***************************************************************************** + * + * sysfs attributes + * + *****************************************************************************/ + +#ifdef CONFIG_IWLWIFI_DEBUG + +/* + * The following adds a new attribute to the sysfs representation + * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/) + * used for controlling the debug level. + * + * See the level definitions in iwl for details. + * + * The debug_level being managed using sysfs below is a per device debug + * level that is used instead of the global debug level if it (the per + * device debug level) is set. + */ +static ssize_t show_debug_level(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); +} +static ssize_t store_debug_level(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 0, &val); + if (ret) + IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); + else { + priv->debug_level = val; + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, + "Not enough memory to generate traffic log\n"); + } + return strnlen(buf, count); +} + +static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, + show_debug_level, store_debug_level); + + +#endif /* CONFIG_IWLWIFI_DEBUG */ + + +static ssize_t show_temperature(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + return sprintf(buf, "%d\n", priv->temperature); +} + +static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); + +static ssize_t show_tx_power(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + if (!iwl_is_ready_rf(priv)) + return sprintf(buf, "off\n"); + else + return sprintf(buf, "%d\n", priv->tx_power_user_lmt); +} + +static ssize_t store_tx_power(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + IWL_INFO(priv, "%s is not in decimal form.\n", buf); + else { + ret = iwl_set_tx_power(priv, val, false); + if (ret) + IWL_ERR(priv, "failed setting tx power (0x%d).\n", + ret); + else + ret = count; + } + return ret; +} + +static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); + +static ssize_t show_rts_ht_protection(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + return sprintf(buf, "%s\n", + priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self"); +} + +static ssize_t store_rts_ht_protection(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + IWL_INFO(priv, "Input is not in decimal form.\n"); + else { + if (!iwl_is_associated(priv)) + priv->cfg->use_rts_for_ht = val ? true : false; + else + IWL_ERR(priv, "Sta associated with AP - " + "Change protection mechanism is not allowed\n"); + ret = count; + } + return ret; +} + +static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO, + show_rts_ht_protection, store_rts_ht_protection); + + +static struct attribute *iwl_sysfs_entries[] = { + &dev_attr_temperature.attr, + &dev_attr_tx_power.attr, + &dev_attr_rts_ht_protection.attr, +#ifdef CONFIG_IWLWIFI_DEBUG + &dev_attr_debug_level.attr, +#endif + NULL +}; + +static struct attribute_group iwl_attribute_group = { + .name = NULL, /* put in device directory */ + .attrs = iwl_sysfs_entries, +}; + /****************************************************************************** * * uCode download functions @@ -1965,6 +2115,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) if (err) IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); + err = sysfs_create_group(&priv->pci_dev->dev.kobj, + &iwl_attribute_group); + if (err) { + IWL_ERR(priv, "failed to create sysfs device attributes\n"); + goto out_unbind; + } + /* We have our copies now, allow OS release its copies */ release_firmware(ucode_raw); complete(&priv->_agn.firmware_loading_complete); @@ -3262,141 +3419,6 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, return 0; } -/***************************************************************************** - * - * sysfs attributes - * - *****************************************************************************/ - -#ifdef CONFIG_IWLWIFI_DEBUG - -/* - * The following adds a new attribute to the sysfs representation - * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/) - * used for controlling the debug level. - * - * See the level definitions in iwl for details. - * - * The debug_level being managed using sysfs below is a per device debug - * level that is used instead of the global debug level if it (the per - * device debug level) is set. - */ -static ssize_t show_debug_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); -} -static ssize_t store_debug_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - unsigned long val; - int ret; - - ret = strict_strtoul(buf, 0, &val); - if (ret) - IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); - else { - priv->debug_level = val; - if (iwl_alloc_traffic_mem(priv)) - IWL_ERR(priv, - "Not enough memory to generate traffic log\n"); - } - return strnlen(buf, count); -} - -static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, - show_debug_level, store_debug_level); - - -#endif /* CONFIG_IWLWIFI_DEBUG */ - - -static ssize_t show_temperature(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - return sprintf(buf, "%d\n", priv->temperature); -} - -static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); - -static ssize_t show_tx_power(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - if (!iwl_is_ready_rf(priv)) - return sprintf(buf, "off\n"); - else - return sprintf(buf, "%d\n", priv->tx_power_user_lmt); -} - -static ssize_t store_tx_power(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - unsigned long val; - int ret; - - ret = strict_strtoul(buf, 10, &val); - if (ret) - IWL_INFO(priv, "%s is not in decimal form.\n", buf); - else { - ret = iwl_set_tx_power(priv, val, false); - if (ret) - IWL_ERR(priv, "failed setting tx power (0x%d).\n", - ret); - else - ret = count; - } - return ret; -} - -static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); - -static ssize_t show_rts_ht_protection(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - return sprintf(buf, "%s\n", - priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self"); -} - -static ssize_t store_rts_ht_protection(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - unsigned long val; - int ret; - - ret = strict_strtoul(buf, 10, &val); - if (ret) - IWL_INFO(priv, "Input is not in decimal form.\n"); - else { - if (!iwl_is_associated(priv)) - priv->cfg->use_rts_for_ht = val ? true : false; - else - IWL_ERR(priv, "Sta associated with AP - " - "Change protection mechanism is not allowed\n"); - ret = count; - } - return ret; -} - -static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO, - show_rts_ht_protection, store_rts_ht_protection); - - /***************************************************************************** * * driver setup and teardown @@ -3550,21 +3572,6 @@ static void iwl_uninit_drv(struct iwl_priv *priv) kfree(priv->scan_cmd); } -static struct attribute *iwl_sysfs_entries[] = { - &dev_attr_temperature.attr, - &dev_attr_tx_power.attr, - &dev_attr_rts_ht_protection.attr, -#ifdef CONFIG_IWLWIFI_DEBUG - &dev_attr_debug_level.attr, -#endif - NULL -}; - -static struct attribute_group iwl_attribute_group = { - .name = NULL, /* put in device directory */ - .attrs = iwl_sysfs_entries, -}; - static struct ieee80211_ops iwl_hw_ops = { .tx = iwl_mac_tx, .start = iwl_mac_start, @@ -3750,11 +3757,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); goto out_disable_msi; } - err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); - if (err) { - IWL_ERR(priv, "failed to create sysfs device attributes\n"); - goto out_free_irq; - } iwl_setup_deferred_work(priv); iwl_setup_rx_handlers(priv); @@ -3788,15 +3790,13 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = iwl_request_firmware(priv, true); if (err) - goto out_remove_sysfs; + goto out_destroy_workqueue; return 0; - out_remove_sysfs: + out_destroy_workqueue: destroy_workqueue(priv->workqueue); priv->workqueue = NULL; - sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); - out_free_irq: free_irq(priv->pci_dev->irq, priv); iwl_free_isr_ict(priv); out_disable_msi: -- GitLab From 1c24d06f8e065023ebb428db5af5514500839ee6 Mon Sep 17 00:00:00 2001 From: Jan Kara <jack@suse.cz> Date: Fri, 4 Jun 2010 17:07:55 +0200 Subject: [PATCH 714/842] jffs2: update ctime when changing the file's permission by setfacl jffs2 didn't update the ctime of the file when its permission was changed. Steps to reproduce: # touch aaa # stat -c %Z aaa 1275289822 # setfacl -m 'u::x,g::x,o::x' aaa # stat -c %Z aaa 1275289822 <- unchanged But, according to the spec of the ctime, jffs2 must update it. Port of ext3 patch by Miao Xie <miaox@cn.fujitsu.com>. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> --- fs/jffs2/acl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 7cdc3196476a..64d3b4b48dbf 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c @@ -234,8 +234,9 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) if (inode->i_mode != mode) { struct iattr attr; - attr.ia_valid = ATTR_MODE; + attr.ia_valid = ATTR_MODE | ATTR_CTIME; attr.ia_mode = mode; + attr.ia_ctime = CURRENT_TIME_SEC; rc = jffs2_do_setattr(inode, &attr); if (rc < 0) return rc; -- GitLab From 8ffb335e8d696affc04f963bf73ce2196f80edb9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Sun, 6 Jun 2010 15:34:40 -0700 Subject: [PATCH 715/842] ip6mr: fix a typo in ip6mr_for_each_table() Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv6/ip6mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 073071f2b75b..89c0b077c7aa 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -120,7 +120,7 @@ static void mroute_clean_tables(struct mr6_table *mrt); static void ipmr_expire_process(unsigned long arg); #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES -#define ip6mr_for_each_table(mrt, met) \ +#define ip6mr_for_each_table(mrt, net) \ list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list) static struct mr6_table *ip6mr_get_table(struct net *net, u32 id) -- GitLab From 024a07bacf8287a6ddfa83e9d5b951c5e8b4070e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> Date: Sun, 6 Jun 2010 15:38:47 -0700 Subject: [PATCH 716/842] r8169: fix random mdio_write failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some configurations need delay between the "write completed" indication and new write to work reliably. Realtek driver seems to use longer delay when polling the "write complete" bit, so it waits long enough between writes with high probability (but could probably break too). This patch adds a new udelay to make sure we wait unconditionally some time after the write complete indication. This caused a regression with XID 18000000 boards when the board specific phy configuration writing many mdio registers was added in commit 2e955856ff (r8169: phy init for the 8169scd). Some of the configration mdio writes would almost always fail, and depending on failure might leave the PHY in non-working state. Signed-off-by: Timo Teräs <timo.teras@iki.fi> Acked-off-by: Francois Romieu <romieu@fr.zoreil.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/r8169.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 217e709bda3e..03a8318d90a2 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -559,6 +559,11 @@ static void mdio_write(void __iomem *ioaddr, int reg_addr, int value) break; udelay(25); } + /* + * Some configurations require a small delay even after the write + * completed indication or the next write might fail. + */ + udelay(25); } static int mdio_read(void __iomem *ioaddr, int reg_addr) -- GitLab From 386f40c86d6c8d5b717ef20620af1a750d0dacb4 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Sun, 6 Jun 2010 20:44:04 -0700 Subject: [PATCH 717/842] Revert "tty: fix a little bug in scrup, vt.c" This reverts commit 962400e8fd29981a7b166e463dd143b6ac6a3e76, which was entirely bogus. The code used to multiply the character offset by "vc->vc_cols", and that's actually correct, because 'd' itself is an 'unsigned short'. So the pointer arithmetic already takes the size of a VGA character into account. Changing it to use vc_size_row (which is just "vc_cols" shifted up to take the size of the character into account) ends up multiplying with the VGA character size twice. This got reported as bugs for various other subsystems, because what it actually results in is writing the 16-bit vc_video_erase_char pattern (usually 0x0720: 0x07 is the default attribute, 0x20 is ASCII space) into some random other allocation. So Markus ended up reporting this as a ext4 bug, while to Torsten Kaiser it looked like a problem with KMS or libata. Jeff Chua saw it in different places. And finally - Justin Mattock had slab poisoning enabled, and saw it as a slab poison overwritten. And bisected and reverted this to verify the buggy commit. Reported-by: Markus Trippelsdorf <markus@trippelsdorf.de> Reported-by: Torsten Kaiser <just.for.lkml@googlemail.com> Reported-by: Jeff Chua <jeff.chua.linux@gmail.com> Reported-by: Justin P. Mattock <justinmattock@gmail.com> Reported-bisected-and-tested-by: Justin P. Mattock <justinmattock@gmail.com> Acked-by: Dave Airlie <airlied@redhat.com> Cc: Frank Pan <frankpzh@gmail.com> Cc: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/char/vt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1296c42ed5c6..7cdb6ee569cd 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -304,7 +304,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(d + (b - t - nr) * vc->vc_size_row, vc->vc_video_erase_char, + scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, vc->vc_size_row * nr); } -- GitLab From 9227a46bfbac0516fb7428715a095e1bc59b872a Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna <jussi.kivilinna@mbnet.fi> Date: Mon, 7 Jun 2010 00:56:27 -0700 Subject: [PATCH 718/842] asix: check packet size against mtu+ETH_HLEN instead of ETH_FRAME_LEN Driver checks received packet is too large in asix_rx_fixup() and fails if it is. Problem is that MTU might be set larger than 1500 and asix fails to work correctly with VLAN tagged packets. The check should be 'dev->net->mtu + ETH_HLEN' instead. Tested with AX88772. Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/usb/asix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 1f802e90474c..9516f382a6ba 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -344,7 +344,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 2; } - if (size > ETH_FRAME_LEN) { + if (size > dev->net->mtu + ETH_HLEN) { netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", size); return 0; -- GitLab From 3fd7fa4a89f0b85b9b33e922f15a2289c0fb8499 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov <dkirjanov@kernel.org> Date: Mon, 7 Jun 2010 01:13:57 -0700 Subject: [PATCH 719/842] 8139too: fix buffer overrun in rtl8139_init_board Fix rtl_chip_info buffer overrun when we can't identify the chip. (i = ARRAY_SIZE (rtl_chip_info) in this case) Signed-off-by: Denis Kirjanov <dkirjanov@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/8139too.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 4ba72933f0da..80cd074d3817 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -860,6 +860,7 @@ retry: } /* if unknown chip, assume array element #0, original RTL-8139 in this case */ + i = 0; dev_dbg(&pdev->dev, "unknown chip version, assuming RTL-8139\n"); dev_dbg(&pdev->dev, "TxConfig = 0x%lx\n", RTL_R32 (TxConfig)); tp->chipset = 0; -- GitLab From 238c1a78c957f3dc7cb848b161dcf4805793ed56 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov <dkirjanov@hera.kernel.org> Date: Tue, 1 Jun 2010 15:43:34 -0400 Subject: [PATCH 720/842] powerpc/oprofile: fix potential buffer overrun in op_model_cell.c Fix potential initial_lfsr buffer overrun. Writing past the end of the buffer could happen when index == ENTRIES Signed-off-by: Denis Kirjanov <dkirjanov@kernel.org> Cc: stable@kernel.org Signed-off-by: Robert Richter <robert.richter@amd.com> --- arch/powerpc/oprofile/op_model_cell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c index 2c9e52267292..7fd90d02d8c6 100644 --- a/arch/powerpc/oprofile/op_model_cell.c +++ b/arch/powerpc/oprofile/op_model_cell.c @@ -1077,7 +1077,7 @@ static int calculate_lfsr(int n) index = ENTRIES-1; /* make sure index is valid */ - if ((index > ENTRIES) || (index < 0)) + if ((index >= ENTRIES) || (index < 0)) index = ENTRIES-1; return initial_lfsr[index]; -- GitLab From 035320d54758e21227987e3aae0d46e7a04f4ddc Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Sun, 6 Jun 2010 23:48:40 +0000 Subject: [PATCH 721/842] ipmr: dont corrupt lists ipmr_rules_exit() and ip6mr_rules_exit() free a list of items, but forget to properly remove these items from list. List head is not changed and still points to freed memory. This can trigger a fault later when icmpv6_sk_exit() is called. Fix is to either reinit list, or use list_del() to properly remove items from list before freeing them. bugzilla report : https://bugzilla.kernel.org/show_bug.cgi?id=16120 Introduced by commit d1db275dd3f6e4 (ipv6: ip6mr: support multiple tables) and commit f0ad0860d01e (ipv4: ipmr: support multiple tables) Reported-by: Alex Zhavnerchik <alex.vizor@gmail.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> CC: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv4/ipmr.c | 4 +++- net/ipv6/ip6mr.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 856123fe32f9..757f25eb9b4b 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -267,8 +267,10 @@ static void __net_exit ipmr_rules_exit(struct net *net) { struct mr_table *mrt, *next; - list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) + list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) { + list_del(&mrt->list); kfree(mrt); + } fib_rules_unregister(net->ipv4.mr_rules_ops); } #else diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 89c0b077c7aa..66078dad7fe8 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -254,8 +254,10 @@ static void __net_exit ip6mr_rules_exit(struct net *net) { struct mr6_table *mrt, *next; - list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) + list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) { + list_del(&mrt->list); ip6mr_free_table(mrt); + } fib_rules_unregister(net->ipv6.mr6_rules_ops); } #else -- GitLab From cfca31ce789963c0dd6ca2e9cc13b90cc2802fbd Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Thu, 27 May 2010 14:32:24 +0200 Subject: [PATCH 722/842] [PATCH 2/11] drivers/watchdog: Eliminate a NULL pointer dereference At the point of the call to dev_err, wm8350 is NULL. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @r exists@ expression E,E1; identifier f; statement S1,S2,S3; @@ if ((E == NULL && ...) || ...) { ... when != if (...) S1 else S2 when != E = E1 * E->f ... when any return ...; } else S3 // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be> --- drivers/watchdog/wm8350_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/wm8350_wdt.c b/drivers/watchdog/wm8350_wdt.c index 89dd7b035295..b68d928c8f90 100644 --- a/drivers/watchdog/wm8350_wdt.c +++ b/drivers/watchdog/wm8350_wdt.c @@ -284,7 +284,7 @@ static int __devinit wm8350_wdt_probe(struct platform_device *pdev) struct wm8350 *wm8350 = platform_get_drvdata(pdev); if (!wm8350) { - dev_err(wm8350->dev, "No driver data supplied\n"); + pr_err("No driver data supplied\n"); return -ENODEV; } -- GitLab From 02caa56e4b789b80ae7e0f0f0789f94b44ad32ef Mon Sep 17 00:00:00 2001 From: Dominik Brodowski <linux@dominikbrodowski.net> Date: Fri, 21 May 2010 15:16:53 +0200 Subject: [PATCH 723/842] pcmcia: only keep saved I365_CSCINT flag if there is no PCI irq Keeping the saved I365_CSCINT flag around breaks PCMCIA on some system, and is only needed on a few systems to get PCMCIA to work. This patch allows PCMCIA to work on both types, and it fixes https://bugzilla.kernel.org/show_bug.cgi?id=16015 Reported-by: Justin P. Mattock <justinmattock@gmail.com> CC: <stable@kernel.org> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> --- drivers/pcmcia/yenta_socket.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 424e576f3acb..6bf8b2c06c7d 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -975,7 +975,7 @@ static irqreturn_t yenta_probe_handler(int irq, void *dev_id) /* probes the PCI interrupt, use only on override functions */ static int yenta_probe_cb_irq(struct yenta_socket *socket) { - u8 reg; + u8 reg = 0; if (!socket->cb_irq) return -1; @@ -989,7 +989,8 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket) } /* generate interrupt, wait */ - reg = exca_readb(socket, I365_CSCINT); + if (!socket->dev->irq) + reg = exca_readb(socket, I365_CSCINT); exca_writeb(socket, I365_CSCINT, reg | I365_CSC_STSCHG); cb_writel(socket, CB_SOCKET_EVENT, -1); cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK); -- GitLab From 4f2d364b315191bf9f8659f7d221acdf5506a989 Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" <justinmattock@gmail.com> Date: Thu, 20 May 2010 13:40:02 -0700 Subject: [PATCH 724/842] pcmcia: yenta_socket.c Remove extra #ifdef CONFIG_YENTA_TI Seems pointless to have two #ifdef's with the same CONFIG_YENTA_TI. Remove the extra one and move CARDBUS_TYPE_ENE with the others. [linux@dominikbrodowski.net: spelling & whitespace fixes] Signed-off-by: Justin P. Mattock <justinmattock@gmail.com> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> --- drivers/pcmcia/yenta_socket.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 6bf8b2c06c7d..f1d41374eea7 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -880,6 +880,12 @@ static struct cardbus_type cardbus_type[] = { .restore_state = ti_restore_state, .sock_init = ti_init, }, + [CARDBUS_TYPE_ENE] = { + .override = ene_override, + .save_state = ti_save_state, + .restore_state = ti_restore_state, + .sock_init = ti_init, + }, #endif #ifdef CONFIG_YENTA_RICOH [CARDBUS_TYPE_RICOH] = { @@ -902,14 +908,6 @@ static struct cardbus_type cardbus_type[] = { .restore_state = o2micro_restore_state, }, #endif -#ifdef CONFIG_YENTA_TI - [CARDBUS_TYPE_ENE] = { - .override = ene_override, - .save_state = ti_save_state, - .restore_state = ti_restore_state, - .sock_init = ti_init, - }, -#endif }; -- GitLab From 287b87a350de4e344d60697a1f16abe2a6cd350a Mon Sep 17 00:00:00 2001 From: Dominik Brodowski <linux@dominikbrodowski.net> Date: Mon, 7 Jun 2010 18:26:51 +0200 Subject: [PATCH 725/842] pcmcia: dev_node removal bugfix Patch c7c2fa07 removed one line too much from smc91c92_cs.c. Reported-by: Komuro <komurojun-mbn@nifty.com> CC: netdev@vger.kernel.org CC: linux-wireless@vger.kernel.org Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> --- drivers/net/pcmcia/smc91c92_cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 7b6fe89f9db0..64e6a84bbbbe 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -322,6 +322,7 @@ static int smc91c92_probe(struct pcmcia_device *link) return -ENOMEM; smc = netdev_priv(dev); smc->p_dev = link; + link->priv = dev; spin_lock_init(&smc->lock); link->io.NumPorts1 = 16; -- GitLab From b83156b52dd77979cc93bafc2283929532f6f7d0 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski <linux@dominikbrodowski.net> Date: Mon, 7 Jun 2010 18:31:17 +0200 Subject: [PATCH 726/842] pcmcia: avoid validate_cis failure on CIS override Commit a8408c17 introduced a new check to pccard_validate_cis(), which avoids any "late" calls to this function. This broke the insertion of cards which require a CIS override which changes the number of card functions. Fix this by asserting that this is _not_ a late call, but a proper call early during the card insertion process. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=16138 Reported-by: Mikulas Patocka <mpatocka@redhat.com> CC: <stable@kernel.org> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> --- drivers/pcmcia/ds.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 7ef7adee5e4f..9fc339845538 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -671,6 +671,7 @@ static void pcmcia_requery(struct pcmcia_socket *s) if (old_funcs != new_funcs) { /* we need to re-start */ pcmcia_card_remove(s, NULL); + s->functions = 0; pcmcia_card_add(s); } } -- GitLab From aa679c36756003f1fabdb9fc6f00eb159559f7c3 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas <notasas@gmail.com> Date: Sat, 5 Jun 2010 02:25:47 +0300 Subject: [PATCH 727/842] wl1251: fix a memory leak in probe wl1251_sdio_probe() error path is missing wl1251_free_hw, add it. Signed-off-by: Grazvydas Ignotas <notasas@gmail.com> Acked-by: Kalle Valo <kvalo@adurom.com> Cc: stable@kernel.org Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/wl12xx/wl1251_sdio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c index d234285c2c81..c561332e7009 100644 --- a/drivers/net/wireless/wl12xx/wl1251_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c @@ -259,6 +259,7 @@ disable: sdio_disable_func(func); release: sdio_release_host(func); + wl1251_free_hw(wl); return ret; } -- GitLab From 0f666a08901f8b01f294ca0ad751019375240ae3 Mon Sep 17 00:00:00 2001 From: Jason Dravet <dravet@hotmail.com> Date: Sat, 5 Jun 2010 15:08:29 -0500 Subject: [PATCH 728/842] p54usb: Add device ID for Dell WLA3310 USB Add Dell WLA3310 USB wireless card, which has a Z-Com XG-705A chipset, to the USB Ids in p54usb. Signed-off-by: Jason Dravet <dravet@hotmail.com> Tested-by: Richard Gregory Tillmore <rtillmore@gmail.com> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Acked-by: Christian Lamparter <chunkeey@googlemail.com> Cc: <stable@kernel.org> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/p54/p54usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index d5b197b4d5bb..73073259f508 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -80,6 +80,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ + {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */ {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */ {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */ {} -- GitLab From 436c109adb54433fff689abd71c23a6505e46bb0 Mon Sep 17 00:00:00 2001 From: Bruno Randolf <br1@einfach.org> Date: Mon, 7 Jun 2010 13:11:19 +0900 Subject: [PATCH 729/842] ath5k: fix NULL pointer in antenna configuration If the channel is not set yet and we configure the antennas just store the setting. It will be activated during the next reset, when the channel is set. Signed-off-by: Bruno Randolf <br1@einfach.org> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/ath/ath5k/phy.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 1b81c4778800..492cbb15720d 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1814,6 +1814,13 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) u8 def_ant, tx_ant, ee_mode; u32 sta_id1 = 0; + /* if channel is not initialized yet we can't set the antennas + * so just store the mode. it will be set on the next reset */ + if (channel == NULL) { + ah->ah_ant_mode = ant_mode; + return; + } + def_ant = ah->ah_def_ant; ATH5K_TRACE(ah->ah_sc); -- GitLab From e500ae5b535a5209fd397fcc542e3b3290fc2fc5 Mon Sep 17 00:00:00 2001 From: Zhu Yi <yi.zhu@intel.com> Date: Mon, 7 Jun 2010 14:15:43 +0800 Subject: [PATCH 730/842] wireless: remove my name from the maintainer list Remove my name from the MAINTAINERS file. Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- MAINTAINERS | 4 ---- 1 file changed, 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 8d51903a6627..83be538d26c4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2966,7 +2966,6 @@ F: drivers/net/ixgb/ F: drivers/net/ixgbe/ INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT -M: Zhu Yi <yi.zhu@intel.com> M: Reinette Chatre <reinette.chatre@intel.com> M: Intel Linux Wireless <ilw@linux.intel.com> L: linux-wireless@vger.kernel.org @@ -2976,7 +2975,6 @@ F: Documentation/networking/README.ipw2100 F: drivers/net/wireless/ipw2x00/ipw2100.* INTEL PRO/WIRELESS 2915ABG NETWORK CONNECTION SUPPORT -M: Zhu Yi <yi.zhu@intel.com> M: Reinette Chatre <reinette.chatre@intel.com> M: Intel Linux Wireless <ilw@linux.intel.com> L: linux-wireless@vger.kernel.org @@ -3007,7 +3005,6 @@ F: drivers/net/wimax/i2400m/ F: include/linux/wimax/i2400m.h INTEL WIRELESS WIFI LINK (iwlwifi) -M: Zhu Yi <yi.zhu@intel.com> M: Reinette Chatre <reinette.chatre@intel.com> M: Wey-Yi Guy <wey-yi.w.guy@intel.com> M: Intel Linux Wireless <ilw@linux.intel.com> @@ -3019,7 +3016,6 @@ F: drivers/net/wireless/iwlwifi/ INTEL WIRELESS MULTICOMM 3200 WIFI (iwmc3200wifi) M: Samuel Ortiz <samuel.ortiz@intel.com> -M: Zhu Yi <yi.zhu@intel.com> M: Intel Linux Wireless <ilw@linux.intel.com> L: linux-wireless@vger.kernel.org S: Supported -- GitLab From 35dd0509b21e4b5bab36b9eb80c8dab0322f5007 Mon Sep 17 00:00:00 2001 From: Holger Schurig <holgerschurig@gmail.com> Date: Mon, 7 Jun 2010 16:33:49 +0200 Subject: [PATCH 731/842] mac80211: fix function pointer check This makes "iw wlan0 dump survey" work again with mac80211-based drivers that support it, e.g. ath5k. Signed-off-by: Holger Schurig <holgerschurig@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- net/mac80211/driver-ops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4f2271316650..9c1da0809160 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -349,7 +349,7 @@ static inline int drv_get_survey(struct ieee80211_local *local, int idx, struct survey_info *survey) { int ret = -EOPNOTSUPP; - if (local->ops->conf_tx) + if (local->ops->get_survey) ret = local->ops->get_survey(&local->hw, idx, survey); /* trace_drv_get_survey(local, idx, survey, ret); */ return ret; -- GitLab From b475a3b83a7709e16a734ef2b8ead4d50f885427 Mon Sep 17 00:00:00 2001 From: Tejun Heo <tj@kernel.org> Date: Thu, 3 Jun 2010 11:35:03 +0200 Subject: [PATCH 732/842] sata_via: explain the magic fix Add Joseph Chan's explanation of the problem and workaround to the VT6421 magic fix. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Joseph Chan <JosephChan@via.com.tw> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/sata_via.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 0ecd0f6aa2c0..4730c42a5ee5 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -578,10 +578,24 @@ static void svia_configure(struct pci_dev *pdev) /* * vt6421 has problems talking to some drives. The following - * is the magic fix from Joseph Chan <JosephChan@via.com.tw>. - * Please add proper documentation if possible. + * is the fix from Joseph Chan <JosephChan@via.com.tw>. + * + * When host issues HOLD, device may send up to 20DW of data + * before acknowledging it with HOLDA and the host should be + * able to buffer them in FIFO. Unfortunately, some WD drives + * send upto 40DW before acknowledging HOLD and, in the + * default configuration, this ends up overflowing vt6421's + * FIFO, making the controller abort the transaction with + * R_ERR. + * + * Rx52[2] is the internal 128DW FIFO Flow control watermark + * adjusting mechanism enable bit and the default value 0 + * means host will issue HOLD to device when the left FIFO + * size goes below 32DW. Setting it to 1 makes the watermark + * 64DW. * * https://bugzilla.kernel.org/show_bug.cgi?id=15173 + * http://article.gmane.org/gmane.linux.ide/46352 */ if (pdev->device == 0x3249) { pci_read_config_byte(pdev, 0x52, &tmp8); -- GitLab From 4daedcfe8c6851aa01cc1997220f2577f4039c13 Mon Sep 17 00:00:00 2001 From: Tejun Heo <tj@kernel.org> Date: Thu, 3 Jun 2010 11:57:04 +0200 Subject: [PATCH 733/842] ahci: add pci quirk for JMB362 JMB362 is a new variant of jmicron controller which is similar to JMB360 but has two SATA ports instead of one. As there is no PATA port, single function AHCI mode can be used as in JMB360. Add pci quirk for JMB362. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Aries Lee <arieslee@jmicron.com> Cc: stable@kernel.org Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/pci/quirks.c | 5 ++++- include/linux/pci_ids.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b7512cf08c58..477345d41641 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1457,7 +1457,8 @@ static void quirk_jmicron_ata(struct pci_dev *pdev) conf5 &= ~(1 << 24); /* Clear bit 24 */ switch (pdev->device) { - case PCI_DEVICE_ID_JMICRON_JMB360: + case PCI_DEVICE_ID_JMICRON_JMB360: /* SATA single port */ + case PCI_DEVICE_ID_JMICRON_JMB362: /* SATA dual ports */ /* The controller should be in single function ahci mode */ conf1 |= 0x0002A100; /* Set 8, 13, 15, 17 */ break; @@ -1493,12 +1494,14 @@ static void quirk_jmicron_ata(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB362, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB362, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f149dd10908b..4eb467910a45 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2321,6 +2321,7 @@ #define PCI_VENDOR_ID_JMICRON 0x197B #define PCI_DEVICE_ID_JMICRON_JMB360 0x2360 #define PCI_DEVICE_ID_JMICRON_JMB361 0x2361 +#define PCI_DEVICE_ID_JMICRON_JMB362 0x2362 #define PCI_DEVICE_ID_JMICRON_JMB363 0x2363 #define PCI_DEVICE_ID_JMICRON_JMB365 0x2365 #define PCI_DEVICE_ID_JMICRON_JMB366 0x2366 -- GitLab From 7a4f876b876afb13856a79a0402f71b9dfbe86a8 Mon Sep 17 00:00:00 2001 From: Colin Tuckley <colin.tuckley@arm.com> Date: Fri, 4 Jun 2010 16:19:51 +0200 Subject: [PATCH 734/842] sata_sil24: fix kernel panic on ARM caused by unaligned access in sata_sil24 The sata_sil24 driver has six 16-bit registers that are initialised with 32-bit writes. This cause a kernel panic on ARM due to the unaligned accesses which result. This patch changes the accesses to the correct 16-bit ones. Signed-off-by: Colin Tuckley <colin.tuckley@arm.com> Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/sata_sil24.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index e9250514734b..70b58fe9e5b1 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -539,12 +539,12 @@ static void sil24_config_port(struct ata_port *ap) writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); /* zero error counters. */ - writel(0x8000, port + PORT_DECODE_ERR_THRESH); - writel(0x8000, port + PORT_CRC_ERR_THRESH); - writel(0x8000, port + PORT_HSHK_ERR_THRESH); - writel(0x0000, port + PORT_DECODE_ERR_CNT); - writel(0x0000, port + PORT_CRC_ERR_CNT); - writel(0x0000, port + PORT_HSHK_ERR_CNT); + writew(0x8000, port + PORT_DECODE_ERR_THRESH); + writew(0x8000, port + PORT_CRC_ERR_THRESH); + writew(0x8000, port + PORT_HSHK_ERR_THRESH); + writew(0x0000, port + PORT_DECODE_ERR_CNT); + writew(0x0000, port + PORT_CRC_ERR_CNT); + writew(0x0000, port + PORT_HSHK_ERR_CNT); /* always use 64bit activation */ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); -- GitLab From 0ee719527229fa86ace8e3abccae3c2a8bbfd6db Mon Sep 17 00:00:00 2001 From: Tejun Heo <tj@kernel.org> Date: Mon, 7 Jun 2010 15:15:08 +0200 Subject: [PATCH 735/842] ahci: redo stopping DMA engines on empty ports Commit 96d60303fd (ahci: Turn off DMA engines when there's no device) implemented stopping DMA engines on empty ports but it used single sampling of status registers to determine device presence which led to disabling of DMA engines on occupied ports. Do it after all EH actions are complete using device presence state determined by EH. This avoids spurious disabling of DMA engines and simplifies the code. Signed-off-by: Tejun Heo <tj@kernel.org> Tested-by: Marc Dionne <marc.c.dionne@gmail.com> Cc: Matthew Garrett <mjg@redhat.com> Cc: Robert Hancock <hancockrwd@gmail.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/libahci.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 1984a6e89e84..261f86d102e8 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -541,29 +541,11 @@ static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) return -EINVAL; } -static int ahci_is_device_present(void __iomem *port_mmio) -{ - u8 status = readl(port_mmio + PORT_TFDATA) & 0xff; - - /* Make sure PxTFD.STS.BSY and PxTFD.STS.DRQ are 0 */ - if (status & (ATA_BUSY | ATA_DRQ)) - return 0; - - /* Make sure PxSSTS.DET is 3h */ - status = readl(port_mmio + PORT_SCR_STAT) & 0xf; - if (status != 3) - return 0; - return 1; -} - void ahci_start_engine(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; - if (!ahci_is_device_present(port_mmio)) - return; - /* start DMA */ tmp = readl(port_mmio + PORT_CMD); tmp |= PORT_CMD_START; @@ -1892,6 +1874,9 @@ static void ahci_error_handler(struct ata_port *ap) } sata_pmp_error_handler(ap); + + if (!ata_dev_enabled(ap->link.device)) + ahci_stop_engine(ap); } static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) -- GitLab From 85a0e7539781dad4bfcffd98e72fa9f130f4e40d Mon Sep 17 00:00:00 2001 From: Ondrej Zary <linux@rainbow-software.org> Date: Tue, 8 Jun 2010 00:32:49 +0200 Subject: [PATCH 736/842] PM / x86: Save/restore MISC_ENABLE register Save/restore MISC_ENABLE register on suspend/resume. This fixes OOPS (invalid opcode) on resume from STR on Asus P4P800-VM, which wakes up with MWAIT disabled. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=15385 Signed-off-by: Ondrej Zary <linux@rainbow-software.org> Tested-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: H. Peter Anvin <hpa@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> --- arch/x86/include/asm/suspend_32.h | 2 ++ arch/x86/include/asm/suspend_64.h | 2 ++ arch/x86/power/cpu.c | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/arch/x86/include/asm/suspend_32.h b/arch/x86/include/asm/suspend_32.h index 48dcfa62ea07..fd921c3a6841 100644 --- a/arch/x86/include/asm/suspend_32.h +++ b/arch/x86/include/asm/suspend_32.h @@ -15,6 +15,8 @@ static inline int arch_prepare_suspend(void) { return 0; } struct saved_context { u16 es, fs, gs, ss; unsigned long cr0, cr2, cr3, cr4; + u64 misc_enable; + bool misc_enable_saved; struct desc_ptr gdt; struct desc_ptr idt; u16 ldt; diff --git a/arch/x86/include/asm/suspend_64.h b/arch/x86/include/asm/suspend_64.h index 06284f42b759..8d942afae681 100644 --- a/arch/x86/include/asm/suspend_64.h +++ b/arch/x86/include/asm/suspend_64.h @@ -27,6 +27,8 @@ struct saved_context { u16 ds, es, fs, gs, ss; unsigned long gs_base, gs_kernel_base, fs_base; unsigned long cr0, cr2, cr3, cr4, cr8; + u64 misc_enable; + bool misc_enable_saved; unsigned long efer; u16 gdt_pad; u16 gdt_limit; diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index 0a979f3e5b8a..1290ba54b350 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c @@ -105,6 +105,8 @@ static void __save_processor_state(struct saved_context *ctxt) ctxt->cr4 = read_cr4(); ctxt->cr8 = read_cr8(); #endif + ctxt->misc_enable_saved = !rdmsrl_safe(MSR_IA32_MISC_ENABLE, + &ctxt->misc_enable); } /* Needed by apm.c */ @@ -152,6 +154,8 @@ static void fix_processor_context(void) */ static void __restore_processor_state(struct saved_context *ctxt) { + if (ctxt->misc_enable_saved) + wrmsrl(MSR_IA32_MISC_ENABLE, ctxt->misc_enable); /* * control registers */ -- GitLab From 6d7b7d578f2c182f77ab6dd1c375f848f38ea1a6 Mon Sep 17 00:00:00 2001 From: Daniel Walker <dwalker@codeaurora.org> Date: Thu, 20 May 2010 15:39:33 -0700 Subject: [PATCH 737/842] msm: dma: add completion.h header At some point this was exposed (not sure how), linux-2.6/arch/arm/mach-msm/dma.c:92: error: field 'complete' has incomplete type linux-2.6/arch/arm/mach-msm/dma.c: In function 'dmov_exec_cmdptr_complete_func': linux-2.6/arch/arm/mach-msm/dma.c:108: error: implicit declaration of function 'complete' linux-2.6/arch/arm/mach-msm/dma.c: In function 'msm_dmov_exec_cmd': linux-2.6/arch/arm/mach-msm/dma.c:120: error: implicit declaration of function 'init_completion' linux-2.6/arch/arm/mach-msm/dma.c:123: error: implicit declaration of function 'wait_for_completion' and the fix is just to add the header. Signed-off-by: Daniel Walker <dwalker@codeaurora.org> --- arch/arm/mach-msm/dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index d029d1f5f9e2..02cae5e2951c 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -17,6 +17,7 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/interrupt.h> +#include <linux/completion.h> #include <mach/dma.h> #define MSM_DMOV_CHANNEL_COUNT 16 -- GitLab From a3524f1b27671eda909cde37da9caff41133b272 Mon Sep 17 00:00:00 2001 From: Dave Airlie <airlied@redhat.com> Date: Sun, 6 Jun 2010 18:59:41 +1000 Subject: [PATCH 738/842] drm/i915: fix oops on single crtc devices. (regression fix since fbdev/kms rework). My fb rework didn't remember about the 84/65s. Reported-by: Ondrej Zary <linux@rainbow-software.org> Tested-by: Ondrej Zary <linux@rainbow-software.org> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 9 ++++----- drivers/gpu/drm/i915/intel_fb.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9ed8ecd95801..276583159847 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -278,6 +278,7 @@ typedef struct drm_i915_private { struct mem_block *agp_heap; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; + int num_pipe; /* For hangcheck timer */ #define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 04e1bb499ff8..2861da3aaf7e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5470,7 +5470,6 @@ static void intel_init_display(struct drm_device *dev) void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int num_pipe; int i; drm_mode_config_init(dev); @@ -5500,13 +5499,13 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); if (IS_MOBILE(dev) || IS_I9XX(dev)) - num_pipe = 2; + dev_priv->num_pipe = 2; else - num_pipe = 1; + dev_priv->num_pipe = 1; DRM_DEBUG_KMS("%d display pipe%s available.\n", - num_pipe, num_pipe > 1 ? "s" : ""); + dev_priv->num_pipe, dev_priv->num_pipe > 1 ? "s" : ""); - for (i = 0; i < num_pipe; i++) { + for (i = 0; i < dev_priv->num_pipe; i++) { intel_crtc_init(dev, i); } diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index f8c76e64bb77..dfbb0c6e1f51 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -253,7 +253,7 @@ int intel_fbdev_init(struct drm_device *dev) dev_priv->fbdev = ifbdev; ifbdev->helper.funcs = &intel_fb_helper_funcs; - drm_fb_helper_init(dev, &ifbdev->helper, 2, + drm_fb_helper_init(dev, &ifbdev->helper, dev_priv->num_pipe, INTELFB_CONN_LIMIT); drm_fb_helper_single_add_all_connectors(&ifbdev->helper); -- GitLab From 5a79395b2791cc70442ab8434aed1b5206683e7c Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sun, 6 Jun 2010 10:50:03 +0100 Subject: [PATCH 739/842] drm: Propagate error from drm_fb_helper_init(). The previous commit fixes the problem, these commits make sure we actually fail properly if it happens again. I've squashed the commits from Chris since they are all fixing one issue. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/i915/i915_dma.c | 19 ++++++++++++++----- drivers/gpu/drm/i915/intel_fb.c | 10 ++++++++-- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 8 +++++++- drivers/gpu/drm/radeon/radeon_fb.c | 12 +++++++++--- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index b2ebf02e4f8a..59a2bf8592ec 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1402,19 +1402,19 @@ static int i915_load_modeset_init(struct drm_device *dev, /* if we have > 1 VGA cards, then disable the radeon VGA resources */ ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode); if (ret) - goto destroy_ringbuffer; + goto cleanup_ringbuffer; ret = vga_switcheroo_register_client(dev->pdev, i915_switcheroo_set_state, i915_switcheroo_can_switch); if (ret) - goto destroy_ringbuffer; + goto cleanup_vga_client; intel_modeset_init(dev); ret = drm_irq_install(dev); if (ret) - goto destroy_ringbuffer; + goto cleanup_vga_switcheroo; /* Always safe in the mode setting case. */ /* FIXME: do pre/post-mode set stuff in core KMS code */ @@ -1426,11 +1426,20 @@ static int i915_load_modeset_init(struct drm_device *dev, I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); - intel_fbdev_init(dev); + ret = intel_fbdev_init(dev); + if (ret) + goto cleanup_irq; + drm_kms_helper_poll_init(dev); return 0; -destroy_ringbuffer: +cleanup_irq: + drm_irq_uninstall(dev); +cleanup_vga_switcheroo: + vga_switcheroo_unregister_client(dev->pdev); +cleanup_vga_client: + vga_client_register(dev->pdev, NULL, NULL, NULL); +cleanup_ringbuffer: mutex_lock(&dev->struct_mutex); i915_gem_cleanup_ringbuffer(dev); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index dfbb0c6e1f51..c3c505244e07 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -245,6 +245,7 @@ int intel_fbdev_init(struct drm_device *dev) { struct intel_fbdev *ifbdev; drm_i915_private_t *dev_priv = dev->dev_private; + int ret; ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); if (!ifbdev) @@ -253,8 +254,13 @@ int intel_fbdev_init(struct drm_device *dev) dev_priv->fbdev = ifbdev; ifbdev->helper.funcs = &intel_fb_helper_funcs; - drm_fb_helper_init(dev, &ifbdev->helper, dev_priv->num_pipe, - INTELFB_CONN_LIMIT); + ret = drm_fb_helper_init(dev, &ifbdev->helper, + dev_priv->num_pipe, + INTELFB_CONN_LIMIT); + if (ret) { + kfree(ifbdev); + return ret; + } drm_fb_helper_single_add_all_connectors(&ifbdev->helper); drm_fb_helper_initial_config(&ifbdev->helper, 32); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index fd4a2df715e9..c9a4a0d2a115 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -377,6 +377,7 @@ int nouveau_fbcon_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fbdev *nfbdev; + int ret; nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL); if (!nfbdev) @@ -386,7 +387,12 @@ int nouveau_fbcon_init(struct drm_device *dev) dev_priv->nfbdev = nfbdev; nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; - drm_fb_helper_init(dev, &nfbdev->helper, 2, 4); + ret = drm_fb_helper_init(dev, &nfbdev->helper, 2, 4); + if (ret) { + kfree(nfbdev); + return ret; + } + drm_fb_helper_single_add_all_connectors(&nfbdev->helper); drm_fb_helper_initial_config(&nfbdev->helper, 32); return 0; diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index e192acfbf0cd..dc1634bb0c11 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -363,6 +363,7 @@ int radeon_fbdev_init(struct radeon_device *rdev) { struct radeon_fbdev *rfbdev; int bpp_sel = 32; + int ret; /* select 8 bpp console on RN50 or 16MB cards */ if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) @@ -376,9 +377,14 @@ int radeon_fbdev_init(struct radeon_device *rdev) rdev->mode_info.rfbdev = rfbdev; rfbdev->helper.funcs = &radeon_fb_helper_funcs; - drm_fb_helper_init(rdev->ddev, &rfbdev->helper, - rdev->num_crtc, - RADEONFB_CONN_LIMIT); + ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper, + rdev->num_crtc, + RADEONFB_CONN_LIMIT); + if (ret) { + kfree(rfbdev); + return ret; + } + drm_fb_helper_single_add_all_connectors(&rfbdev->helper); drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); return 0; -- GitLab From 9bad145ee2ef43ac36d397190a7d8b1a7306d3fb Mon Sep 17 00:00:00 2001 From: Dave Airlie <airlied@redhat.com> Date: Mon, 7 Jun 2010 12:00:57 +1000 Subject: [PATCH 740/842] drm/radeon: fix PM on non-vram cards. PM attemps to unmap objects that aren't actually mapped into userspace ever, so just don't bother unmapping them at this point, since all you are doing is nothing. We should be making sure all access to these objects are locked in kernel space instead. In theory the VRAM gart table is already done, and both the shaders and stolen vga memory blocks are never accessed at runtime. fixes: https://bugzilla.kernel.org/show_bug.cgi?id=16127 Reported-by: Jure Repnic <jlp.bugs@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_pm.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 02281269a881..6f80625179a6 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -127,15 +127,6 @@ static void radeon_unmap_vram_bos(struct radeon_device *rdev) if (bo->tbo.mem.mem_type == TTM_PL_VRAM) ttm_bo_unmap_virtual(&bo->tbo); } - - if (rdev->gart.table.vram.robj) - ttm_bo_unmap_virtual(&rdev->gart.table.vram.robj->tbo); - - if (rdev->stollen_vga_memory) - ttm_bo_unmap_virtual(&rdev->stollen_vga_memory->tbo); - - if (rdev->r600_blit.shader_obj) - ttm_bo_unmap_virtual(&rdev->r600_blit.shader_obj->tbo); } static void radeon_sync_with_vblank(struct radeon_device *rdev) -- GitLab From fc2362afd5ab9456caab4de317da796cc88944fe Mon Sep 17 00:00:00 2001 From: Dave Airlie <airlied@redhat.com> Date: Mon, 7 Jun 2010 12:14:54 +1000 Subject: [PATCH 741/842] drm/fb: use printk to print out the switching to text mode error. using DRM_ERROR, results in people blaming the drm code for the oops, and not looking at the oops. (sadly yes I've gotten reports). Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/drm_fb_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index b3779d243aef..08c4c926e65f 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -264,7 +264,7 @@ bool drm_fb_helper_force_kernel_mode(void) int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed, void *panic_str) { - DRM_ERROR("panic occurred, switching back to text console\n"); + printk(KERN_ERR "panic occurred, switching back to text console\n"); return drm_fb_helper_force_kernel_mode(); return 0; } -- GitLab From e902a358c753b93245083201c02312a580cf13d4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Fri, 4 Jun 2010 12:23:21 +0200 Subject: [PATCH 742/842] drm/drm_crtc: return -EFAULT on copy_to_user errors copy_from_user() returns the number of bytes left to be copied but we want to return a negative error code here. This is in the ioctl handler so the error code get returned to userspace. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/drm_crtc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 994d23beeb1d..57cea01c4ffb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1840,8 +1840,10 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, ret = copy_from_user(clips, clips_ptr, num_clips * sizeof(*clips)); - if (ret) + if (ret) { + ret = -EFAULT; goto out_err2; + } } if (fb->funcs->dirty) { -- GitLab From 9b8eb4d14767209c83087063352cd04266ecdfd1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Fri, 4 Jun 2010 12:24:13 +0200 Subject: [PATCH 743/842] drm/vmwgfx: return -EFAULT for copy_to_user errors copy_to/from_user() returns the number of bytes remaining to be copied but we want to return a negative error code here. This gets returned to userspace. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index bdd67cf83315..8e396850513c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -644,6 +644,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ret = copy_from_user(cmd, user_cmd, arg->command_size); if (unlikely(ret != 0)) { + ret = -EFAULT; DRM_ERROR("Failed copying commands.\n"); goto out_commit; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index f8fbbc67a406..8612378b131e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -597,8 +597,10 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, ret = copy_from_user(srf->sizes, user_sizes, srf->num_sizes * sizeof(*srf->sizes)); - if (unlikely(ret != 0)) + if (unlikely(ret != 0)) { + ret = -EFAULT; goto out_err1; + } if (srf->scanout && srf->num_sizes == 1 && @@ -697,9 +699,11 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, if (user_sizes) ret = copy_to_user(user_sizes, srf->sizes, srf->num_sizes * sizeof(*srf->sizes)); - if (unlikely(ret != 0)) + if (unlikely(ret != 0)) { DRM_ERROR("copy_to_user failed %p %u\n", user_sizes, srf->num_sizes); + ret = -EFAULT; + } out_bad_resource: out_no_reference: ttm_base_object_unref(&base); -- GitLab From 148a03bc0b0e3ef153d0cade7bc88e9b14edfb7a Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Thu, 3 Jun 2010 19:00:03 -0400 Subject: [PATCH 744/842] drm/radeon/kms/evergreen: set accel_enabled This is needed to enable accel in the ddx. However, due to a bug in older versions of the ddx, it relies on accel being disabled in order to load properly on evergreen chips. To maintain compatility, we add a new get accel param and call that from the ddx. The old one always returns false for evergreen cards. [this fixes a regression with older userspaces on newer kernels]. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/evergreen.c | 2 +- drivers/gpu/drm/radeon/radeon_drv.c | 3 ++- drivers/gpu/drm/radeon/radeon_kms.c | 9 ++++++++- include/drm/radeon_drm.h | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 0440c0939bdd..49c94aef0dda 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2153,7 +2153,7 @@ int evergreen_init(struct radeon_device *rdev) if (r) return r; - rdev->accel_working = false; + rdev->accel_working = true; r = evergreen_startup(rdev); if (r) { dev_err(rdev->dev, "disabling GPU acceleration\n"); diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 902d1731a652..e166fe4d7c30 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -45,9 +45,10 @@ * - 2.2.0 - add r6xx/r7xx const buffer support * - 2.3.0 - add MSPOS + 3D texture + r500 VAP regs * - 2.4.0 - add crtc id query + * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 4 +#define KMS_DRIVER_MINOR 5 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 04068352ccd2..6a70c0dc7f92 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -118,7 +118,11 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) value = rdev->num_z_pipes; break; case RADEON_INFO_ACCEL_WORKING: - value = rdev->accel_working; + /* xf86-video-ati 6.13.0 relies on this being false for evergreen */ + if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK)) + value = false; + else + value = rdev->accel_working; break; case RADEON_INFO_CRTC_FROM_ID: for (i = 0, found = 0; i < rdev->num_crtc; i++) { @@ -134,6 +138,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return -EINVAL; } break; + case RADEON_INFO_ACCEL_WORKING2: + value = rdev->accel_working; + break; default: DRM_DEBUG("Invalid request %d\n", info->request); return -EINVAL; diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h index 3ff9fc071dfe..5347063e9d5a 100644 --- a/include/drm/radeon_drm.h +++ b/include/drm/radeon_drm.h @@ -903,6 +903,7 @@ struct drm_radeon_cs { #define RADEON_INFO_NUM_Z_PIPES 0x02 #define RADEON_INFO_ACCEL_WORKING 0x03 #define RADEON_INFO_CRTC_FROM_ID 0x04 +#define RADEON_INFO_ACCEL_WORKING2 0x05 struct drm_radeon_info { uint32_t request; -- GitLab From 8de016e2bd8ebce9b3728462085bef51179841a6 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Thu, 3 Jun 2010 21:28:23 -0400 Subject: [PATCH 745/842] drm/radeon/kms/combios: fix typo in voltage fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed by Rafał Miłecki. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_combios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 102c744eaf5a..f6f907e7217a 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2455,7 +2455,7 @@ default_mode: rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0]; if ((state_index > 0) && - (rdev->pm.power_state[0].clock_info[0].voltage.type = VOLTAGE_GPIO)) + (rdev->pm.power_state[0].clock_info[0].voltage.type == VOLTAGE_GPIO)) rdev->pm.power_state[state_index].clock_info[0].voltage = rdev->pm.power_state[0].clock_info[0].voltage; else -- GitLab From f8ed8b4c5d30b5214f185997131b06e35f6f7113 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Mon, 7 Jun 2010 17:49:51 -0400 Subject: [PATCH 746/842] drm/radeon/kms/pm: Misc fixes - don't rest the power state in pm_init() We already boot up to the default power state. Note this patch relies on: drm/radeon/kms/pm: patch default power state with default clocks/voltages on r6xx+ To make sure the default power state matches the boot up state. - In the pm resume path asic init will have set the power state back to the default so reset the tracking state values. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_pm.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 6f80625179a6..62e7f967c6c4 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -368,15 +368,18 @@ void radeon_pm_suspend(struct radeon_device *rdev) { mutex_lock(&rdev->pm.mutex); cancel_delayed_work(&rdev->pm.dynpm_idle_work); - rdev->pm.current_power_state_index = -1; - rdev->pm.current_clock_mode_index = -1; - rdev->pm.current_sclk = 0; - rdev->pm.current_mclk = 0; mutex_unlock(&rdev->pm.mutex); } void radeon_pm_resume(struct radeon_device *rdev) { + /* asic init will reset the default power state */ + mutex_lock(&rdev->pm.mutex); + rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.current_clock_mode_index = 0; + rdev->pm.current_sclk = rdev->clock.default_sclk; + rdev->pm.current_mclk = rdev->clock.default_mclk; + mutex_unlock(&rdev->pm.mutex); radeon_pm_compute_clocks(rdev); } @@ -385,12 +388,13 @@ int radeon_pm_init(struct radeon_device *rdev) int ret; /* default to profile method */ rdev->pm.pm_method = PM_METHOD_PROFILE; + rdev->pm.profile = PM_PROFILE_DEFAULT; rdev->pm.dynpm_state = DYNPM_STATE_DISABLED; rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; rdev->pm.dynpm_can_upclock = true; rdev->pm.dynpm_can_downclock = true; - rdev->pm.current_sclk = 0; - rdev->pm.current_mclk = 0; + rdev->pm.current_sclk = rdev->clock.default_sclk; + rdev->pm.current_mclk = rdev->clock.default_mclk; if (rdev->bios) { if (rdev->is_atom_bios) @@ -398,19 +402,9 @@ int radeon_pm_init(struct radeon_device *rdev) else radeon_combios_get_power_modes(rdev); radeon_pm_init_profile(rdev); - rdev->pm.current_power_state_index = -1; - rdev->pm.current_clock_mode_index = -1; } if (rdev->pm.num_power_states > 1) { - if (rdev->pm.pm_method == PM_METHOD_PROFILE) { - mutex_lock(&rdev->pm.mutex); - rdev->pm.profile = PM_PROFILE_DEFAULT; - radeon_pm_update_profile(rdev); - radeon_pm_set_clocks(rdev); - mutex_unlock(&rdev->pm.mutex); - } - /* where's the best place to put these? */ ret = device_create_file(rdev->dev, &dev_attr_power_profile); if (ret) -- GitLab From c9e75b2125b563e67663f78ad53ea9387a9a7aa1 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Wed, 2 Jun 2010 17:56:01 -0400 Subject: [PATCH 747/842] drm/radeon/kms/pm: add mid profile This adds an additional profile, mid, to the pm profile code which takes the place of the old low profile. The default behavior remains the same, e.g., auto profile now selects between mid and high profiles based on power source, however, you can now manually force the low profile which was previously only available as a dpms off state. Enabling the low profile when the displays are on has been known to cause display corruption in some cases. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/r100.c | 10 ++++ drivers/gpu/drm/radeon/r420.c | 12 +++- drivers/gpu/drm/radeon/r600.c | 94 ++++++++++++++++++++++++++++-- drivers/gpu/drm/radeon/radeon.h | 11 ++-- drivers/gpu/drm/radeon/radeon_pm.c | 12 +++- 5 files changed, 126 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index cc004b05d63e..cf89aa2eb28c 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -162,6 +162,11 @@ void r100_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* mid sh */ + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; /* high sh */ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; @@ -172,6 +177,11 @@ void r100_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* mid mh */ + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; /* high mh */ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 4415a5ee5871..e6c89142bb4d 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -45,9 +45,14 @@ void r420_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; /* low sh */ rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* mid sh */ + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; /* high sh */ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; @@ -58,6 +63,11 @@ void r420_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* mid mh */ + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; /* high mh */ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index e14f59748e65..d152ceca5d37 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -291,6 +291,11 @@ void rs780_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* mid sh */ + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; /* high sh */ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; @@ -301,6 +306,11 @@ void rs780_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* mid mh */ + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; /* high mh */ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 1; @@ -317,6 +327,11 @@ void rs780_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* mid sh */ + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; /* high sh */ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 2; @@ -327,6 +342,11 @@ void rs780_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* mid mh */ + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; /* high mh */ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 2; @@ -343,6 +363,11 @@ void rs780_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 2; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* mid sh */ + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; /* high sh */ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 2; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 3; @@ -353,6 +378,11 @@ void rs780_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* mid mh */ + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; /* high mh */ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 2; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 3; @@ -375,6 +405,11 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* mid sh */ + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; /* high sh */ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; @@ -385,6 +420,11 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* mid mh */ + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; /* high mh */ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; @@ -401,7 +441,12 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + /* mid sh */ + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = 1; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1; /* high sh */ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = 1; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = 1; @@ -411,7 +456,12 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = 2; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = 2; rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + /* low mh */ + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = 2; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1; /* high mh */ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = 2; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = 2; @@ -430,14 +480,30 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; } else { rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + } + /* mid sh */ + if (rdev->flags & RADEON_IS_MOBILITY) { + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1; + } else { + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1; } /* high sh */ rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = @@ -453,14 +519,30 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 2; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; } else { rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 1; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + } + /* mid mh */ + if (rdev->flags & RADEON_IS_MOBILITY) { + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1; + } else { + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = + r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1; } /* high mh */ rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5f96fe871b3f..2ad0e0304294 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -648,15 +648,18 @@ enum radeon_pm_profile_type { PM_PROFILE_DEFAULT, PM_PROFILE_AUTO, PM_PROFILE_LOW, + PM_PROFILE_MID, PM_PROFILE_HIGH, }; #define PM_PROFILE_DEFAULT_IDX 0 #define PM_PROFILE_LOW_SH_IDX 1 -#define PM_PROFILE_HIGH_SH_IDX 2 -#define PM_PROFILE_LOW_MH_IDX 3 -#define PM_PROFILE_HIGH_MH_IDX 4 -#define PM_PROFILE_MAX 5 +#define PM_PROFILE_MID_SH_IDX 2 +#define PM_PROFILE_HIGH_SH_IDX 3 +#define PM_PROFILE_LOW_MH_IDX 4 +#define PM_PROFILE_MID_MH_IDX 5 +#define PM_PROFILE_HIGH_MH_IDX 6 +#define PM_PROFILE_MAX 7 struct radeon_pm_profile { int dpms_off_ps_idx; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 62e7f967c6c4..fcdf1db1e3ce 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -84,9 +84,9 @@ static void radeon_pm_update_profile(struct radeon_device *rdev) rdev->pm.profile_index = PM_PROFILE_HIGH_SH_IDX; } else { if (rdev->pm.active_crtc_count > 1) - rdev->pm.profile_index = PM_PROFILE_LOW_MH_IDX; + rdev->pm.profile_index = PM_PROFILE_MID_MH_IDX; else - rdev->pm.profile_index = PM_PROFILE_LOW_SH_IDX; + rdev->pm.profile_index = PM_PROFILE_MID_SH_IDX; } break; case PM_PROFILE_LOW: @@ -95,6 +95,12 @@ static void radeon_pm_update_profile(struct radeon_device *rdev) else rdev->pm.profile_index = PM_PROFILE_LOW_SH_IDX; break; + case PM_PROFILE_MID: + if (rdev->pm.active_crtc_count > 1) + rdev->pm.profile_index = PM_PROFILE_MID_MH_IDX; + else + rdev->pm.profile_index = PM_PROFILE_MID_SH_IDX; + break; case PM_PROFILE_HIGH: if (rdev->pm.active_crtc_count > 1) rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX; @@ -302,6 +308,8 @@ static ssize_t radeon_set_pm_profile(struct device *dev, rdev->pm.profile = PM_PROFILE_AUTO; else if (strncmp("low", buf, strlen("low")) == 0) rdev->pm.profile = PM_PROFILE_LOW; + else if (strncmp("mid", buf, strlen("mid")) == 0) + rdev->pm.profile = PM_PROFILE_MID; else if (strncmp("high", buf, strlen("high")) == 0) rdev->pm.profile = PM_PROFILE_HIGH; else { -- GitLab From cbd4623d4d3a622de6481052b44cd33ea880cd61 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Mon, 7 Jun 2010 02:24:54 -0400 Subject: [PATCH 748/842] drm/radeon/kms: fix typo in printing the HPD info I forgot to fix this in 8e36ed00842668a39a6ed1b0a00b8ac92b7c4cd5 Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 1006549d1570..8154cdf796e4 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -284,8 +284,7 @@ static const char *connector_names[15] = { "eDP", }; -static const char *hpd_names[7] = { - "NONE", +static const char *hpd_names[6] = { "HPD1", "HPD2", "HPD3", -- GitLab From aa1df0f229829109e49d1dc493252fd94a7af2a1 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Mon, 7 Jun 2010 11:35:53 -0400 Subject: [PATCH 749/842] drm/radeon/kms/pm: Disable voltage adjust on RS780/RS880 The vddc value in the power tables is not an actual voltage like on discrete r6xx/r7xx/evergreen systems, but instead has a symbolic meaning (e.g., NONE, LOW, HIGH, etc.). See atombios.h Most RS780/RS880 vbioses don't have a SetVoltage table anyway, so it shouldn't be doing anything to the hardware at the moment. I need to figure out how voltage is supposed to work on the newer IGPs; until then, disable it. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_atombios.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 4305cd55d0ac..f0fcd6c3d38c 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1833,10 +1833,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) /* skip invalid modes */ if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) continue; - rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = - VOLTAGE_SW; - rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = - clock_info->usVDDC; + /* voltage works differently on IGPs */ mode_index++; } else if (ASIC_IS_DCE4(rdev)) { struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *clock_info = -- GitLab From 4d60173fc1b12b0c308f861620fe8e2a84f6e5da Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexdeucher@gmail.com> Date: Mon, 7 Jun 2010 18:15:18 -0400 Subject: [PATCH 750/842] drm/radeon/kms/pm: track current voltage (v2) track the current voltage level and avoid setting it if the requested voltage is already set. v2: check voltage type before checking current voltage Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/evergreen.c | 8 ++++++-- drivers/gpu/drm/radeon/r600.c | 9 ++++++--- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_atombios.c | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 1 + drivers/gpu/drm/radeon/rv770.c | 9 +++++++-- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 49c94aef0dda..b86d6ac9c5ba 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -45,8 +45,12 @@ void evergreen_pm_misc(struct radeon_device *rdev) struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; struct radeon_voltage *voltage = &ps->clock_info[0].voltage; - if ((voltage->type == VOLTAGE_SW) && voltage->voltage) - radeon_atom_set_voltage(rdev, voltage->voltage); + if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { + if (voltage->voltage != rdev->pm.current_vddc) { + radeon_atom_set_voltage(rdev, voltage->voltage); + rdev->pm.current_vddc = voltage->voltage; + } + } } void evergreen_pm_prepare(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d152ceca5d37..acec26b70d0d 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -561,9 +561,12 @@ void r600_pm_misc(struct radeon_device *rdev) struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; struct radeon_voltage *voltage = &ps->clock_info[0].voltage; - if ((voltage->type == VOLTAGE_SW) && voltage->voltage) - radeon_atom_set_voltage(rdev, voltage->voltage); - + if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { + if (voltage->voltage != rdev->pm.current_vddc) { + radeon_atom_set_voltage(rdev, voltage->voltage); + rdev->pm.current_vddc = voltage->voltage; + } + } } bool r600_gui_idle(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 2ad0e0304294..8e1d44ca26ec 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -748,6 +748,7 @@ struct radeon_pm { int default_power_state_index; u32 current_sclk; u32 current_mclk; + u32 current_vddc; struct radeon_i2c_chan *i2c_bus; /* selected pm method */ enum radeon_pm_method pm_method; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index f0fcd6c3d38c..99bd8a9c56b3 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1966,6 +1966,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; rdev->pm.current_clock_mode_index = 0; + rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; } void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index fcdf1db1e3ce..f2e1c60afda5 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -387,6 +387,7 @@ void radeon_pm_resume(struct radeon_device *rdev) rdev->pm.current_clock_mode_index = 0; rdev->pm.current_sclk = rdev->clock.default_sclk; rdev->pm.current_mclk = rdev->clock.default_mclk; + rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; mutex_unlock(&rdev->pm.mutex); radeon_pm_compute_clocks(rdev); } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 33952da65340..7bde6eecf8c2 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -48,8 +48,13 @@ void rv770_pm_misc(struct radeon_device *rdev) struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; struct radeon_voltage *voltage = &ps->clock_info[0].voltage; - if ((voltage->type == VOLTAGE_SW) && voltage->voltage) - radeon_atom_set_voltage(rdev, voltage->voltage); + + if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { + if (voltage->voltage != rdev->pm.current_vddc) { + radeon_atom_set_voltage(rdev, voltage->voltage); + rdev->pm.current_vddc = voltage->voltage; + } + } } /* -- GitLab From a081a9d6f566160bc4c08a85b74d817e983595ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> Date: Mon, 7 Jun 2010 18:20:25 -0400 Subject: [PATCH 751/842] drm/radeon/kms/r600+: use voltage from requested clock mode (v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes FDO bug #28375, it's kind of regression, so quite important to have it for .35. V2: Fix on RV770+ as well. All other chipsets have only one clock mode per state. V3: I'm out of luck today. Grepped for voltage in r*.c and missed evergreen. agd5f: rebased Signed-off-by: Rafał Miłecki <zajec5@gmail.com> Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/evergreen.c | 7 ++++--- drivers/gpu/drm/radeon/r600.c | 7 ++++--- drivers/gpu/drm/radeon/rv770.c | 8 ++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index b86d6ac9c5ba..b2b7c11e447f 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -41,9 +41,10 @@ void evergreen_fini(struct radeon_device *rdev); void evergreen_pm_misc(struct radeon_device *rdev) { - int requested_index = rdev->pm.requested_power_state_index; - struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; - struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + int req_ps_idx = rdev->pm.requested_power_state_index; + int req_cm_idx = rdev->pm.requested_clock_mode_index; + struct radeon_power_state *ps = &rdev->pm.power_state[req_ps_idx]; + struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { if (voltage->voltage != rdev->pm.current_vddc) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index acec26b70d0d..7b5539100114 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -557,9 +557,10 @@ void r600_pm_init_profile(struct radeon_device *rdev) void r600_pm_misc(struct radeon_device *rdev) { - int requested_index = rdev->pm.requested_power_state_index; - struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; - struct radeon_voltage *voltage = &ps->clock_info[0].voltage; + int req_ps_idx = rdev->pm.requested_power_state_index; + int req_cm_idx = rdev->pm.requested_clock_mode_index; + struct radeon_power_state *ps = &rdev->pm.power_state[req_ps_idx]; + struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { if (voltage->voltage != rdev->pm.current_vddc) { diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 7bde6eecf8c2..e8fb8b66e002 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -44,10 +44,10 @@ void rv770_fini(struct radeon_device *rdev); void rv770_pm_misc(struct radeon_device *rdev) { - int requested_index = rdev->pm.requested_power_state_index; - struct radeon_power_state *ps = &rdev->pm.power_state[requested_index]; - struct radeon_voltage *voltage = &ps->clock_info[0].voltage; - + int req_ps_idx = rdev->pm.requested_power_state_index; + int req_cm_idx = rdev->pm.requested_clock_mode_index; + struct radeon_power_state *ps = &rdev->pm.power_state[req_ps_idx]; + struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { if (voltage->voltage != rdev->pm.current_vddc) { -- GitLab From 0fcbe9473ac9c53463a61c9c83db8293bee15d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> Date: Mon, 7 Jun 2010 18:25:21 -0400 Subject: [PATCH 752/842] drm/radeon/kms: add trivial debugging for voltage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit agd5f: rebased Signed-off-by: Rafał Miłecki <zajec5@gmail.com> Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/evergreen.c | 1 + drivers/gpu/drm/radeon/r600.c | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 2 ++ drivers/gpu/drm/radeon/rv770.c | 1 + 4 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index b2b7c11e447f..4b6623df3b96 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -50,6 +50,7 @@ void evergreen_pm_misc(struct radeon_device *rdev) if (voltage->voltage != rdev->pm.current_vddc) { radeon_atom_set_voltage(rdev, voltage->voltage); rdev->pm.current_vddc = voltage->voltage; + DRM_DEBUG("Setting: v: %d\n", voltage->voltage); } } } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 7b5539100114..0e91871f45be 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -566,6 +566,7 @@ void r600_pm_misc(struct radeon_device *rdev) if (voltage->voltage != rdev->pm.current_vddc) { radeon_atom_set_voltage(rdev, voltage->voltage); rdev->pm.current_vddc = voltage->voltage; + DRM_DEBUG("Setting: v: %d\n", voltage->voltage); } } } diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index f2e1c60afda5..19fb3652c7bd 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -699,6 +699,8 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data) seq_printf(m, "default memory clock: %u0 kHz\n", rdev->clock.default_mclk); if (rdev->asic->get_memory_clock) seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); + if (rdev->pm.current_vddc) + seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc); if (rdev->asic->get_pcie_lanes) seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev)); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index e8fb8b66e002..cec536c222c5 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -53,6 +53,7 @@ void rv770_pm_misc(struct radeon_device *rdev) if (voltage->voltage != rdev->pm.current_vddc) { radeon_atom_set_voltage(rdev, voltage->voltage); rdev->pm.current_vddc = voltage->voltage; + DRM_DEBUG("Setting: v: %d\n", voltage->voltage); } } } -- GitLab From f712d0c7e726ccbf2ab668cc30f307ecf37adf4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> Date: Mon, 7 Jun 2010 18:29:44 -0400 Subject: [PATCH 753/842] drm/radeon/kms/pm: resurrect printing power states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit debug only agd5f: rebased Signed-off-by: Rafał Miłecki <zajec5@gmail.com> Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_pm.c | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 19fb3652c7bd..63f679a04b25 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -33,6 +33,14 @@ #define RADEON_WAIT_VBLANK_TIMEOUT 200 #define RADEON_WAIT_IDLE_TIMEOUT 200 +static const char *radeon_pm_state_type_name[5] = { + "Default", + "Powersave", + "Battery", + "Balanced", + "Performance", +}; + static void radeon_dynpm_idle_work_handler(struct work_struct *work); static int radeon_debugfs_pm_init(struct radeon_device *rdev); static bool radeon_pm_in_vbl(struct radeon_device *rdev); @@ -278,6 +286,42 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) mutex_unlock(&rdev->ddev->struct_mutex); } +static void radeon_pm_print_states(struct radeon_device *rdev) +{ + int i, j; + struct radeon_power_state *power_state; + struct radeon_pm_clock_info *clock_info; + + DRM_DEBUG("%d Power State(s)\n", rdev->pm.num_power_states); + for (i = 0; i < rdev->pm.num_power_states; i++) { + power_state = &rdev->pm.power_state[i]; + DRM_DEBUG("State %d: %s\n", i, + radeon_pm_state_type_name[power_state->type]); + if (i == rdev->pm.default_power_state_index) + DRM_DEBUG("\tDefault"); + if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) + DRM_DEBUG("\t%d PCIE Lanes\n", power_state->pcie_lanes); + if (power_state->flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) + DRM_DEBUG("\tSingle display only\n"); + DRM_DEBUG("\t%d Clock Mode(s)\n", power_state->num_clock_modes); + for (j = 0; j < power_state->num_clock_modes; j++) { + clock_info = &(power_state->clock_info[j]); + if (rdev->flags & RADEON_IS_IGP) + DRM_DEBUG("\t\t%d e: %d%s\n", + j, + clock_info->sclk * 10, + clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : ""); + else + DRM_DEBUG("\t\t%d e: %d\tm: %d\tv: %d%s\n", + j, + clock_info->sclk * 10, + clock_info->mclk * 10, + clock_info->voltage.voltage, + clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : ""); + } + } +} + static ssize_t radeon_get_pm_profile(struct device *dev, struct device_attribute *attr, char *buf) @@ -410,6 +454,7 @@ int radeon_pm_init(struct radeon_device *rdev) radeon_atombios_get_power_modes(rdev); else radeon_combios_get_power_modes(rdev); + radeon_pm_print_states(rdev); radeon_pm_init_profile(rdev); } -- GitLab From 1eb38100abc467f1133e548d82ab171cab34292b Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Tue, 1 Jun 2010 13:40:41 +1000 Subject: [PATCH 754/842] drm/nouveau: match U/DP script against SOR link It appears version 0x21 'U' and 'd' tables require us to take the SOR link into account when selecting the appropriate table for a particular output. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_bios.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 9ba2deaadcc7..47a27a4728da 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -3920,7 +3920,8 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b static uint8_t * bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent, - uint16_t record, int record_len, int record_nr) + uint16_t record, int record_len, int record_nr, + bool match_link) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nvbios *bios = &dev_priv->vbios; @@ -3928,12 +3929,28 @@ bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent, uint16_t table; int i, v; + switch (dcbent->type) { + case OUTPUT_TMDS: + case OUTPUT_LVDS: + case OUTPUT_DP: + break; + default: + match_link = false; + break; + } + for (i = 0; i < record_nr; i++, record += record_len) { table = ROM16(bios->data[record]); if (!table) continue; entry = ROM32(bios->data[table]); + if (match_link) { + v = (entry & 0x00c00000) >> 22; + if (!(v & dcbent->sorconf.link)) + continue; + } + v = (entry & 0x000f0000) >> 16; if (!(v & dcbent->or)) continue; @@ -3975,7 +3992,7 @@ nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent, *length = table[4]; return bios_output_config_match(dev, dcbent, bios->display.dp_table_ptr + table[1], - table[2], table[3]); + table[2], table[3], table[0] >= 0x21); } int @@ -4064,7 +4081,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, dcbent->type, dcbent->location, dcbent->or); otable = bios_output_config_match(dev, dcbent, table[1] + bios->display.script_table_ptr, - table[2], table[3]); + table[2], table[3], table[0] >= 0x21); if (!otable) { NV_ERROR(dev, "Couldn't find matching output script table\n"); return 1; -- GitLab From 6d696305530c0b3fcd7d15ad87d7203cb53df5b7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Wed, 2 Jun 2010 10:16:24 +1000 Subject: [PATCH 755/842] drm/nouveau: completely fail init if we fail to map the PRAMIN BAR On cards where there's a specific BAR for PRAMIN, we used to try and fall back to the "legacy" aperture within the mmio BAR. This is doomed to cause problems, so lets just fail completely as there's obviously something else very wrong anyway. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_state.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 147e59c40151..b02a231d6937 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -779,29 +779,24 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) return ret; } - /* map larger RAMIN aperture on NV40 cards */ - dev_priv->ramin = NULL; + /* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */ if (dev_priv->card_type >= NV_40) { int ramin_bar = 2; if (pci_resource_len(dev->pdev, ramin_bar) == 0) ramin_bar = 3; dev_priv->ramin_size = pci_resource_len(dev->pdev, ramin_bar); - dev_priv->ramin = ioremap( - pci_resource_start(dev->pdev, ramin_bar), + dev_priv->ramin = + ioremap(pci_resource_start(dev->pdev, ramin_bar), dev_priv->ramin_size); if (!dev_priv->ramin) { - NV_ERROR(dev, "Failed to init RAMIN mapping, " - "limited instance memory available\n"); + NV_ERROR(dev, "Failed to PRAMIN BAR"); + return -ENOMEM; } - } - - /* On older cards (or if the above failed), create a map covering - * the BAR0 PRAMIN aperture */ - if (!dev_priv->ramin) { + } else { dev_priv->ramin_size = 1 * 1024 * 1024; dev_priv->ramin = ioremap(mmio_start_offs + NV_RAMIN, - dev_priv->ramin_size); + dev_priv->ramin_size); if (!dev_priv->ramin) { NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n"); return -ENOMEM; -- GitLab From 55a4c5c515c1f4b4bde00c443e71ff9f3822013e Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Thu, 22 Apr 2010 11:40:53 +0200 Subject: [PATCH 756/842] nouveau: off by one in nv50_gpio_location() If "gpio->line" is 32 then "nv50_gpio_reg[gpio->line >> 3]" reads past the end of the array. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/nouveau/nv50_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c index c61782b314e7..bb47ad737267 100644 --- a/drivers/gpu/drm/nouveau/nv50_gpio.c +++ b/drivers/gpu/drm/nouveau/nv50_gpio.c @@ -31,7 +31,7 @@ nv50_gpio_location(struct dcb_gpio_entry *gpio, uint32_t *reg, uint32_t *shift) { const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; - if (gpio->line > 32) + if (gpio->line >= 32) return -EINVAL; *reg = nv50_gpio_reg[gpio->line >> 3]; -- GitLab From 75047944480a33afad76a272b21116d032ba61fa Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Tue, 25 May 2010 11:52:27 +0200 Subject: [PATCH 757/842] drm/nouveau: off by one in init_i2c_device_find() dcb->i2c[] has DCB_MAX_NUM_I2C_ENTRIES entries. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_bios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 47a27a4728da..fc924b649195 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -834,7 +834,7 @@ init_i2c_device_find(struct drm_device *dev, int i2c_index) if (i2c_index == 0x81) i2c_index = (dcb->i2c_default_indices & 0xf0) >> 4; - if (i2c_index > DCB_MAX_NUM_I2C_ENTRIES) { + if (i2c_index >= DCB_MAX_NUM_I2C_ENTRIES) { NV_ERROR(dev, "invalid i2c_index 0x%x\n", i2c_index); return NULL; } -- GitLab From 4eb3033c72099fab3536ed8ac54a5dc99f0832d7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Mon, 7 Jun 2010 13:59:40 +1000 Subject: [PATCH 758/842] drm/nv50: fix iommu errors caused by device reading from address 0 Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/nouveau/nv50_fb.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c index a95e6941ba88..32611bd30e6d 100644 --- a/drivers/gpu/drm/nouveau/nv50_fb.c +++ b/drivers/gpu/drm/nouveau/nv50_fb.c @@ -6,10 +6,16 @@ int nv50_fb_init(struct drm_device *dev) { - /* This is needed to get meaningful information from 100c90 - * on traps. No idea what these values mean exactly. */ struct drm_nouveau_private *dev_priv = dev->dev_private; + /* Not a clue what this is exactly. Without pointing it at a + * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) + * cause IOMMU "read from address 0" errors (rh#561267) + */ + nv_wr32(dev, 0x100c08, dev_priv->gart_info.sg_dummy_bus >> 8); + + /* This is needed to get meaningful information from 100c90 + * on traps. No idea what these values mean exactly. */ switch (dev_priv->chipset) { case 0x50: nv_wr32(dev, 0x100c90, 0x0707ff); -- GitLab From d294ed69408b54c18f0420516ea057b2a734624d Mon Sep 17 00:00:00 2001 From: Dave Airlie <airlied@redhat.com> Date: Tue, 8 Jun 2010 13:04:50 +1000 Subject: [PATCH 759/842] drm/radeon: reset i2c valid to avoid incorrect tv-out polling. We really don't want to be polling tv-out but since we weren't forcing the i2c lines to invalid (tv-out has no DDC), we were adding tv connectors to the polling setup and this was causing blinking on secondary displays. This fixes the regression Torsten reported. Reported-by: Torsten Kaiser <just.for.lkml@googlemail.com> Tested-by: Torsten Kaiser <just.for.lkml@googlemail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_combios.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index f6f907e7217a..1bee2f9e24a5 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2026,6 +2026,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC); break; default: + ddc_i2c.valid = false; break; } @@ -2339,6 +2340,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) if (RBIOS8(tv_info + 6) == 'T') { if (radeon_apply_legacy_tv_quirks(dev)) { hpd.hpd = RADEON_HPD_NONE; + ddc_i2c.valid = false; radeon_add_legacy_encoder(dev, radeon_get_encoder_id (dev, -- GitLab From b62e948fd00bda1be2af31b591e5284374de551f Mon Sep 17 00:00:00 2001 From: Dave Airlie <airlied@redhat.com> Date: Tue, 8 Jun 2010 10:42:28 +1000 Subject: [PATCH 760/842] drm/radeon: don't poll tv dac if crtc2 is in use. So when we added output polling, we'd suddenly use this code more often, and the fact that it always takes over crtc2 and messes with it during probing isn't what we really want to be happening. A more complete fix would to change it to use whatever crtc was free at the time, but for now lets stay simple and just don't poll if crtc2 is already in use. Although a more correct fix was found I suspect we should do this as well, until we get a chance to readdres the tv out polling issues. Reported-by: Torsten Kaiser <just.for.lkml@googlemail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 5a13b3eeef19..5b07b8848e09 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -1168,6 +1168,17 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; bool color = true; + struct drm_crtc *crtc; + + /* find out if crtc2 is in use or if this encoder is using it */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + if ((radeon_crtc->crtc_id == 1) && crtc->enabled) { + if (encoder->crtc != crtc) { + return connector_status_disconnected; + } + } + } if (connector->connector_type == DRM_MODE_CONNECTOR_SVIDEO || connector->connector_type == DRM_MODE_CONNECTOR_Composite || -- GitLab From f534116308a0d553641725c4619814337758784f Mon Sep 17 00:00:00 2001 From: Yegor Yefremov <yegorslists@googlemail.com> Date: Tue, 8 Jun 2010 08:57:13 +0200 Subject: [PATCH 761/842] ALSA: atmel: set "channel A event" output to debug Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/atmel/ac97c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 428121a7e705..10c3a871a12d 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -657,7 +657,7 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) if (sr & AC97C_SR_CAEVT) { struct snd_pcm_runtime *runtime; int offset, next_period, block_size; - dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", + dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", casr & AC97C_CSR_OVRUN ? " OVRUN" : "", casr & AC97C_CSR_RXRDY ? " RXRDY" : "", casr & AC97C_CSR_UNRUN ? " UNRUN" : "", -- GitLab From 6e12970bd4f453c9cfcac6564567efe515ce1f1d Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" <justinmattock@gmail.com> Date: Sun, 6 Jun 2010 16:09:49 -0700 Subject: [PATCH 762/842] ALSA: hda - Add SSID table for MacBookAir2,1 This adds the SSID number to snd_pci_quirk for the MacBookAir2,1 taken from codec#0 at: http://launchpadlibrarian.net/49455483/Card0.Codecs.codec.0.txt keep in mind I do not have one of these machines on hand so please if you do have this machine please test for me.. Signed-off-by: Justin P. Mattock <justinmattock@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d792cddbf4c2..f266c544ac69 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9477,6 +9477,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), + SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21), SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), -- GitLab From f53dae28cd17ec618a1295962d0f40e00b84665d Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" <justinmattock@gmail.com> Date: Sun, 6 Jun 2010 16:09:51 -0700 Subject: [PATCH 763/842] ALSA: hda - Add SSID table for MacBookAir1,1 This patch add's the MacBookAir1,1 SSID entry to patch_realtek.c which adds sound support. bug entry: https://bugs.launchpad.net/mactel-support/+bug/268301 Note:I do not have this machine on hand only codec#0 file for the machine so please test if you have the appropriate equipment. Signed-off-by: Justin P. Mattock <justinmattock@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f266c544ac69..9df3c088942d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9477,6 +9477,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), + SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21), SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), -- GitLab From ab669967d0ecf784567843180e715ccb0e42db36 Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" <justinmattock@gmail.com> Date: Sun, 6 Jun 2010 16:09:53 -0700 Subject: [PATCH 764/842] ALSA: hda - Add SSID table for iMac7,1. This patch add's the iMac7,1 SSID entry to patch_realtek.c which adds sound support. bug entry: https://bugs.launchpad.net/mactel-support/+bug/360866 Note:I do not have this machine on hand only codec#0 file for the machine so please test if you have the appropriate equipment. Signed-off-by: Justin P. Mattock <justinmattock@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9df3c088942d..fc767b6b4785 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9477,6 +9477,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), + SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M), SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21), SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), -- GitLab From ff8bd64eaf2963752feaa0ac2f7ff1254e0091ce Mon Sep 17 00:00:00 2001 From: Wan ZongShun <mcuos.com@gmail.com> Date: Tue, 8 Jun 2010 16:51:27 +0200 Subject: [PATCH 765/842] ALSA: sound/spi: patch for the unuseful variable removal The '*bitclk' of structure 'snd_at73c213' seems no use, so I make a patch to remove the unnecessary variable. Signed-off-by: Wan ZongShun <mcuos.com@gmail.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Takashi Iwai <tiwai@suse.de> --- sound/spi/at73c213.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 4c7b051f9d17..1bc56b2b94e2 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -69,7 +69,6 @@ struct snd_at73c213 { int irq; int period; unsigned long bitrate; - struct clk *bitclk; struct ssc_device *ssc; struct spi_device *spi; u8 spi_wbuffer[2]; -- GitLab From f6ab91add6355e231e1c47897027b2a6ee4fa268 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra <a.p.zijlstra@chello.nl> Date: Fri, 4 Jun 2010 15:18:01 +0200 Subject: [PATCH 766/842] perf: Fix signed comparison in perf_adjust_period() Frederic reported that frequency driven swevents didn't work properly and even caused a division-by-zero error. It turns out there are two bugs, the division-by-zero comes from a failure to deal with that in perf_calculate_period(). The other was more interesting and turned out to be a wrong comparison in perf_adjust_period(). The comparison was between an s64 and u64 and got implicitly converted to an unsigned comparison. The problem is that period_left is typically < 0, so it ended up being always true. Cure this by making the local period variables s64. Reported-by: Frederic Weisbecker <fweisbec@gmail.com> Tested-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: <stable@kernel.org> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu> --- kernel/perf_event.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 31d6afe92594..ff86c558af4c 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -1507,6 +1507,9 @@ do { \ divisor = nsec * frequency; } + if (!divisor) + return dividend; + return div64_u64(dividend, divisor); } @@ -1529,7 +1532,7 @@ static int perf_event_start(struct perf_event *event) static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count) { struct hw_perf_event *hwc = &event->hw; - u64 period, sample_period; + s64 period, sample_period; s64 delta; period = perf_calculate_period(event, nsec, count); -- GitLab From c2f0e8c803ceba530060ec9bb9c74a06c2c3d833 Mon Sep 17 00:00:00 2001 From: Heiko Carstens <heiko.carstens@de.ibm.com> Date: Tue, 8 Jun 2010 18:58:09 +0200 Subject: [PATCH 767/842] [S390] appldata/extmem/kvm: add missing GFP_KERNEL flag Add missing GFP flag to memory allocations. The part in cio only changes a comment. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> --- arch/s390/appldata/appldata_os.c | 2 +- arch/s390/kvm/kvm-s390.c | 2 +- arch/s390/mm/extmem.c | 19 ++++++++++--------- drivers/s390/cio/itcw.c | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c index 55c80ffd42b9..92f1cb745d69 100644 --- a/arch/s390/appldata/appldata_os.c +++ b/arch/s390/appldata/appldata_os.c @@ -181,7 +181,7 @@ static int __init appldata_os_init(void) goto out; } - appldata_os_data = kzalloc(max_size, GFP_DMA); + appldata_os_data = kzalloc(max_size, GFP_KERNEL | GFP_DMA); if (appldata_os_data == NULL) { rc = -ENOMEM; goto out; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 8093e6f47f49..ae3705816878 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -761,7 +761,7 @@ static int __init kvm_s390_init(void) * to hold the maximum amount of facilites. On the other hand, we * only set facilities that are known to work in KVM. */ - facilities = (unsigned long long *) get_zeroed_page(GFP_DMA); + facilities = (unsigned long long *) get_zeroed_page(GFP_KERNEL|GFP_DMA); if (!facilities) { kvm_exit(); return -ENOMEM; diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 6409fd57eb04..3cc95dd0a3a6 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -105,7 +105,7 @@ static int dcss_set_subcodes(void) { #ifdef CONFIG_64BIT - char *name = kmalloc(8 * sizeof(char), GFP_DMA); + char *name = kmalloc(8 * sizeof(char), GFP_KERNEL | GFP_DMA); unsigned long rx, ry; int rc; @@ -252,12 +252,13 @@ dcss_diag_translate_rc (int vm_rc) { static int query_segment_type (struct dcss_segment *seg) { - struct qin64 *qin = kmalloc (sizeof(struct qin64), GFP_DMA); - struct qout64 *qout = kmalloc (sizeof(struct qout64), GFP_DMA); - - int diag_cc, rc, i; unsigned long dummy, vmrc; + int diag_cc, rc, i; + struct qout64 *qout; + struct qin64 *qin; + qin = kmalloc(sizeof(*qin), GFP_KERNEL | GFP_DMA); + qout = kmalloc(sizeof(*qout), GFP_KERNEL | GFP_DMA); if ((qin == NULL) || (qout == NULL)) { rc = -ENOMEM; goto out_free; @@ -286,7 +287,7 @@ query_segment_type (struct dcss_segment *seg) copy data for the new format. */ if (segext_scode == DCSS_SEGEXT) { struct qout64_old *qout_old; - qout_old = kzalloc(sizeof(struct qout64_old), GFP_DMA); + qout_old = kzalloc(sizeof(*qout_old), GFP_KERNEL | GFP_DMA); if (qout_old == NULL) { rc = -ENOMEM; goto out_free; @@ -407,11 +408,11 @@ segment_overlaps_others (struct dcss_segment *seg) static int __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end) { - struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment), - GFP_DMA); - int rc, diag_cc; unsigned long start_addr, end_addr, dummy; + struct dcss_segment *seg; + int rc, diag_cc; + seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA); if (seg == NULL) { rc = -ENOMEM; goto out; diff --git a/drivers/s390/cio/itcw.c b/drivers/s390/cio/itcw.c index 17da9ab932ed..a0ae29564774 100644 --- a/drivers/s390/cio/itcw.c +++ b/drivers/s390/cio/itcw.c @@ -42,7 +42,7 @@ * size_t size; * * size = itcw_calc_size(1, 2, 0); - * buffer = kmalloc(size, GFP_DMA); + * buffer = kmalloc(size, GFP_KERNEL | GFP_DMA); * if (!buffer) * return -ENOMEM; * itcw = itcw_init(buffer, size, ITCW_OP_READ, 1, 2, 0); -- GitLab From 3164a3cbf8a6bdf85fe3816fe670b391f31c004a Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Date: Tue, 8 Jun 2010 18:58:10 +0200 Subject: [PATCH 768/842] [S390] kprobes: add parameter check to module_free() When unregistering kprobes, kprobes calls module_free() and always passes NULL for the mod parameter. Add a check to prevent NULL pointer dereferences. See commit 740a8de0796dd12890b3c8ddcfabfcb528b78d40 for more details. Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> --- arch/s390/kernel/module.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 639380a0c45c..22cfd634c355 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -55,8 +55,10 @@ void *module_alloc(unsigned long size) /* Free memory returned from module_alloc */ void module_free(struct module *mod, void *module_region) { - vfree(mod->arch.syminfo); - mod->arch.syminfo = NULL; + if (mod) { + vfree(mod->arch.syminfo); + mod->arch.syminfo = NULL; + } vfree(module_region); } -- GitLab From 9940fa80ce0e546646b057958960c5c6fd2bbbb2 Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Tue, 8 Jun 2010 18:58:11 +0200 Subject: [PATCH 769/842] [S390] arch/s390/kvm: Use GFP_ATOMIC when a lock is held The containing function is called from several places. At one of them, in the function __sigp_stop, the spin lock &fi->lock is held. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // <smpl> @gfp exists@ identifier fn; position p; @@ fn(...) { ... when != spin_unlock when any GFP_KERNEL@p ... when any } @locked@ identifier gfp.fn; @@ spin_lock(...) ... when != spin_unlock fn(...) @depends on locked@ position gfp.p; @@ - GFP_KERNEL@p + GFP_ATOMIC // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Acked-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> --- arch/s390/kvm/sigp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index eff3c5989b46..702276f5e2fa 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -113,7 +113,7 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action) { struct kvm_s390_interrupt_info *inti; - inti = kzalloc(sizeof(*inti), GFP_KERNEL); + inti = kzalloc(sizeof(*inti), GFP_ATOMIC); if (!inti) return -ENOMEM; inti->type = KVM_S390_SIGP_STOP; -- GitLab From 40a510ddc57b49a01668643b1dec691a0e996c52 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky <schwidefsky@de.ibm.com> Date: Tue, 8 Jun 2010 18:58:12 +0200 Subject: [PATCH 770/842] [S390] Update default configuration. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> --- arch/s390/defconfig | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/arch/s390/defconfig b/arch/s390/defconfig index bcd6884985ad..253f158db668 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.34-rc3 -# Fri Apr 9 09:57:10 2010 +# Linux kernel version: 2.6.35-rc1 +# Fri Jun 4 11:32:40 2010 # CONFIG_SCHED_MC=y CONFIG_MMU=y @@ -35,11 +35,13 @@ CONFIG_CONSTRUCTORS=y CONFIG_EXPERIMENTAL=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_BZIP2=y CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y CONFIG_KERNEL_GZIP=y # CONFIG_KERNEL_BZIP2 is not set # CONFIG_KERNEL_LZMA is not set @@ -77,6 +79,7 @@ CONFIG_CGROUP_NS=y # CONFIG_CGROUP_CPUACCT is not set # CONFIG_RESOURCE_COUNTERS is not set # CONFIG_CGROUP_SCHED is not set +# CONFIG_BLK_CGROUP is not set CONFIG_SYSFS_DEPRECATED=y CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_RELAY is not set @@ -157,7 +160,6 @@ CONFIG_STOP_MACHINE=y CONFIG_BLOCK=y CONFIG_BLK_DEV_BSG=y # CONFIG_BLK_DEV_INTEGRITY is not set -# CONFIG_BLK_CGROUP is not set CONFIG_BLOCK_COMPAT=y # @@ -166,7 +168,6 @@ CONFIG_BLOCK_COMPAT=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y -# CONFIG_CFQ_GROUP_IOSCHED is not set CONFIG_DEFAULT_DEADLINE=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set @@ -247,7 +248,6 @@ CONFIG_64BIT=y CONFIG_SMP=y CONFIG_NR_CPUS=32 CONFIG_HOTPLUG_CPU=y -# CONFIG_SCHED_BOOK is not set CONFIG_COMPAT=y CONFIG_SYSVIPC_COMPAT=y CONFIG_AUDIT_ARCH=y @@ -320,7 +320,6 @@ CONFIG_COMPAT_BINFMT_ELF=y # CONFIG_HAVE_AOUT is not set CONFIG_BINFMT_MISC=m CONFIG_FORCE_MAX_ZONEORDER=9 -# CONFIG_PROCESS_DEBUG is not set CONFIG_PFAULT=y # CONFIG_SHARED_KERNEL is not set # CONFIG_CMM is not set @@ -457,6 +456,7 @@ CONFIG_NF_CONNTRACK=m # CONFIG_IP6_NF_IPTABLES is not set # CONFIG_IP_DCCP is not set CONFIG_IP_SCTP=m +# CONFIG_NET_SCTPPROBE is not set # CONFIG_SCTP_DBG_MSG is not set # CONFIG_SCTP_DBG_OBJCNT is not set # CONFIG_SCTP_HMAC_NONE is not set @@ -465,6 +465,7 @@ CONFIG_SCTP_HMAC_MD5=y # CONFIG_RDS is not set # CONFIG_TIPC is not set # CONFIG_ATM is not set +# CONFIG_L2TP is not set # CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set # CONFIG_DECNET is not set @@ -525,6 +526,7 @@ CONFIG_NET_ACT_NAT=m # CONFIG_NET_CLS_IND is not set CONFIG_NET_SCH_FIFO=y # CONFIG_DCB is not set +CONFIG_RPS=y # # Network testing @@ -546,6 +548,7 @@ CONFIG_CAN_VCAN=m # CONFIG_WIMAX is not set # CONFIG_RFKILL is not set # CONFIG_NET_9P is not set +# CONFIG_CAIF is not set # CONFIG_PCMCIA is not set CONFIG_CCW=y @@ -728,6 +731,7 @@ CONFIG_VIRTIO_NET=m # Character devices # CONFIG_DEVKMEM=y +# CONFIG_N_GSM is not set CONFIG_UNIX98_PTYS=y # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set CONFIG_LEGACY_PTYS=y @@ -775,6 +779,7 @@ CONFIG_S390_TAPE_34XX=m # CONFIG_MONREADER is not set CONFIG_MONWRITER=m CONFIG_S390_VMUR=m +# CONFIG_RAMOOPS is not set # # PPS support @@ -788,10 +793,6 @@ CONFIG_S390_VMUR=m # CONFIG_NEW_LEDS is not set CONFIG_ACCESSIBILITY=y # CONFIG_AUXDISPLAY is not set - -# -# TI VLYNQ -# # CONFIG_STAGING is not set # @@ -976,6 +977,7 @@ CONFIG_DEBUG_MEMORY_INIT=y # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y # CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_LATENCYTOP is not set CONFIG_SYSCTL_SYSCALL_CHECK=y @@ -1010,6 +1012,7 @@ CONFIG_BRANCH_PROFILE_NONE=y CONFIG_KPROBE_EVENT=y # CONFIG_RING_BUFFER_BENCHMARK is not set # CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set CONFIG_SAMPLES=y # CONFIG_SAMPLE_TRACEPOINTS is not set # CONFIG_SAMPLE_TRACE_EVENTS is not set -- GitLab From b394eebdd3d436f1796e53b97799554c5aa77431 Mon Sep 17 00:00:00 2001 From: Linus Walleij <linus.walleij@stericsson.com> Date: Mon, 31 May 2010 09:28:30 +0100 Subject: [PATCH 771/842] ARM: 6152/1: ux500 make it possible to disable localtimers Currently compilation of ux500 fails if you deselect the kernel feature for localtimers. Acked-by: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/mach-ux500/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index c7bc4199e3a8..4556aea9c3c5 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o obj-$(CONFIG_MACH_U5500) += board-u5500.o -obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o -- GitLab From 17ebba1fe4da4b5d62782be8743e0e8231812af9 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre <nico@fluxnic.net> Date: Mon, 7 Jun 2010 21:28:55 +0100 Subject: [PATCH 772/842] ARM: 6165/1: trap overflows on highmem pages from kmap_atomic when debugging When CONFIG_DEBUG_HIGHMEM is used, the fixmap entry used for a highmem page by kmap_atomic() is always cleared by kunmap_atomic(). This helps find bad usages such as dereferences after the unmap, or overflow into the adjacent fixmap areas. But this debugging aid is completely bypassed when a kmap for the same page already exists as the kmap is reused instead. ON VIVT systems we have no choice but to reuse that kmap due to cache coherency issues, but on non VIVT systems we should always force the fixmap usage when debugging is active. Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/mm/highmem.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index 77b030f5ec09..086816b205b8 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -48,7 +48,16 @@ void *kmap_atomic(struct page *page, enum km_type type) debug_kmap_atomic(type); - kmap = kmap_high_get(page); +#ifdef CONFIG_DEBUG_HIGHMEM + /* + * There is no cache coherency issue when non VIVT, so force the + * dedicated kmap usage for better debugging purposes in that case. + */ + if (!cache_is_vivt()) + kmap = NULL; + else +#endif + kmap = kmap_high_get(page); if (kmap) return kmap; -- GitLab From 6db6340c42d027b6364d49fa99d69019aca24de4 Mon Sep 17 00:00:00 2001 From: Johannes Berg <johannes.berg@intel.com> Date: Mon, 7 Jun 2010 21:20:38 +0200 Subject: [PATCH 773/842] iwlwifi: add missing rcu_read_lock Using ieee80211_find_sta() needs to be under RCU read lock, which iwlwifi currently misses, so fix it. Cc: stable@kernel.org Reported-by: Miles Lane <miles.lane@gmail.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Acked-by: Reinette Chatre <reinette.chatre@intel.com> Tested-by: Miles Lane <miles.lane@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index c402bfc83f36..a732f1094e5d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -1125,6 +1125,7 @@ static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb) struct ieee80211_sta *sta; struct iwl_station_priv *sta_priv; + rcu_read_lock(); sta = ieee80211_find_sta(priv->vif, hdr->addr1); if (sta) { sta_priv = (void *)sta->drv_priv; @@ -1133,6 +1134,7 @@ static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb) atomic_dec_return(&sta_priv->pending_frames) == 0) ieee80211_sta_block_awake(priv->hw, sta, false); } + rcu_read_unlock(); ieee80211_tx_status_irqsafe(priv->hw, skb); } -- GitLab From 5e27fb78df95e027723af2c90ecc9b4527ae59e9 Mon Sep 17 00:00:00 2001 From: Anfei <anfei.zhou@gmail.com> Date: Tue, 8 Jun 2010 15:16:49 +0100 Subject: [PATCH 774/842] ARM: 6166/1: Proper prefetch abort handling on pre-ARMv6 Instruction faults on pre-ARMv6 CPUs are interpreted as a 'translation fault', but do_translation_fault doesn't handle well if user mode trying to run instruction above TASK_SIZE, and result in the infinite retry of that instruction. CC: <stable@kernel.org> Signed-off-by: Anfei Zhou <anfei.zhou@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/mm/fault.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 92f5801f99c1..cbfb2edcf7d1 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -393,6 +393,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr, if (addr < TASK_SIZE) return do_page_fault(addr, fsr, regs); + if (user_mode(regs)) + goto bad_area; + index = pgd_index(addr); /* -- GitLab From b054b747a694927879c94dd11af54d04346aed7d Mon Sep 17 00:00:00 2001 From: Johannes Berg <johannes.berg@intel.com> Date: Mon, 7 Jun 2010 21:50:07 +0200 Subject: [PATCH 775/842] mac80211: fix deauth before assoc When we receive a deauthentication frame before having successfully associated, we neither print a message nor abort assocation. The former makes it hard to debug, while the latter later causes a warning in cfg80211 when, as will typically be the case, association timed out. This warning was reported by many, e.g. in https://bugzilla.kernel.org/show_bug.cgi?id=15981, but I couldn't initially pinpoint it. I verified the fix by hacking hostapd to send a deauth frame instead of an association response. Cc: stable@kernel.org Signed-off-by: Johannes Berg <johannes.berg@intel.com> Tested-by: Miles Lane <miles.lane@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> --- net/mac80211/mlme.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3310e70aa52f..f803f8b72a93 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1760,9 +1760,45 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && - (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) { + struct ieee80211_local *local = sdata->local; + struct ieee80211_work *wk; + + mutex_lock(&local->work_mtx); + list_for_each_entry(wk, &local->work_list, list) { + if (wk->sdata != sdata) + continue; + + if (wk->type != IEEE80211_WORK_ASSOC) + continue; + + if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN)) + continue; + if (memcmp(mgmt->sa, wk->filter_ta, ETH_ALEN)) + continue; + /* + * Printing the message only here means we can't + * spuriously print it, but it also means that it + * won't be printed when the frame comes in before + * we even tried to associate or in similar cases. + * + * Ultimately, I suspect cfg80211 should print the + * messages instead. + */ + printk(KERN_DEBUG + "%s: deauthenticated from %pM (Reason: %u)\n", + sdata->name, mgmt->bssid, + le16_to_cpu(mgmt->u.deauth.reason_code)); + + list_del_rcu(&wk->list); + free_work(wk); + break; + } + mutex_unlock(&local->work_mtx); + + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); + } out: kfree_skb(skb); } -- GitLab From 9a40ac86152c9cffd3dca482a15ddf9a8c5716b3 Mon Sep 17 00:00:00 2001 From: Khem Raj <raj.khem@gmail.com> Date: Fri, 4 Jun 2010 04:05:15 +0100 Subject: [PATCH 776/842] ARM: 6164/1: Add kto and kfrom to input operands list. When functions incoming parameters are not in input operands list gcc 4.5 does not load the parameters into registers before calling this function but the inline assembly assumes valid addresses inside this function. This breaks the code because r0 and r1 are invalid when execution enters v4wb_copy_user_page () Also the constant needs to be used as third input operand so account for that as well. Tested on qemu arm. CC: <stable@kernel.org> Signed-off-by: Khem Raj <raj.khem@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/mm/copypage-feroceon.c | 4 ++-- arch/arm/mm/copypage-v4wb.c | 4 ++-- arch/arm/mm/copypage-v4wt.c | 4 ++-- arch/arm/mm/copypage-xsc3.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/mm/copypage-feroceon.c b/arch/arm/mm/copypage-feroceon.c index 5eb4fd93893d..ac163de7dc01 100644 --- a/arch/arm/mm/copypage-feroceon.c +++ b/arch/arm/mm/copypage-feroceon.c @@ -18,7 +18,7 @@ feroceon_copy_user_page(void *kto, const void *kfrom) { asm("\ stmfd sp!, {r4-r9, lr} \n\ - mov ip, %0 \n\ + mov ip, %2 \n\ 1: mov lr, r1 \n\ ldmia r1!, {r2 - r9} \n\ pld [lr, #32] \n\ @@ -64,7 +64,7 @@ feroceon_copy_user_page(void *kto, const void *kfrom) mcr p15, 0, ip, c7, c10, 4 @ drain WB\n\ ldmfd sp!, {r4-r9, pc}" : - : "I" (PAGE_SIZE)); + : "r" (kto), "r" (kfrom), "I" (PAGE_SIZE)); } void feroceon_copy_user_highpage(struct page *to, struct page *from, diff --git a/arch/arm/mm/copypage-v4wb.c b/arch/arm/mm/copypage-v4wb.c index 7c2eb55cd4a9..cb589cbb2b6c 100644 --- a/arch/arm/mm/copypage-v4wb.c +++ b/arch/arm/mm/copypage-v4wb.c @@ -27,7 +27,7 @@ v4wb_copy_user_page(void *kto, const void *kfrom) { asm("\ stmfd sp!, {r4, lr} @ 2\n\ - mov r2, %0 @ 1\n\ + mov r2, %2 @ 1\n\ ldmia r1!, {r3, r4, ip, lr} @ 4\n\ 1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\ stmia r0!, {r3, r4, ip, lr} @ 4\n\ @@ -44,7 +44,7 @@ v4wb_copy_user_page(void *kto, const void *kfrom) mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB\n\ ldmfd sp!, {r4, pc} @ 3" : - : "I" (PAGE_SIZE / 64)); + : "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64)); } void v4wb_copy_user_highpage(struct page *to, struct page *from, diff --git a/arch/arm/mm/copypage-v4wt.c b/arch/arm/mm/copypage-v4wt.c index 172e6a55458e..30c7d048a324 100644 --- a/arch/arm/mm/copypage-v4wt.c +++ b/arch/arm/mm/copypage-v4wt.c @@ -25,7 +25,7 @@ v4wt_copy_user_page(void *kto, const void *kfrom) { asm("\ stmfd sp!, {r4, lr} @ 2\n\ - mov r2, %0 @ 1\n\ + mov r2, %2 @ 1\n\ ldmia r1!, {r3, r4, ip, lr} @ 4\n\ 1: stmia r0!, {r3, r4, ip, lr} @ 4\n\ ldmia r1!, {r3, r4, ip, lr} @ 4+1\n\ @@ -40,7 +40,7 @@ v4wt_copy_user_page(void *kto, const void *kfrom) mcr p15, 0, r2, c7, c7, 0 @ flush ID cache\n\ ldmfd sp!, {r4, pc} @ 3" : - : "I" (PAGE_SIZE / 64)); + : "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64)); } void v4wt_copy_user_highpage(struct page *to, struct page *from, diff --git a/arch/arm/mm/copypage-xsc3.c b/arch/arm/mm/copypage-xsc3.c index 747ad4140fc7..f9cde0702f1e 100644 --- a/arch/arm/mm/copypage-xsc3.c +++ b/arch/arm/mm/copypage-xsc3.c @@ -34,7 +34,7 @@ xsc3_mc_copy_user_page(void *kto, const void *kfrom) { asm("\ stmfd sp!, {r4, r5, lr} \n\ - mov lr, %0 \n\ + mov lr, %2 \n\ \n\ pld [r1, #0] \n\ pld [r1, #32] \n\ @@ -67,7 +67,7 @@ xsc3_mc_copy_user_page(void *kto, const void *kfrom) \n\ ldmfd sp!, {r4, r5, pc}" : - : "I" (PAGE_SIZE / 64 - 1)); + : "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64 - 1)); } void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, -- GitLab From af0d5cb908f7f9adeb5d3d3dbef64c644bb6809c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Sat, 5 Jun 2010 22:52:21 +0200 Subject: [PATCH 777/842] hp_sdc_rtc: fix broken ioctl conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 55929332c92 "drivers: Push down BKL into various drivers" introduced a regression in hp_sdc_rtc, caused by a missing change of the .unlocked_ioctl pointer to the newly introduced function. Fixes: drivers/input/misc/hp_sdc_rtc.c:681: warning: initialization from incompatible pointer type drivers/input/misc/hp_sdc_rtc.c:665: warning: ‘hp_sdc_rtc_unlocked_ioctl’ defined but not used Reported-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> --- drivers/input/misc/hp_sdc_rtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index e00a1cc79c0a..c19066479057 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -678,7 +678,7 @@ static const struct file_operations hp_sdc_rtc_fops = { .llseek = no_llseek, .read = hp_sdc_rtc_read, .poll = hp_sdc_rtc_poll, - .unlocked_ioctl = hp_sdc_rtc_ioctl, + .unlocked_ioctl = hp_sdc_rtc_unlocked_ioctl, .open = hp_sdc_rtc_open, .fasync = hp_sdc_rtc_fasync, }; -- GitLab From b9b76dfaac6fa2c289ee8a005be637afd2da7e2f Mon Sep 17 00:00:00 2001 From: Oleg Nesterov <oleg@redhat.com> Date: Thu, 3 Jun 2010 23:34:09 +0200 Subject: [PATCH 778/842] tracing: Fix null pointer deref with SEND_SIG_FORCED BUG: unable to handle kernel NULL pointer dereference at 0000000000000006 IP: [<ffffffff8107bd37>] ftrace_raw_event_signal_generate+0x87/0x140 TP_STORE_SIGINFO() forgets about SEND_SIG_FORCED, fix. We should probably export is_si_special() and change TP_STORE_SIGINFO() to use it in the longer term. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Roland McGrath <roland@redhat.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Jason Baron <jbaron@redhat.com> Cc: Masami Hiramatsu <mhiramat@redhat.com> Cc: 2.6.33.x-2.6.34.x <stable@kernel.org> LKML-Reference: <20100603213409.GA8307@redhat.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> --- include/trace/events/signal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/trace/events/signal.h b/include/trace/events/signal.h index 814566c99d29..17df43464df0 100644 --- a/include/trace/events/signal.h +++ b/include/trace/events/signal.h @@ -10,7 +10,8 @@ #define TP_STORE_SIGINFO(__entry, info) \ do { \ - if (info == SEND_SIG_NOINFO) { \ + if (info == SEND_SIG_NOINFO || \ + info == SEND_SIG_FORCED) { \ __entry->errno = 0; \ __entry->code = SI_USER; \ } else if (info == SEND_SIG_PRIV) { \ -- GitLab From c3935e30495869dd611e1cd62253c94ebc7c6c04 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" <bfields@citi.umich.edu> Date: Fri, 4 Jun 2010 16:42:08 -0400 Subject: [PATCH 779/842] nfsd4: shut down callback queue outside state lock This reportedly causes a lockdep warning on nfsd shutdown. That looks like a false positive to me, but there's no reason why this needs the state lock anyway. Reported-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 12f7109720c2..4a2734758778 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4122,8 +4122,8 @@ nfs4_state_shutdown(void) nfs4_lock_state(); nfs4_release_reclaim(); __nfs4_state_shutdown(); - nfsd4_destroy_callback_queue(); nfs4_unlock_state(); + nfsd4_destroy_callback_queue(); } /* -- GitLab From 0b5649278e39a068aaf91399941bab1b4a4a3cc2 Mon Sep 17 00:00:00 2001 From: Dave Chinner <dchinner@redhat.com> Date: Wed, 9 Jun 2010 10:37:18 +1000 Subject: [PATCH 780/842] writeback: pay attention to wbc->nr_to_write in write_cache_pages If a filesystem writes more than one page in ->writepage, write_cache_pages fails to notice this and continues to attempt writeback when wbc->nr_to_write has gone negative - this trace was captured from XFS: wbc_writeback_start: towrt=1024 wbc_writepage: towrt=1024 wbc_writepage: towrt=0 wbc_writepage: towrt=-1 wbc_writepage: towrt=-5 wbc_writepage: towrt=-21 wbc_writepage: towrt=-85 This has adverse effects on filesystem writeback behaviour. write_cache_pages() needs to terminate after a certain number of pages are written, not after a certain number of calls to ->writepage are made. This is a regression introduced by 17bc6c30cf6bfffd816bdc53682dd46fc34a2cf4 ("vfs: Add no_nrwrite_index_update writeback control flag"), but cannot be reverted directly due to subsequent bug fixes that have gone in on top of it. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- include/linux/writeback.h | 9 --------- include/trace/events/ext4.h | 5 +---- mm/page-writeback.c | 15 +++++---------- 3 files changed, 6 insertions(+), 23 deletions(-) diff --git a/include/linux/writeback.h b/include/linux/writeback.h index f64134653a8c..d63ef8f9609f 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -56,15 +56,6 @@ struct writeback_control { unsigned for_reclaim:1; /* Invoked from the page allocator */ unsigned range_cyclic:1; /* range_start is cyclic */ unsigned more_io:1; /* more io to be dispatched */ - /* - * write_cache_pages() won't update wbc->nr_to_write and - * mapping->writeback_index if no_nrwrite_index_update - * is set. write_cache_pages() may write more than we - * requested and we want to make sure nr_to_write and - * writeback_index are updated in a consistent manner - * so we use a single control to update them - */ - unsigned no_nrwrite_index_update:1; }; /* diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index f5b1ba90e952..f3865c7b4166 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -306,7 +306,6 @@ TRACE_EVENT(ext4_da_writepages_result, __field( int, pages_written ) __field( long, pages_skipped ) __field( char, more_io ) - __field( char, no_nrwrite_index_update ) __field( pgoff_t, writeback_index ) ), @@ -317,16 +316,14 @@ TRACE_EVENT(ext4_da_writepages_result, __entry->pages_written = pages_written; __entry->pages_skipped = wbc->pages_skipped; __entry->more_io = wbc->more_io; - __entry->no_nrwrite_index_update = wbc->no_nrwrite_index_update; __entry->writeback_index = inode->i_mapping->writeback_index; ), - TP_printk("dev %s ino %lu ret %d pages_written %d pages_skipped %ld more_io %d no_nrwrite_index_update %d writeback_index %lu", + TP_printk("dev %s ino %lu ret %d pages_written %d pages_skipped %ld more_io %d writeback_index %lu", jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino, __entry->ret, __entry->pages_written, __entry->pages_skipped, __entry->more_io, - __entry->no_nrwrite_index_update, (unsigned long) __entry->writeback_index) ); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 5fa63bdf52e4..b3dbb8040ed5 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -835,7 +835,6 @@ int write_cache_pages(struct address_space *mapping, pgoff_t done_index; int cycled; int range_whole = 0; - long nr_to_write = wbc->nr_to_write; pagevec_init(&pvec, 0); if (wbc->range_cyclic) { @@ -935,11 +934,10 @@ continue_unlock: done = 1; break; } - } + } - if (nr_to_write > 0) { - nr_to_write--; - if (nr_to_write == 0 && + if (wbc->nr_to_write > 0) { + if (--wbc->nr_to_write == 0 && wbc->sync_mode == WB_SYNC_NONE) { /* * We stop writing back only if we are @@ -970,11 +968,8 @@ continue_unlock: end = writeback_index - 1; goto retry; } - if (!wbc->no_nrwrite_index_update) { - if (wbc->range_cyclic || (range_whole && nr_to_write > 0)) - mapping->writeback_index = done_index; - wbc->nr_to_write = nr_to_write; - } + if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) + mapping->writeback_index = done_index; return ret; } -- GitLab From 254c8c2dbf0e06a560a5814eb90cb628adb2de66 Mon Sep 17 00:00:00 2001 From: Dave Chinner <dchinner@redhat.com> Date: Wed, 9 Jun 2010 10:37:19 +1000 Subject: [PATCH 781/842] xfs: remove nr_to_write writeback windup. Now that the background flush code has been fixed, we shouldn't need to silently multiply the wbc->nr_to_write to get good writeback. Remove that code. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- fs/xfs/linux-2.6/xfs_aops.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index a0fa3bf0d1bb..34640d6dbdcb 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -1381,14 +1381,6 @@ xfs_vm_writepage( if (!page_has_buffers(page)) create_empty_buffers(page, 1 << inode->i_blkbits, 0); - - /* - * VM calculation for nr_to_write seems off. Bump it way - * up, this gets simple streaming writes zippy again. - * To be reviewed again after Jens' writeback changes. - */ - wbc->nr_to_write *= 4; - /* * Convert delayed allocate, unwritten or unmapped space * to real space and flush out to disk. -- GitLab From d87815cb2090e07b0b0b2d73dc9740706e92c80c Mon Sep 17 00:00:00 2001 From: Dave Chinner <dchinner@redhat.com> Date: Wed, 9 Jun 2010 10:37:20 +1000 Subject: [PATCH 782/842] writeback: limit write_cache_pages integrity scanning to current EOF sync can currently take a really long time if a concurrent writer is extending a file. The problem is that the dirty pages on the address space grow in the same direction as write_cache_pages scans, so if the writer keeps ahead of writeback, the writeback will not terminate until the writer stops adding dirty pages. For a data integrity sync, we only need to write the pages dirty at the time we start the writeback, so we can stop scanning once we get to the page that was at the end of the file at the time the scan started. This will prevent operations like copying a large file preventing sync from completing as it will not write back pages that were dirtied after the sync was started. This does not impact the existing integrity guarantees, as any dirty page (old or new) within the EOF range at the start of the scan will still be captured. This patch will not prevent sync from blocking on large writes into holes. That requires more complex intervention while this patch only addresses the common append-case of this sync holdoff. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- mm/page-writeback.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index b3dbb8040ed5..bbd396ac9546 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -851,7 +851,22 @@ int write_cache_pages(struct address_space *mapping, if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) range_whole = 1; cycled = 1; /* ignore range_cyclic tests */ + + /* + * If this is a data integrity sync, cap the writeback to the + * current end of file. Any extension to the file that occurs + * after this is a new write and we don't need to write those + * pages out to fulfil our data integrity requirements. If we + * try to write them out, we can get stuck in this scan until + * the concurrent writer stops adding dirty pages and extending + * EOF. + */ + if (wbc->sync_mode == WB_SYNC_ALL && + wbc->range_end == LLONG_MAX) { + end = i_size_read(mapping->host) >> PAGE_CACHE_SHIFT; + } } + retry: done_index = index; while (!done && (index <= end)) { -- GitLab From 8d86dc6a5bcd0f1d5b9364d43843f1bb4b15f57a Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Tue, 8 Jun 2010 20:16:28 -0700 Subject: [PATCH 783/842] Revert "drm/i915: Don't enable pipe/plane/VCO early (wait for DPMS on)." This reverts commit cfecde435dda78248d6fcdc424bed68d5db6be0b, since it seems to cause some systems to not come up with any video output at all (or video that only comes on when X starts up). Fixes bugzilla: http://bugzilla.kernel.org/show_bug.cgi?id=16163 Reported-and-tested-by: David John <davidjon@xenontk.org> Tested-by: Nick Bowler <nbowler@elliptictech.com> Acked-by: Carl Worth <cworth@cworth.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2861da3aaf7e..cc8131ff319f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3653,6 +3653,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, pipeconf &= ~PIPEACONF_DOUBLE_WIDE; } + dspcntr |= DISPLAY_PLANE_ENABLE; + pipeconf |= PIPEACONF_ENABLE; + dpll |= DPLL_VCO_ENABLE; + + /* Disable the panel fitter if it was on our pipe */ if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe) I915_WRITE(PFIT_CONTROL, 0); -- GitLab From ffe57d02b23ebc5422cf81566b3ce566d68a3e22 Mon Sep 17 00:00:00 2001 From: Michal Simek <monstr@monstr.eu> Date: Mon, 7 Jun 2010 15:17:55 +0200 Subject: [PATCH 784/842] microblaze: Define ARCH_SLAB_MINALIGN to fix slab crash The commit "mm: Move ARCH_SLAB_MINALIGN and ARCH_KMALLOC_MINALIGN to <linux/slab_def.h>" 1f0ce8b3dd667dca7 which moved the ARCH_SLAB_MINALIGN default into the global header broke FLAT for Microblaze. Error message: slab error in verify_redzone_free(): cache `idr_layer_cache': memory outside object was overwritten Signed-off-by: Michal Simek <monstr@monstr.eu> --- arch/microblaze/include/asm/page.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h index de493f86d28f..464ff32bee3d 100644 --- a/arch/microblaze/include/asm/page.h +++ b/arch/microblaze/include/asm/page.h @@ -34,6 +34,8 @@ /* MS be sure that SLAB allocates aligned objects */ #define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES +#define ARCH_SLAB_MINALIGN L1_CACHE_BYTES + #define PAGE_UP(addr) (((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1))) #define PAGE_DOWN(addr) ((addr)&(~((PAGE_SIZE)-1))) -- GitLab From fcdcddbcbbd39a3363bd48414bfe44553b6d698a Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Date: Tue, 8 Jun 2010 20:03:15 +0900 Subject: [PATCH 785/842] microblaze: Fix sg_dma_len() regression The commit "asm-generic: add NEED_SG_DMA_LENGTH to define sg_dma_len()" 18e98307de0d746cb0845ebf66535ce2184c25a2 broke microblaze compilation. dma_direct_map_sg() sets sg->dma_length, however microblaze doesn't set NEED_SG_DMA_LENGTH so scatterlist strcutres doesn't include dma_length. sg->dma_length is always equal to sg->length on microblaze. So we don't need to set set dma_length, that is, microblaze can simply use sg->length. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Michal Simek <monstr@monstr.eu> --- arch/microblaze/kernel/dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c index 9dcd90b5df55..79c74659f204 100644 --- a/arch/microblaze/kernel/dma.c +++ b/arch/microblaze/kernel/dma.c @@ -90,7 +90,6 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, /* FIXME this part of code is untested */ for_each_sg(sgl, sg, nents, i) { sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev); - sg->dma_length = sg->length; __dma_sync_page(page_to_phys(sg_page(sg)), sg->offset, sg->length, direction); } -- GitLab From a06cdb5676272a12056820aeb49a1416ad2d0c6f Mon Sep 17 00:00:00 2001 From: Jean Delvare <khali@linux-fr.org> Date: Tue, 18 May 2010 09:34:12 +0200 Subject: [PATCH 786/842] KVM: powerpc: fix init/exit annotation kvmppc_e500_exit() is a module_exit function, so it should be tagged with __exit, not __init. The incorrect annotation was added by commit 2986b8c72c272ea58edd37903b042c6da985627d. Signed-off-by: Jean Delvare <khali@linux-fr.org> Cc: stable@kernel.org Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com> --- arch/powerpc/kvm/e500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c index bc2b4004eb26..e8a00b0c4449 100644 --- a/arch/powerpc/kvm/e500.c +++ b/arch/powerpc/kvm/e500.c @@ -164,7 +164,7 @@ static int __init kvmppc_e500_init(void) return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); } -static void __init kvmppc_e500_exit(void) +static void __exit kvmppc_e500_exit(void) { kvmppc_booke_exit(); } -- GitLab From fe5913e4e1700cbfc337f4b1da9ddb26f6a55586 Mon Sep 17 00:00:00 2001 From: Joerg Roedel <joerg.roedel@amd.com> Date: Mon, 17 May 2010 14:43:34 +0200 Subject: [PATCH 787/842] KVM: SVM: Handle MCEs early in the vmexit process This patch moves handling of the MC vmexits to an earlier point in the vmexit. The handle_exit function is too late because the vcpu might alreadry have changed its physical cpu. Cc: stable@kernel.org Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Signed-off-by: Avi Kivity <avi@redhat.com> --- arch/x86/kvm/svm.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 96dc232bfc56..5e1ed033cd7e 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1410,7 +1410,7 @@ static int nm_interception(struct vcpu_svm *svm) return 1; } -static int mc_interception(struct vcpu_svm *svm) +static void svm_handle_mce(struct vcpu_svm *svm) { /* * On an #MC intercept the MCE handler is not called automatically in @@ -1420,6 +1420,11 @@ static int mc_interception(struct vcpu_svm *svm) "int $0x12\n"); /* not sure if we ever come back to this point */ + return; +} + +static int mc_interception(struct vcpu_svm *svm) +{ return 1; } @@ -3088,6 +3093,14 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) vcpu->arch.regs_avail &= ~(1 << VCPU_EXREG_PDPTR); vcpu->arch.regs_dirty &= ~(1 << VCPU_EXREG_PDPTR); } + + /* + * We need to handle MC intercepts here before the vcpu has a chance to + * change the physical cpu + */ + if (unlikely(svm->vmcb->control.exit_code == + SVM_EXIT_EXCP_BASE + MC_VECTOR)) + svm_handle_mce(svm); } #undef R -- GitLab From 67ec66077799f2fef84b21a643912b179c422281 Mon Sep 17 00:00:00 2001 From: Joerg Roedel <joerg.roedel@amd.com> Date: Mon, 17 May 2010 14:43:35 +0200 Subject: [PATCH 788/842] KVM: SVM: Implement workaround for Erratum 383 This patch implements a workaround for AMD erratum 383 into KVM. Without this erratum fix it is possible for a guest to kill the host machine. This patch implements the suggested workaround for hypervisors which will be published by the next revision guide update. [jan: fix overflow warning on i386] [xiao: fix unused variable warning] Cc: stable@kernel.org Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Signed-off-by: Avi Kivity <avi@redhat.com> --- arch/x86/include/asm/msr-index.h | 1 + arch/x86/kvm/svm.c | 81 ++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index b49d8ca228f6..8c7ae4318629 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -110,6 +110,7 @@ #define MSR_AMD64_PATCH_LOADER 0xc0010020 #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 #define MSR_AMD64_OSVW_STATUS 0xc0010141 +#define MSR_AMD64_DC_CFG 0xc0011022 #define MSR_AMD64_IBSFETCHCTL 0xc0011030 #define MSR_AMD64_IBSFETCHLINAD 0xc0011031 #define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 5e1ed033cd7e..ce438e0fdd26 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -28,6 +28,7 @@ #include <linux/ftrace_event.h> #include <linux/slab.h> +#include <asm/tlbflush.h> #include <asm/desc.h> #include <asm/virtext.h> @@ -56,6 +57,8 @@ MODULE_LICENSE("GPL"); #define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) +static bool erratum_383_found __read_mostly; + static const u32 host_save_user_msrs[] = { #ifdef CONFIG_X86_64 MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE, @@ -374,6 +377,31 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, svm->vmcb->control.event_inj_err = error_code; } +static void svm_init_erratum_383(void) +{ + u32 low, high; + int err; + u64 val; + + /* Only Fam10h is affected */ + if (boot_cpu_data.x86 != 0x10) + return; + + /* Use _safe variants to not break nested virtualization */ + val = native_read_msr_safe(MSR_AMD64_DC_CFG, &err); + if (err) + return; + + val |= (1ULL << 47); + + low = lower_32_bits(val); + high = upper_32_bits(val); + + native_write_msr_safe(MSR_AMD64_DC_CFG, low, high); + + erratum_383_found = true; +} + static int has_svm(void) { const char *msg; @@ -429,6 +457,8 @@ static int svm_hardware_enable(void *garbage) wrmsrl(MSR_VM_HSAVE_PA, page_to_pfn(sd->save_area) << PAGE_SHIFT); + svm_init_erratum_383(); + return 0; } @@ -1410,8 +1440,59 @@ static int nm_interception(struct vcpu_svm *svm) return 1; } +static bool is_erratum_383(void) +{ + int err, i; + u64 value; + + if (!erratum_383_found) + return false; + + value = native_read_msr_safe(MSR_IA32_MC0_STATUS, &err); + if (err) + return false; + + /* Bit 62 may or may not be set for this mce */ + value &= ~(1ULL << 62); + + if (value != 0xb600000000010015ULL) + return false; + + /* Clear MCi_STATUS registers */ + for (i = 0; i < 6; ++i) + native_write_msr_safe(MSR_IA32_MCx_STATUS(i), 0, 0); + + value = native_read_msr_safe(MSR_IA32_MCG_STATUS, &err); + if (!err) { + u32 low, high; + + value &= ~(1ULL << 2); + low = lower_32_bits(value); + high = upper_32_bits(value); + + native_write_msr_safe(MSR_IA32_MCG_STATUS, low, high); + } + + /* Flush tlb to evict multi-match entries */ + __flush_tlb_all(); + + return true; +} + static void svm_handle_mce(struct vcpu_svm *svm) { + if (is_erratum_383()) { + /* + * Erratum 383 triggered. Guest state is corrupt so kill the + * guest. + */ + pr_err("KVM: Guest triggered AMD Erratum 383\n"); + + set_bit(KVM_REQ_TRIPLE_FAULT, &svm->vcpu.requests); + + return; + } + /* * On an #MC intercept the MCE handler is not called automatically in * the host. So do it by hand here. -- GitLab From 3be2264be3c00865116f997dc53ebcc90fe7fc4b Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti <mtosatti@redhat.com> Date: Fri, 28 May 2010 09:44:59 -0300 Subject: [PATCH 789/842] KVM: MMU: invalidate and flush on spte small->large page size change Always invalidate spte and flush TLBs when changing page size, to make sure different sized translations for the same address are never cached in a CPU's TLB. Currently the only case where this occurs is when a non-leaf spte pointer is overwritten by a leaf, large spte entry. This can happen after dirty logging is disabled on a memslot, for example. Noticed by Andrea. KVM-Stable-Tag Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com> --- arch/x86/kvm/mmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 81563e76e28f..6fbcb48d5a9b 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1870,6 +1870,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, child = page_header(pte & PT64_BASE_ADDR_MASK); mmu_page_remove_parent_pte(child, sptep); + __set_spte(sptep, shadow_trap_nonpresent_pte); + kvm_flush_remote_tlbs(vcpu->kvm); } else if (pfn != spte_to_pfn(*sptep)) { pgprintk("hfn old %lx new %lx\n", spte_to_pfn(*sptep), pfn); -- GitLab From 69325a122580d3a7b26589e8efdd6663001c3297 Mon Sep 17 00:00:00 2001 From: Avi Kivity <avi@redhat.com> Date: Thu, 27 May 2010 14:35:58 +0300 Subject: [PATCH 790/842] KVM: MMU: Remove user access when allowing kernel access to gpte.w=0 page If cr0.wp=0, we have to allow the guest kernel access to a page with pte.w=0. We do that by setting spte.w=1, since the host cr0.wp must remain set so the host can write protect pages. Once we allow write access, we must remove user access otherwise we mistakenly allow the user to write the page. Reviewed-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Signed-off-by: Avi Kivity <avi@redhat.com> --- arch/x86/kvm/mmu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 6fbcb48d5a9b..a6f695d76928 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1815,6 +1815,9 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, spte |= PT_WRITABLE_MASK; + if (!tdp_enabled && !(pte_access & ACC_WRITE_MASK)) + spte &= ~PT_USER_MASK; + /* * Optimization: for pte sync, if spte was writable the hash * lookup is unnecessary (and expensive). Write protection -- GitLab From 05b782ab951a896d7da41775999821f692dc9e01 Mon Sep 17 00:00:00 2001 From: Jan Kiszka <jan.kiszka@siemens.com> Date: Wed, 26 May 2010 21:36:33 +0200 Subject: [PATCH 791/842] KVM: Fix order passed to iommu_unmap This is obviously a left-over from the the old interface taking the size. Apparently a mostly harmless issue with the current iommu_unmap implementation. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Acked-by: Joerg Roedel <joerg.roedel@amd.com> Signed-off-by: Avi Kivity <avi@redhat.com> --- virt/kvm/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index d2f06be63354..96048ee9e39e 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -271,7 +271,7 @@ static void kvm_iommu_put_pages(struct kvm *kvm, pfn = phys >> PAGE_SHIFT; /* Unmap address from IO address space */ - order = iommu_unmap(domain, gfn_to_gpa(gfn), PAGE_SIZE); + order = iommu_unmap(domain, gfn_to_gpa(gfn), 0); unmap_pages = 1ULL << order; /* Unpin all pages we just unmapped to not leak any memory */ -- GitLab From 3499f4d0d1159a21245d6071f8af6a71b86a78bc Mon Sep 17 00:00:00 2001 From: Julia Lawall <julia@diku.dk> Date: Wed, 26 May 2010 17:57:05 +0200 Subject: [PATCH 792/842] KVM: ia64: Add missing spin_unlock in kvm_arch_hardware_enable() Add a spin_unlock missing on the error path. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @@ expression E1; @@ * spin_lock(E1,...); <+... when != E1 if (...) { ... when != E1 * return ...; } ...+> * spin_unlock(E1,...); // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Signed-off-by: Avi Kivity <avi@redhat.com> --- arch/ia64/kvm/kvm-ia64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index d5f4e9161201..21b701374f72 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c @@ -144,6 +144,7 @@ int kvm_arch_hardware_enable(void *garbage) VP_INIT_ENV : VP_INIT_ENV_INITALIZE, __pa(kvm_vm_buffer), KVM_VM_BUFFER_BASE, &tmp_base); if (status != 0) { + spin_unlock(&vp_lock); printk(KERN_WARNING"kvm: Failed to Enable VT Support!!!!\n"); return -EINVAL; } -- GitLab From 79907d89c397b8bc2e05b347ec94e928ea919d33 Mon Sep 17 00:00:00 2001 From: Alan Cox <alan@linux.intel.com> Date: Wed, 9 Jun 2010 09:39:49 +0100 Subject: [PATCH 793/842] misc: Fix allocation 'borrowed' by vhost_net 10, 233 is allocated officially to /dev/kmview which is shipping in Ubuntu and Debian distributions. vhost_net seem to have borrowed it without making a proper request and this causes regressions in the other distributions. vhost_net can use a dynamic minor so use that instead. Also update the file with a comment to try and avoid future misunderstandings. cc: stable@kernel.org Signed-off-by: Alan Cox <device@lanana.org> [ We should have caught this before 2.6.34 got released. - Linus ] Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- drivers/vhost/net.c | 2 +- include/linux/miscdevice.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 0f41c9195e9b..df5b6b971f26 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -637,7 +637,7 @@ const static struct file_operations vhost_net_fops = { }; static struct miscdevice vhost_net_misc = { - VHOST_NET_MINOR, + MISC_DYNAMIC_MINOR, "vhost-net", &vhost_net_fops, }; diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index b631c46cffd9..f6c9b7dcb9fd 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -3,6 +3,12 @@ #include <linux/module.h> #include <linux/major.h> +/* + * These allocations are managed by device@lanana.org. If you use an + * entry that is not in assigned your entry may well be moved and + * reassigned, or set dynamic if a fixed value is not justified. + */ + #define PSMOUSE_MINOR 1 #define MS_BUSMOUSE_MINOR 2 #define ATIXL_BUSMOUSE_MINOR 3 @@ -30,7 +36,6 @@ #define HPET_MINOR 228 #define FUSE_MINOR 229 #define KVM_MINOR 232 -#define VHOST_NET_MINOR 233 #define BTRFS_MINOR 234 #define AUTOFS_MINOR 235 #define MISC_DYNAMIC_MINOR 255 -- GitLab From f3d56144c86beb25c7d206efa66d6efba908371c Mon Sep 17 00:00:00 2001 From: Daniel Walker <dwalker@codeaurora.org> Date: Mon, 24 May 2010 10:15:00 -0700 Subject: [PATCH 794/842] mmc: msm: fix compile error on MSM7x30 MSM7x30 isn't supported in this driver yet. If ones tried to compile it in with MSM7x30 configure you get, linux-2.6/drivers/mmc/host/msm_sdcc.c: In function 'msmsdcc_fifo_addr': linux-2.6/drivers/mmc/host/msm_sdcc.c:165: error: 'MSM_SDC1_PHYS' undeclared (first use in this function) linux-2.6/drivers/mmc/host/msm_sdcc.c:165: error: (Each undeclared identifier is reported only once linux-2.6/drivers/mmc/host/msm_sdcc.c:165: error: for each function it appears in.) linux-2.6/drivers/mmc/host/msm_sdcc.c:167: error: 'MSM_SDC2_PHYS' undeclared (first use in this function) linux-2.6/drivers/mmc/host/msm_sdcc.c:169: error: 'MSM_SDC3_PHYS' undeclared (first use in this function) linux-2.6/drivers/mmc/host/msm_sdcc.c:171: error: 'MSM_SDC4_PHYS' undeclared (first use in this function) So we add a Kconfig check to prevent this. Signed-off-by: Daniel Walker <dwalker@codeaurora.org> --- drivers/mmc/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index e171e77f6129..f06d06e7fdfa 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -249,7 +249,7 @@ config MMC_IMX config MMC_MSM7X00A tristate "Qualcomm MSM 7X00A SDCC Controller Support" - depends on MMC && ARCH_MSM + depends on MMC && ARCH_MSM && !ARCH_MSM7X30 help This provides support for the SD/MMC cell found in the MSM 7X00A controllers from Qualcomm. -- GitLab From a7f5378e2449fc8ae3f92739a6cc2239748ef86a Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> Date: Wed, 9 Jun 2010 19:52:22 +0100 Subject: [PATCH 795/842] FRV: Reinstate null behaviour for the GDB remote protocol 'p' command Reinstate the null behaviour that the in-kernel gdbstub had for the GDB remote protocol 'p' command (retrieve a single register value) prior to commit 7ca8b9c0dafd ("frv: extend gdbstub to support more features of gdb"). Before that, the 'p' command just returned an empty reply, which causes gdb to then go and use the 'g' command. However, since that commit, the 'p' command returns an error string, which causes gdb to abort its connection to the target. Not all gdb versions are affected, some use try 'g' first, and if that works, don't bother with 'p', and so don't see the error. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> --- arch/frv/kernel/gdb-stub.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/frv/kernel/gdb-stub.c b/arch/frv/kernel/gdb-stub.c index 84d103c33c9c..a4dba6b20bd0 100644 --- a/arch/frv/kernel/gdb-stub.c +++ b/arch/frv/kernel/gdb-stub.c @@ -1789,6 +1789,12 @@ void gdbstub(int sigval) flush_cache = 1; break; + /* pNN: Read value of reg N and return it */ + case 'p': + /* return no value, indicating that we don't support + * this command and that gdb should use 'g' instead */ + break; + /* PNN,=RRRRRRRR: Write value R to reg N return OK */ case 'P': ptr = &input_buffer[1]; -- GitLab From 08c801f8d45387a1b46066aad1789a9bb9c4b645 Mon Sep 17 00:00:00 2001 From: Tim Gardner <tim.gardner@canonical.com> Date: Tue, 8 Jun 2010 17:51:27 -0600 Subject: [PATCH 796/842] net: Print num_rx_queues imbalance warning only when there are allocated queues BugLink: http://bugs.launchpad.net/bugs/591416 There are a number of network drivers (bridge, bonding, etc) that are not yet receive multi-queue enabled and use alloc_netdev(), so don't print a num_rx_queues imbalance warning in that case. Also, only print the warning once for those drivers that _are_ multi-queue enabled. Signed-off-by: Tim Gardner <tim.gardner@canonical.com> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> --- net/core/dev.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index d03470f5260a..14a85682af38 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2253,11 +2253,9 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, if (skb_rx_queue_recorded(skb)) { u16 index = skb_get_rx_queue(skb); if (unlikely(index >= dev->num_rx_queues)) { - if (net_ratelimit()) { - pr_warning("%s received packet on queue " - "%u, but number of RX queues is %u\n", - dev->name, index, dev->num_rx_queues); - } + WARN_ONCE(dev->num_rx_queues > 1, "%s received packet " + "on queue %u, but number of RX queues is %u\n", + dev->name, index, dev->num_rx_queues); goto done; } rxqueue = dev->_rx + index; -- GitLab From 2da30e703c5a56e27249fa8b8607708123fa52f5 Mon Sep 17 00:00:00 2001 From: Michal Marek <mmarek@suse.cz> Date: Mon, 7 Jun 2010 22:22:12 +0200 Subject: [PATCH 797/842] kbuild: Generate modules.builtin in make modules Generating the file in make modules_install was broken as well, because it didn't work in a readonly filesystem and otherwise it generated a root-owned file which is not wanted. Reported-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Michal Marek <mmarek@suse.cz> --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 654c31aaec64..993d1f335925 100644 --- a/Makefile +++ b/Makefile @@ -1095,7 +1095,7 @@ all: modules # using awk while concatenating to the final file. PHONY += modules -modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) +modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order @$(kecho) ' Building modules, stage 2.'; $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost @@ -1117,7 +1117,7 @@ PHONY += modules_install modules_install: _modinst_ _modinst_post PHONY += _modinst_ -_modinst_: modules.builtin +_modinst_: @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \ echo "Warning: you may need to install module-init-tools"; \ echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\ -- GitLab From e13647c158307f0e7ff5fc5bec34731f28917595 Mon Sep 17 00:00:00 2001 From: Richard Cochran <richardcochran@gmail.com> Date: Mon, 7 Jun 2010 05:39:32 +0000 Subject: [PATCH 798/842] phylib: Add support for the LXT973 phy. This patch implements a work around for Erratum 5, "3.3 V Fiber Speed Selection." If the hardware wiring does not respect this erratum, then fiber optic mode will not work properly. Signed-off-by: Richard Cochran <richard.cochran@omicron.at> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/phy/lxt.c | 51 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index 8ee929b796d8..dbd003453737 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -53,6 +53,9 @@ #define MII_LXT971_ISR 19 /* Interrupt Status Register */ +/* register definitions for the 973 */ +#define MII_LXT973_PCR 16 /* Port Configuration Register */ +#define PCR_FIBER_SELECT 1 MODULE_DESCRIPTION("Intel LXT PHY driver"); MODULE_AUTHOR("Andy Fleming"); @@ -119,6 +122,33 @@ static int lxt971_config_intr(struct phy_device *phydev) return err; } +static int lxt973_probe(struct phy_device *phydev) +{ + int val = phy_read(phydev, MII_LXT973_PCR); + + if (val & PCR_FIBER_SELECT) { + /* + * If fiber is selected, then the only correct setting + * is 100Mbps, full duplex, and auto negotiation off. + */ + val = phy_read(phydev, MII_BMCR); + val |= (BMCR_SPEED100 | BMCR_FULLDPLX); + val &= ~BMCR_ANENABLE; + phy_write(phydev, MII_BMCR, val); + /* Remember that the port is in fiber mode. */ + phydev->priv = lxt973_probe; + } else { + phydev->priv = NULL; + } + return 0; +} + +static int lxt973_config_aneg(struct phy_device *phydev) +{ + /* Do nothing if port is in fiber mode. */ + return phydev->priv ? 0 : genphy_config_aneg(phydev); +} + static struct phy_driver lxt970_driver = { .phy_id = 0x78100000, .name = "LXT970", @@ -146,6 +176,18 @@ static struct phy_driver lxt971_driver = { .driver = { .owner = THIS_MODULE,}, }; +static struct phy_driver lxt973_driver = { + .phy_id = 0x00137a10, + .name = "LXT973", + .phy_id_mask = 0xfffffff0, + .features = PHY_BASIC_FEATURES, + .flags = 0, + .probe = lxt973_probe, + .config_aneg = lxt973_config_aneg, + .read_status = genphy_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + static int __init lxt_init(void) { int ret; @@ -157,9 +199,15 @@ static int __init lxt_init(void) ret = phy_driver_register(&lxt971_driver); if (ret) goto err2; + + ret = phy_driver_register(&lxt973_driver); + if (ret) + goto err3; return 0; - err2: + err3: + phy_driver_unregister(&lxt971_driver); + err2: phy_driver_unregister(&lxt970_driver); err1: return ret; @@ -169,6 +217,7 @@ static void __exit lxt_exit(void) { phy_driver_unregister(&lxt970_driver); phy_driver_unregister(&lxt971_driver); + phy_driver_unregister(&lxt973_driver); } module_init(lxt_init); -- GitLab From aea34e7ae7a40bc72f9f11b5658160dfb4b90c48 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Mon, 7 Jun 2010 04:51:58 +0000 Subject: [PATCH 799/842] caif: fix a couple range checks The extra ! character means that these conditions are always false. Signed-off-by: Dan Carpenter <error27@gmail.com> Acked-by: Sjur Braendeland <sjur.brandeland@stericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/caif/cfrfml.c | 2 +- net/caif/cfveil.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c index cd2830fec935..fd27b172fb5d 100644 --- a/net/caif/cfrfml.c +++ b/net/caif/cfrfml.c @@ -83,7 +83,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) if (!cfsrvl_ready(service, &ret)) return ret; - if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) { + if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) { pr_err("CAIF: %s():Packet too large - size=%d\n", __func__, cfpkt_getlen(pkt)); return -EOVERFLOW; diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c index 0fd827f49491..e04f7d964e83 100644 --- a/net/caif/cfveil.c +++ b/net/caif/cfveil.c @@ -84,7 +84,7 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt) return ret; caif_assert(layr->dn != NULL); caif_assert(layr->dn->transmit != NULL); - if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) { + if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) { pr_warning("CAIF: %s(): Packet too large - size=%d\n", __func__, cfpkt_getlen(pkt)); return -EOVERFLOW; -- GitLab From 619baba195d92ec39379e24c151f4a640898d140 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov <avorontsov@mvista.com> Date: Wed, 9 Jun 2010 16:27:08 -0700 Subject: [PATCH 800/842] gianfar: Revive the driver for eTSEC devices (disable timestamping) Since commit cc772ab7cdcaa24d1fae332d92a1602788644f7a ("gianfar: Add hardware RX timestamping support"), the driver no longer works on at least MPC8313ERDB and MPC8568EMDS boards (and possibly much more boards as well). That's how MPC8313 Reference Manual describes RCTRL_TS_ENABLE bit: Timestamp incoming packets as padding bytes. PAL field is set to 8 if the PAL field is programmed to less than 8. Must be set to zero if TMR_CTRL[TE]=0. I see that the commit above sets this bit, but it doesn't handle TMR_CTRL. Manfred probably had this bit set by the firmware for his boards. But obviously this isn't true for all boards in the wild. Also, I recall that Freescale BSPs were explicitly disabling the timestamping because of a performance drop. For now, the best way to deal with this is just disable the timestamping, and later we can discuss proper device tree bindings and implement enabling this feature via some property. Signed-off-by: Anton Vorontsov <avorontsov@mvista.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/gianfar.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 1830f3199cb5..46c69cd06553 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -747,8 +747,7 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev) FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | - FSL_GIANFAR_DEV_HAS_EXTENDED_HASH | - FSL_GIANFAR_DEV_HAS_TIMER; + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; ctype = of_get_property(np, "phy-connection-type", NULL); -- GitLab From 81a95f049962ec20a9aed888e676208b206f0f2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> Date: Wed, 9 Jun 2010 17:31:48 -0700 Subject: [PATCH 801/842] r8169: fix mdio_read and update mdio_write according to hw specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Realtek confirmed that a 20us delay is needed after mdio_read and mdio_write operations. Reduce the delay in mdio_write, and add it to mdio_read too. Also add a comment that the 20us is from hw specs. Signed-off-by: Timo Teräs <timo.teras@iki.fi> Acked-by: Francois Romieu <romieu@fr.zoreil.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/r8169.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 03a8318d90a2..96b6cfbf0a3a 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -560,10 +560,10 @@ static void mdio_write(void __iomem *ioaddr, int reg_addr, int value) udelay(25); } /* - * Some configurations require a small delay even after the write - * completed indication or the next write might fail. + * According to hardware specs a 20us delay is required after write + * complete indication, but before sending next command. */ - udelay(25); + udelay(20); } static int mdio_read(void __iomem *ioaddr, int reg_addr) @@ -583,6 +583,12 @@ static int mdio_read(void __iomem *ioaddr, int reg_addr) } udelay(25); } + /* + * According to hardware specs a 20us delay is required after read + * complete indication, but before sending next command. + */ + udelay(20); + return value; } -- GitLab From 00d9d6a185de89edc0649ca4ead58f0283dfcbac Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Mon, 7 Jun 2010 22:24:44 +0000 Subject: [PATCH 802/842] ipv6: fix ICMP6_MIB_OUTERRORS In commit 1f8438a85366 (icmp: Account for ICMP out errors), I did a typo on IPV6 side, using ICMP6_MIB_OUTMSGS instead of ICMP6_MIB_OUTERRORS Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv6/icmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index ce7992982557..03e62f94ff8e 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -483,7 +483,7 @@ route_done: np->tclass, NULL, &fl, (struct rt6_info*)dst, MSG_DONTWAIT, np->dontfrag); if (err) { - ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS); + ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS); ip6_flush_pending_frames(sk); goto out_put; } @@ -565,7 +565,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) np->dontfrag); if (err) { - ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS); + ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS); ip6_flush_pending_frames(sk); goto out_put; } -- GitLab From 607b30fcf20c6e5339591692db6ffa0b15e041a0 Mon Sep 17 00:00:00 2001 From: Michal Marek <mmarek@suse.cz> Date: Thu, 10 Jun 2010 12:23:08 +0200 Subject: [PATCH 803/842] kbuild: Create output directory in Makefile.modbuiltin Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Michal Marek <mmarek@suse.cz> --- scripts/Makefile.modbuiltin | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/Makefile.modbuiltin b/scripts/Makefile.modbuiltin index 102a276f6eea..1adb974e6950 100644 --- a/scripts/Makefile.modbuiltin +++ b/scripts/Makefile.modbuiltin @@ -14,6 +14,11 @@ __modbuiltin: include scripts/Kbuild.include +ifneq ($(KBUILD_SRC),) +# Create output directory if not already present +_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj)) +endif + # The filename Kbuild has precedence over Makefile kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) -- GitLab From cf3425707ed9ce0d5ebaba20bc3d22dd39e52f2f Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Wed, 26 May 2010 01:50:21 +1000 Subject: [PATCH 804/842] block: bd_start_claiming fix module refcount bd_start_claiming has an unbalanced module_put introduced in 6b4517a79. Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- fs/block_dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/block_dev.c b/fs/block_dev.c index 7346c96308a5..204a7632c511 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -734,6 +734,7 @@ static struct block_device *bd_start_claiming(struct block_device *bdev, return ERR_PTR(-ENXIO); whole = bdget_disk(disk, 0); + module_put(disk->fops->owner); put_disk(disk); if (!whole) return ERR_PTR(-ENOMEM); -- GitLab From b0018361c3f934858592cbbb5e1a4f318c2a70ed Mon Sep 17 00:00:00 2001 From: Nick Piggin <npiggin@suse.de> Date: Wed, 26 May 2010 01:51:19 +1000 Subject: [PATCH 805/842] block: bd_start_claiming cleanup I don't like the subtle multi-context code in bd_claim (ie. detects where it has been called based on bd_claiming). It seems clearer to just require a new function to finish a 2-part claim. Also improve commentary in bd_start_claiming as to how it should be used. Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- fs/block_dev.c | 72 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/fs/block_dev.c b/fs/block_dev.c index 204a7632c511..a1642ef60197 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -706,8 +706,13 @@ retry: * @bdev is about to be opened exclusively. Check @bdev can be opened * exclusively and mark that an exclusive open is in progress. Each * successful call to this function must be matched with a call to - * either bd_claim() or bd_abort_claiming(). If this function - * succeeds, the matching bd_claim() is guaranteed to succeed. + * either bd_finish_claiming() or bd_abort_claiming() (which do not + * fail). + * + * This function is used to gain exclusive access to the block device + * without actually causing other exclusive open attempts to fail. It + * should be used when the open sequence itself requires exclusive + * access but may subsequently fail. * * CONTEXT: * Might sleep. @@ -783,15 +788,47 @@ static void bd_abort_claiming(struct block_device *whole, void *holder) __bd_abort_claiming(whole, holder); /* releases bdev_lock */ } +/* increment holders when we have a legitimate claim. requires bdev_lock */ +static void __bd_claim(struct block_device *bdev, struct block_device *whole, + void *holder) +{ + /* note that for a whole device bd_holders + * will be incremented twice, and bd_holder will + * be set to bd_claim before being set to holder + */ + whole->bd_holders++; + whole->bd_holder = bd_claim; + bdev->bd_holders++; + bdev->bd_holder = holder; +} + +/** + * bd_finish_claiming - finish claiming a block device + * @bdev: block device of interest (passed to bd_start_claiming()) + * @whole: whole block device returned by bd_start_claiming() + * @holder: holder trying to claim @bdev + * + * Finish a claiming block started by bd_start_claiming(). + * + * CONTEXT: + * Grabs and releases bdev_lock. + */ +static void bd_finish_claiming(struct block_device *bdev, + struct block_device *whole, void *holder) +{ + spin_lock(&bdev_lock); + BUG_ON(whole->bd_claiming != holder); + BUG_ON(!bd_may_claim(bdev, whole, holder)); + __bd_claim(bdev, whole, holder); + __bd_abort_claiming(whole, holder); /* not actually an abort */ +} + /** * bd_claim - claim a block device * @bdev: block device to claim * @holder: holder trying to claim @bdev * - * Try to claim @bdev which must have been opened successfully. This - * function may be called with or without preceding - * blk_start_claiming(). In the former case, this function is always - * successful and terminates the claiming block. + * Try to claim @bdev which must have been opened successfully. * * CONTEXT: * Might sleep. @@ -807,23 +844,10 @@ int bd_claim(struct block_device *bdev, void *holder) might_sleep(); spin_lock(&bdev_lock); - res = bd_prepare_to_claim(bdev, whole, holder); - if (res == 0) { - /* note that for a whole device bd_holders - * will be incremented twice, and bd_holder will - * be set to bd_claim before being set to holder - */ - whole->bd_holders++; - whole->bd_holder = bd_claim; - bdev->bd_holders++; - bdev->bd_holder = holder; - } - - if (whole->bd_claiming) - __bd_abort_claiming(whole, holder); /* releases bdev_lock */ - else - spin_unlock(&bdev_lock); + if (res == 0) + __bd_claim(bdev, whole, holder); + spin_unlock(&bdev_lock); return res; } @@ -1477,7 +1501,7 @@ static int blkdev_open(struct inode * inode, struct file * filp) if (whole) { if (res == 0) - BUG_ON(bd_claim(bdev, filp) != 0); + bd_finish_claiming(bdev, whole, filp); else bd_abort_claiming(whole, filp); } @@ -1713,7 +1737,7 @@ struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *h if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) goto out_blkdev_put; - BUG_ON(bd_claim(bdev, holder) != 0); + bd_finish_claiming(bdev, whole, holder); return bdev; out_blkdev_put: -- GitLab From 3e6c05052c262ebe7fdd85e75e9d4f956cdd8d82 Mon Sep 17 00:00:00 2001 From: Jens Axboe <jaxboe@fusionio.com> Date: Mon, 7 Jun 2010 20:17:38 +0200 Subject: [PATCH 806/842] block: remove duplicate BUG_ON() in bd_finish_claiming() We do the same BUG_ON() just a line later when calling into __bd_abort_claiming(). Reported-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- fs/block_dev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/block_dev.c b/fs/block_dev.c index a1642ef60197..99d6af811747 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -817,7 +817,6 @@ static void bd_finish_claiming(struct block_device *bdev, struct block_device *whole, void *holder) { spin_lock(&bdev_lock); - BUG_ON(whole->bd_claiming != holder); BUG_ON(!bd_may_claim(bdev, whole, holder)); __bd_claim(bdev, whole, holder); __bd_abort_claiming(whole, holder); /* not actually an abort */ -- GitLab From 1d862f41222b7f385bada9f85a67ca5592ffd33e Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <mszeredi@suse.cz> Date: Tue, 8 Jun 2010 16:28:45 +0200 Subject: [PATCH 807/842] pipe: fix pipe buffer resizing pipe_set_size() needs to copy pipe bufs from the old circular buffer to the new. The current code gets this wrong in multiple ways, resulting in oops. Test program is available here: http://www.kernel.org/pub/linux/kernel/people/mszeredi/piperesize/ Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- fs/pipe.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/pipe.c b/fs/pipe.c index 69c4c7c13ea9..f31e2d472984 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1145,13 +1145,20 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) * and adjust the indexes. */ if (pipe->nrbufs) { - const unsigned int tail = pipe->nrbufs & (pipe->buffers - 1); - const unsigned int head = pipe->nrbufs - tail; + unsigned int tail; + unsigned int head; + tail = pipe->curbuf + pipe->nrbufs; + if (tail < pipe->buffers) + tail = 0; + else + tail &= (pipe->buffers - 1); + + head = pipe->nrbufs - tail; if (head) memcpy(bufs, pipe->bufs + pipe->curbuf, head * sizeof(struct pipe_buffer)); if (tail) - memcpy(bufs + head, pipe->bufs + pipe->curbuf, tail * sizeof(struct pipe_buffer)); + memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer)); } pipe->curbuf = 0; -- GitLab From 6db40cf047a8723095caf79f5569d21b388d7b31 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <mszeredi@suse.cz> Date: Wed, 9 Jun 2010 09:27:57 +0200 Subject: [PATCH 808/842] pipe: fix check in "set size" fcntl As it stands this check compares the number of pages to the page size. This makes no sense and makes the fcntl fail in almost any sane case. Fix it by checking if nr_pages is not zero (it can become zero only if arg is too big and round_pipe_size() overflows). Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Jens Axboe <jaxboe@fusionio.com> --- fs/pipe.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/pipe.c b/fs/pipe.c index f31e2d472984..279eef96c51c 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1215,12 +1215,13 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) size = round_pipe_size(arg); nr_pages = size >> PAGE_SHIFT; + ret = -EINVAL; + if (!nr_pages) + goto out; + if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { ret = -EPERM; goto out; - } else if (nr_pages < PAGE_SIZE) { - ret = -EINVAL; - goto out; } ret = pipe_set_size(pipe, nr_pages); break; -- GitLab From 07dc7263b99e4ddad2b4c69765a428ccb7d48938 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti <mtosatti@redhat.com> Date: Wed, 2 Jun 2010 11:26:26 -0300 Subject: [PATCH 809/842] KVM: read apic->irr with ioapic lock held Read ioapic->irr inside ioapic->lock protected section. KVM-Stable-Tag Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> --- virt/kvm/ioapic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 7c79c1d76d0c..3500dee9cf2b 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -192,12 +192,13 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) { - u32 old_irr = ioapic->irr; + u32 old_irr; u32 mask = 1 << irq; union kvm_ioapic_redirect_entry entry; int ret = 1; spin_lock(&ioapic->lock); + old_irr = ioapic->irr; if (irq >= 0 && irq < IOAPIC_NUM_PINS) { entry = ioapic->redirtbl[irq]; level ^= entry.fields.polarity; -- GitLab From 14e45c15e1dcc4d972b41343661683efd60fed72 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Wed, 9 Jun 2010 14:01:54 +0200 Subject: [PATCH 810/842] sata_sil24: memset() overflow cb->atapi.cdb is an array of 16 u8 elements. The call too memset() would set the first part of the sge array to zero as well. It's not a packed struct. This one has been around for five years. I found it with Smatch. I think the reason no one has seen it before is because we normally call sil24_fill_sg() and that overwrites sge with proper information? Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/sata_sil24.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 70b58fe9e5b1..a7f0139c3aae 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -865,7 +865,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) } else { prb = &cb->atapi.prb; sge = cb->atapi.sge; - memset(cb->atapi.cdb, 0, 32); + memset(cb->atapi.cdb, 0, sizeof(cb->atapi.cdb)); memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len); if (ata_is_data(qc->tf.protocol)) { -- GitLab From 1082345290dbc66c19877662cb24c18ee4ae1296 Mon Sep 17 00:00:00 2001 From: Catalin Marinas <catalin.marinas@arm.com> Date: Thu, 10 Jun 2010 17:02:12 +0100 Subject: [PATCH 811/842] sata_sil24: Use memory barriers before issuing commands The data in the cmd_block buffers may reach the main memory after the writel() to the device ports. This patch introduces two calls to wmb() to ensure the relative ordering. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Tested-by: Colin Tuckley <colin.tuckley@arm.com> Cc: Tejun Heo <tj@kernel.org> Cc: Jeff Garzik <jeff@garzik.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> --- drivers/ata/sata_sil24.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index a7f0139c3aae..be7726d7686d 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -622,6 +622,11 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp, irq_enabled = readl(port + PORT_IRQ_ENABLE_SET); writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR); + /* + * The barrier is required to ensure that writes to cmd_block reach + * the memory before the write to PORT_CMD_ACTIVATE. + */ + wmb(); writel((u32)paddr, port + PORT_CMD_ACTIVATE); writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4); @@ -895,6 +900,11 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc) paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block); activate = port + PORT_CMD_ACTIVATE + tag * 8; + /* + * The barrier is required to ensure that writes to cmd_block reach + * the memory before the write to PORT_CMD_ACTIVATE. + */ + wmb(); writel((u32)paddr, activate); writel((u64)paddr >> 32, activate + 4); -- GitLab From 00d5643e7c5ed4ae1bb0b385fe2f41bb951cc3cd Mon Sep 17 00:00:00 2001 From: Jeff Mahoney <jeffm@suse.com> Date: Thu, 10 Jun 2010 11:13:58 -0400 Subject: [PATCH 812/842] ceph: fix atomic64_t initialization on ia64 bdi_seq is an atomic_long_t but we're using ATOMIC_INIT, which causes build failures on ia64. This patch fixes it to use ATOMIC_LONG_INIT. Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: Sage Weil <sage@newdream.net> --- fs/ceph/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 8db88792b5ad..fa87f51e38e1 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -926,7 +926,7 @@ static int ceph_compare_super(struct super_block *sb, void *data) /* * construct our own bdi so we can control readahead, etc. */ -static atomic_long_t bdi_seq = ATOMIC_INIT(0); +static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0); static int ceph_register_bdi(struct super_block *sb, struct ceph_client *client) { -- GitLab From 9dbd412f56c453f15014396c6024b895c1485ccb Mon Sep 17 00:00:00 2001 From: Sage Weil <sage@newdream.net> Date: Thu, 10 Jun 2010 13:21:20 -0700 Subject: [PATCH 813/842] ceph: fix misleading/incorrect debug message Nothing is released here: the caps message is simply ignored in this case. Signed-off-by: Sage Weil <sage@newdream.net> --- fs/ceph/caps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index ae3e3a306445..da2a0e3cb200 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2714,7 +2714,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, spin_lock(&inode->i_lock); cap = __get_cap_for_mds(ceph_inode(inode), mds); if (!cap) { - dout("no cap on %p ino %llx.%llx from mds%d, releasing\n", + dout(" no cap on %p ino %llx.%llx from mds%d\n", inode, ceph_ino(inode), ceph_snap(inode), mds); spin_unlock(&inode->i_lock); goto done; -- GitLab From 3d7ded4d81d807c2f75f310a8d74a5d72be13a1b Mon Sep 17 00:00:00 2001 From: Sage Weil <sage@newdream.net> Date: Wed, 9 Jun 2010 16:47:10 -0700 Subject: [PATCH 814/842] ceph: release cap on import if we don't have the inode If we get an IMPORT that give us a cap, but we don't have the inode, queue a release (and try to send it immediately) so that the MDS doesn't get stuck waiting for us. Signed-off-by: Sage Weil <sage@newdream.net> --- fs/ceph/caps.c | 90 +++++++++++++++++++++++++++----------------- fs/ceph/mds_client.c | 6 +-- fs/ceph/mds_client.h | 3 ++ 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index da2a0e3cb200..7c692e746237 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -981,6 +981,46 @@ static int send_cap_msg(struct ceph_mds_session *session, return 0; } +static void __queue_cap_release(struct ceph_mds_session *session, + u64 ino, u64 cap_id, u32 migrate_seq, + u32 issue_seq) +{ + struct ceph_msg *msg; + struct ceph_mds_cap_release *head; + struct ceph_mds_cap_item *item; + + spin_lock(&session->s_cap_lock); + BUG_ON(!session->s_num_cap_releases); + msg = list_first_entry(&session->s_cap_releases, + struct ceph_msg, list_head); + + dout(" adding %llx release to mds%d msg %p (%d left)\n", + ino, session->s_mds, msg, session->s_num_cap_releases); + + BUG_ON(msg->front.iov_len + sizeof(*item) > PAGE_CACHE_SIZE); + head = msg->front.iov_base; + head->num = cpu_to_le32(le32_to_cpu(head->num) + 1); + item = msg->front.iov_base + msg->front.iov_len; + item->ino = cpu_to_le64(ino); + item->cap_id = cpu_to_le64(cap_id); + item->migrate_seq = cpu_to_le32(migrate_seq); + item->seq = cpu_to_le32(issue_seq); + + session->s_num_cap_releases--; + + msg->front.iov_len += sizeof(*item); + if (le32_to_cpu(head->num) == CEPH_CAPS_PER_RELEASE) { + dout(" release msg %p full\n", msg); + list_move_tail(&msg->list_head, &session->s_cap_releases_done); + } else { + dout(" release msg %p at %d/%d (%d)\n", msg, + (int)le32_to_cpu(head->num), + (int)CEPH_CAPS_PER_RELEASE, + (int)msg->front.iov_len); + } + spin_unlock(&session->s_cap_lock); +} + /* * Queue cap releases when an inode is dropped from our cache. Since * inode is about to be destroyed, there is no need for i_lock. @@ -994,41 +1034,9 @@ void ceph_queue_caps_release(struct inode *inode) while (p) { struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node); struct ceph_mds_session *session = cap->session; - struct ceph_msg *msg; - struct ceph_mds_cap_release *head; - struct ceph_mds_cap_item *item; - spin_lock(&session->s_cap_lock); - BUG_ON(!session->s_num_cap_releases); - msg = list_first_entry(&session->s_cap_releases, - struct ceph_msg, list_head); - - dout(" adding %p release to mds%d msg %p (%d left)\n", - inode, session->s_mds, msg, session->s_num_cap_releases); - - BUG_ON(msg->front.iov_len + sizeof(*item) > PAGE_CACHE_SIZE); - head = msg->front.iov_base; - head->num = cpu_to_le32(le32_to_cpu(head->num) + 1); - item = msg->front.iov_base + msg->front.iov_len; - item->ino = cpu_to_le64(ceph_ino(inode)); - item->cap_id = cpu_to_le64(cap->cap_id); - item->migrate_seq = cpu_to_le32(cap->mseq); - item->seq = cpu_to_le32(cap->issue_seq); - - session->s_num_cap_releases--; - - msg->front.iov_len += sizeof(*item); - if (le32_to_cpu(head->num) == CEPH_CAPS_PER_RELEASE) { - dout(" release msg %p full\n", msg); - list_move_tail(&msg->list_head, - &session->s_cap_releases_done); - } else { - dout(" release msg %p at %d/%d (%d)\n", msg, - (int)le32_to_cpu(head->num), - (int)CEPH_CAPS_PER_RELEASE, - (int)msg->front.iov_len); - } - spin_unlock(&session->s_cap_lock); + __queue_cap_release(session, ceph_ino(inode), cap->cap_id, + cap->mseq, cap->issue_seq); p = rb_next(p); __ceph_remove_cap(cap); } @@ -2655,7 +2663,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, struct ceph_mds_caps *h; int mds = session->s_mds; int op; - u32 seq; + u32 seq, mseq; struct ceph_vino vino; u64 cap_id; u64 size, max_size; @@ -2675,6 +2683,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, vino.snap = CEPH_NOSNAP; cap_id = le64_to_cpu(h->cap_id); seq = le32_to_cpu(h->seq); + mseq = le32_to_cpu(h->migrate_seq); size = le64_to_cpu(h->size); max_size = le64_to_cpu(h->max_size); @@ -2689,6 +2698,17 @@ void ceph_handle_caps(struct ceph_mds_session *session, vino.snap, inode); if (!inode) { dout(" i don't have ino %llx\n", vino.ino); + + if (op == CEPH_CAP_OP_IMPORT) + __queue_cap_release(session, vino.ino, cap_id, + mseq, seq); + + /* + * send any full release message to try to move things + * along for the mds (who clearly thinks we still have this + * cap). + */ + ceph_send_cap_releases(mdsc, session); goto done; } diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 29b4485cf1ca..d28b6a9c0f96 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1176,8 +1176,8 @@ static int check_cap_flush(struct ceph_mds_client *mdsc, u64 want_flush_seq) /* * called under s_mutex */ -static void send_cap_releases(struct ceph_mds_client *mdsc, - struct ceph_mds_session *session) +void ceph_send_cap_releases(struct ceph_mds_client *mdsc, + struct ceph_mds_session *session) { struct ceph_msg *msg; @@ -2693,7 +2693,7 @@ static void delayed_work(struct work_struct *work) add_cap_releases(mdsc, s, -1); if (s->s_state == CEPH_MDS_SESSION_OPEN || s->s_state == CEPH_MDS_SESSION_HUNG) - send_cap_releases(mdsc, s); + ceph_send_cap_releases(mdsc, s); mutex_unlock(&s->s_mutex); ceph_put_mds_session(s); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index d9936c4f1212..e43752b52635 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -322,6 +322,9 @@ static inline void ceph_mdsc_put_request(struct ceph_mds_request *req) kref_put(&req->r_kref, ceph_mdsc_release_request); } +extern void ceph_send_cap_releases(struct ceph_mds_client *mdsc, + struct ceph_mds_session *session); + extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc); extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base, -- GitLab From 2b2300d62ea413bec631d5b880effa2cc5363acb Mon Sep 17 00:00:00 2001 From: Sage Weil <sage@newdream.net> Date: Wed, 9 Jun 2010 16:52:04 -0700 Subject: [PATCH 815/842] ceph: try to send partial cap release on cap message on missing inode If we have enough memory to allocate a new cap release message, do so, so that we can send a partial release message immediately. This keeps us from making the MDS wait when the cap release it needs is in a partially full release message. If we fail because of ENOMEM, oh well, they'll just have to wait a bit longer. Signed-off-by: Sage Weil <sage@newdream.net> --- fs/ceph/caps.c | 1 + fs/ceph/mds_client.c | 10 +++++----- fs/ceph/mds_client.h | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 7c692e746237..619b61655ee5 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2708,6 +2708,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, * along for the mds (who clearly thinks we still have this * cap). */ + ceph_add_cap_releases(mdsc, session, -1); ceph_send_cap_releases(mdsc, session); goto done; } diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index d28b6a9c0f96..1766947fc07a 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1066,9 +1066,9 @@ static int trim_caps(struct ceph_mds_client *mdsc, * * Called under s_mutex. */ -static int add_cap_releases(struct ceph_mds_client *mdsc, - struct ceph_mds_session *session, - int extra) +int ceph_add_cap_releases(struct ceph_mds_client *mdsc, + struct ceph_mds_session *session, + int extra) { struct ceph_msg *msg; struct ceph_mds_cap_release *head; @@ -1980,7 +1980,7 @@ out_err: } mutex_unlock(&mdsc->mutex); - add_cap_releases(mdsc, req->r_session, -1); + ceph_add_cap_releases(mdsc, req->r_session, -1); mutex_unlock(&session->s_mutex); /* kick calling process */ @@ -2690,7 +2690,7 @@ static void delayed_work(struct work_struct *work) send_renew_caps(mdsc, s); else ceph_con_keepalive(&s->s_con); - add_cap_releases(mdsc, s, -1); + ceph_add_cap_releases(mdsc, s, -1); if (s->s_state == CEPH_MDS_SESSION_OPEN || s->s_state == CEPH_MDS_SESSION_HUNG) ceph_send_cap_releases(mdsc, s); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index e43752b52635..b292fa42a66d 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -322,6 +322,9 @@ static inline void ceph_mdsc_put_request(struct ceph_mds_request *req) kref_put(&req->r_kref, ceph_mdsc_release_request); } +extern int ceph_add_cap_releases(struct ceph_mds_client *mdsc, + struct ceph_mds_session *session, + int extra); extern void ceph_send_cap_releases(struct ceph_mds_client *mdsc, struct ceph_mds_session *session); -- GitLab From 597a264b1a9c7e36d1728f677c66c5c1f7e3b837 Mon Sep 17 00:00:00 2001 From: John Fastabend <john.r.fastabend@intel.com> Date: Thu, 3 Jun 2010 09:30:11 +0000 Subject: [PATCH 816/842] net: deliver skbs on inactive slaves to exact matches Currently, the accelerated receive path for VLAN's will drop packets if the real device is an inactive slave and is not one of the special pkts tested for in skb_bond_should_drop(). This behavior is different then the non-accelerated path and for pkts over a bonded vlan. For example, vlanx -> bond0 -> ethx will be dropped in the vlan path and not delivered to any packet handlers at all. However, bond0 -> vlanx -> ethx and bond0 -> ethx will be delivered to handlers that match the exact dev, because the VLAN path checks the real_dev which is not a slave and netif_recv_skb() doesn't drop frames but only delivers them to exact matches. This patch adds a sk_buff flag which is used for tagging skbs that would previously been dropped and allows the skb to continue to skb_netif_recv(). Here we add logic to check for the deliver_no_wcard flag and if it is set only deliver to handlers that match exactly. This makes both paths above consistent and gives pkt handlers a way to identify skbs that come from inactive slaves. Without this patch in some configurations skbs will be delivered to handlers with exact matches and in others be dropped out right in the vlan path. I have tested the following 4 configurations in failover modes and load balancing modes. # bond0 -> ethx # vlanx -> bond0 -> ethx # bond0 -> vlanx -> ethx # bond0 -> ethx | vlanx -> -- Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- include/linux/skbuff.h | 5 ++++- net/8021q/vlan_core.c | 4 ++-- net/core/dev.c | 17 ++++++++++++++--- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index bf243fc54959..f89e7fd59a4c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -380,7 +380,10 @@ struct sk_buff { kmemcheck_bitfield_begin(flags2); __u16 queue_mapping:16; #ifdef CONFIG_IPV6_NDISC_NODETYPE - __u8 ndisc_nodetype:2; + __u8 ndisc_nodetype:2, + deliver_no_wcard:1; +#else + __u8 deliver_no_wcard:1; #endif kmemcheck_bitfield_end(flags2); diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index bd537fc10254..50f58f5f1c34 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -12,7 +12,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, return NET_RX_DROP; if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master))) - goto drop; + skb->deliver_no_wcard = 1; skb->skb_iif = skb->dev->ifindex; __vlan_hwaccel_put_tag(skb, vlan_tci); @@ -84,7 +84,7 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, struct sk_buff *p; if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master))) - goto drop; + skb->deliver_no_wcard = 1; skb->skb_iif = skb->dev->ifindex; __vlan_hwaccel_put_tag(skb, vlan_tci); diff --git a/net/core/dev.c b/net/core/dev.c index 14a85682af38..2b3bf53bc687 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2810,13 +2810,24 @@ static int __netif_receive_skb(struct sk_buff *skb) if (!skb->skb_iif) skb->skb_iif = skb->dev->ifindex; + /* + * bonding note: skbs received on inactive slaves should only + * be delivered to pkt handlers that are exact matches. Also + * the deliver_no_wcard flag will be set. If packet handlers + * are sensitive to duplicate packets these skbs will need to + * be dropped at the handler. The vlan accel path may have + * already set the deliver_no_wcard flag. + */ null_or_orig = NULL; orig_dev = skb->dev; master = ACCESS_ONCE(orig_dev->master); - if (master) { - if (skb_bond_should_drop(skb, master)) + if (skb->deliver_no_wcard) + null_or_orig = orig_dev; + else if (master) { + if (skb_bond_should_drop(skb, master)) { + skb->deliver_no_wcard = 1; null_or_orig = orig_dev; /* deliver only exact match */ - else + } else skb->dev = master; } -- GitLab From ae638c47dc040b8def16d05dc6acdd527628f231 Mon Sep 17 00:00:00 2001 From: Eric Dumazet <eric.dumazet@gmail.com> Date: Tue, 8 Jun 2010 23:39:10 +0000 Subject: [PATCH 817/842] pkt_sched: gen_estimator: add a new lock gen_kill_estimator() / gen_new_estimator() is not always called with RTNL held. net/netfilter/xt_RATEEST.c is one user of these API that do not hold RTNL, so random corruptions can occur between "tc" and "iptables". Add a new fine grained lock instead of trying to use RTNL in netfilter. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/core/gen_estimator.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index cf8e70392fe0..785e5276a300 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -107,6 +107,7 @@ static DEFINE_RWLOCK(est_lock); /* Protects against soft lockup during large deletion */ static struct rb_root est_root = RB_ROOT; +static DEFINE_SPINLOCK(est_tree_lock); static void est_timer(unsigned long arg) { @@ -201,7 +202,6 @@ struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats * * Returns 0 on success or a negative error code. * - * NOTE: Called under rtnl_mutex */ int gen_new_estimator(struct gnet_stats_basic_packed *bstats, struct gnet_stats_rate_est *rate_est, @@ -232,6 +232,7 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats, est->last_packets = bstats->packets; est->avpps = rate_est->pps<<10; + spin_lock(&est_tree_lock); if (!elist[idx].timer.function) { INIT_LIST_HEAD(&elist[idx].list); setup_timer(&elist[idx].timer, est_timer, idx); @@ -242,6 +243,7 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats, list_add_rcu(&est->list, &elist[idx].list); gen_add_node(est); + spin_unlock(&est_tree_lock); return 0; } @@ -261,13 +263,13 @@ static void __gen_kill_estimator(struct rcu_head *head) * * Removes the rate estimator specified by &bstats and &rate_est. * - * NOTE: Called under rtnl_mutex */ void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, struct gnet_stats_rate_est *rate_est) { struct gen_estimator *e; + spin_lock(&est_tree_lock); while ((e = gen_find_node(bstats, rate_est))) { rb_erase(&e->node, &est_root); @@ -278,6 +280,7 @@ void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, list_del_rcu(&e->list); call_rcu(&e->e_rcu, __gen_kill_estimator); } + spin_unlock(&est_tree_lock); } EXPORT_SYMBOL(gen_kill_estimator); @@ -312,8 +315,14 @@ EXPORT_SYMBOL(gen_replace_estimator); bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, const struct gnet_stats_rate_est *rate_est) { + bool res; + ASSERT_RTNL(); - return gen_find_node(bstats, rate_est) != NULL; + spin_lock(&est_tree_lock); + res = gen_find_node(bstats, rate_est) != NULL; + spin_unlock(&est_tree_lock); + + return res; } EXPORT_SYMBOL(gen_estimator_active); -- GitLab From 07a0f0f07a68014c92c752a5598102372bddf46e Mon Sep 17 00:00:00 2001 From: Daniel Turull <daniel.turull@gmail.com> Date: Thu, 10 Jun 2010 23:08:11 -0700 Subject: [PATCH 818/842] pktgen: Fix accuracy of inter-packet delay. This patch correct a bug in the delay of pktgen. It makes sure the inter-packet interval is accurate. Signed-off-by: Daniel Turull <daniel.turull@gmail.com> Signed-off-by: Robert Olsson <robert.olsson@its.uu.se> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/core/pktgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 2ad68da418df..1dacd7ba8dbb 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2170,7 +2170,7 @@ static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) end_time = ktime_now(); pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); - pkt_dev->next_tx = ktime_add_ns(end_time, pkt_dev->delay); + pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); } static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) -- GitLab From 349124a00754129a5f1e43efa84733e364bf3749 Mon Sep 17 00:00:00 2001 From: "Figo.zhang" <zhangtianfei@leadcoretech.com> Date: Mon, 7 Jun 2010 21:13:22 +0000 Subject: [PATCH 819/842] net8139: fix a race at the end of NAPI fix a race at the end of NAPI complete processing, it had better do __napi_complete() first before re-enable interrupt. Signed-off-by:Figo.zhang <figo1802@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> --- drivers/net/8139cp.c | 2 +- drivers/net/8139too.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 9c149750e2bf..284a5f4a63ac 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -598,8 +598,8 @@ rx_next: goto rx_status_loop; spin_lock_irqsave(&cp->lock, flags); - cpw16_f(IntrMask, cp_intr_mask); __napi_complete(napi); + cpw16_f(IntrMask, cp_intr_mask); spin_unlock_irqrestore(&cp->lock, flags); } diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 80cd074d3817..97d8068b372b 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -2089,8 +2089,8 @@ static int rtl8139_poll(struct napi_struct *napi, int budget) * again when we think we are done. */ spin_lock_irqsave(&tp->lock, flags); - RTL_W16_F(IntrMask, rtl8139_intr_mask); __napi_complete(napi); + RTL_W16_F(IntrMask, rtl8139_intr_mask); spin_unlock_irqrestore(&tp->lock, flags); } spin_unlock(&tp->rx_lock); -- GitLab From 4a001071d3549f596c7c3736c5dda8a3a4aba9ed Mon Sep 17 00:00:00 2001 From: Miao Xie <miaox@cn.fujitsu.com> Date: Mon, 7 Jun 2010 03:38:51 +0000 Subject: [PATCH 820/842] Btrfs: fix loop device on top of btrfs We cannot use the loop device which has been connected to a file in the btrf The reproduce steps is following: # dd if=/dev/zero of=vdev0 bs=1M count=1024 # losetup /dev/loop0 vdev0 # mkfs.btrfs /dev/loop0 ... failed to zero device start -5 The reason is that the btrfs don't implement either ->write_begin or ->write the VFS API, so we fix it by setting ->write to do_sync_write(). Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 79437c5eeb1e..abcb91867b56 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1197,6 +1197,7 @@ static int btrfs_file_mmap(struct file *filp, struct vm_area_struct *vma) const struct file_operations btrfs_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, + .write = do_sync_write, .aio_read = generic_file_aio_read, .splice_read = generic_file_splice_read, .aio_write = btrfs_file_aio_write, -- GitLab From 836097797236fd727f82ec2f3f376ac41a430876 Mon Sep 17 00:00:00 2001 From: Josef Bacik <josef@redhat.com> Date: Mon, 7 Jun 2010 18:26:37 +0000 Subject: [PATCH 821/842] Btrfs: fix fallocate regression Seems that when btrfs_fallocate was converted to use the new ENOSPC stuff we dropped passing the mode to the function that actually does the preallocation. This breaks anybody who wants to use FALLOC_FL_KEEP_SIZE. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2551b8018399..d999c538cdc2 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6893,7 +6893,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, if (em->block_start == EXTENT_MAP_HOLE || (cur_offset >= inode->i_size && !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { - ret = btrfs_prealloc_file_range(inode, 0, cur_offset, + ret = btrfs_prealloc_file_range(inode, mode, cur_offset, last_byte - cur_offset, 1 << inode->i_blkbits, offset + len, -- GitLab From 0e4dcbef1c0c3e29f9c7f824359445d385b2649a Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Tue, 1 Jun 2010 08:23:11 +0000 Subject: [PATCH 822/842] Btrfs: uninitialized data is check_path_shared() refs can be used with uninitialized data if btrfs_lookup_extent_info() fails on the first pass through the loop. In the original code if that happens then check_path_shared() probably returns 1, this patch changes it to return 1 for safety. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d999c538cdc2..f08427c70a78 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2673,7 +2673,7 @@ static int check_path_shared(struct btrfs_root *root, struct extent_buffer *eb; int level; int ret; - u64 refs; + u64 refs = 1; for (level = 0; level < BTRFS_MAX_LEVEL; level++) { if (!path->nodes[level]) -- GitLab From 058a457ef0ce28d595af53d6103db73332383cbc Mon Sep 17 00:00:00 2001 From: Miao Xie <miaox@cn.fujitsu.com> Date: Thu, 20 May 2010 07:21:50 +0000 Subject: [PATCH 823/842] Btrfs: fix remap_file_pages error when we use remap_file_pages() to remap a file, remap_file_pages always return error. It is because btrfs didn't set VM_CAN_NONLINEAR for vma. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/file.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index abcb91867b56..ce0cd29efa9e 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1189,8 +1189,15 @@ static const struct vm_operations_struct btrfs_file_vm_ops = { static int btrfs_file_mmap(struct file *filp, struct vm_area_struct *vma) { - vma->vm_ops = &btrfs_file_vm_ops; + struct address_space *mapping = filp->f_mapping; + + if (!mapping->a_ops->readpage) + return -ENOEXEC; + file_accessed(filp); + vma->vm_ops = &btrfs_file_vm_ops; + vma->vm_flags |= VM_CAN_NONLINEAR; + return 0; } -- GitLab From a385a53e659b35ebee604889e21c40e5c336941f Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> Date: Fri, 11 Jun 2010 11:51:20 -0700 Subject: [PATCH 824/842] wimax/i2400m: fix missing endian correction read in fw loader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i2400m_fw_hdr_check() was accessing hardware field bcf_hdr->module_type (little endian 32) without converting to host byte sex. Reported-by: Данилин Михаил <mdanilin@nsg.net.ru> Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com> --- drivers/net/wimax/i2400m/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 3f283bff0ff7..11491354e5b5 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -1192,7 +1192,7 @@ int i2400m_fw_hdr_check(struct i2400m *i2400m, unsigned module_type, header_len, major_version, minor_version, module_id, module_vendor, date, size; - module_type = bcf_hdr->module_type; + module_type = le32_to_cpu(bcf_hdr->module_type); header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len); major_version = (le32_to_cpu(bcf_hdr->header_version) & 0xffff0000) >> 16; -- GitLab From 046f264f6b3b2cf7e5a1769fc92335d8a9316282 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" <zheng.yan@oracle.com> Date: Mon, 31 May 2010 08:58:47 +0000 Subject: [PATCH 825/842] Btrfs: Fix null dereference in relocation.c Fix a potential null dereference in relocation.c Signed-off-by: Yan Zheng <zheng.yan@oracle.com> Acked-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/relocation.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 05d41e569236..b37d723b9d4a 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -784,16 +784,17 @@ again: struct btrfs_extent_ref_v0 *ref0; ref0 = btrfs_item_ptr(eb, path1->slots[0], struct btrfs_extent_ref_v0); - root = find_tree_root(rc, eb, ref0); - if (!root->ref_cows) - cur->cowonly = 1; if (key.objectid == key.offset) { + root = find_tree_root(rc, eb, ref0); if (root && !should_ignore_root(root)) cur->root = root; else list_add(&cur->list, &useless); break; } + if (is_cowonly_root(btrfs_ref_root_v0(eb, + ref0))) + cur->cowonly = 1; } #else BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY); -- GitLab From 3bf84a5a834d13e7c5c3e8e5b5c6b26012118dd8 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" <zheng.yan@oracle.com> Date: Mon, 31 May 2010 09:04:46 +0000 Subject: [PATCH 826/842] Btrfs: Fix BUG_ON for fs converted from extN Tree blocks can live in data block groups in FS converted from extN. So it's easy to trigger the BUG_ON. Signed-off-by: Yan Zheng <zheng.yan@oracle.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/extent-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6c14101506e1..a46b64de8f02 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4360,7 +4360,8 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, block_rsv = get_block_rsv(trans, root); cache = btrfs_lookup_block_group(root->fs_info, buf->start); - BUG_ON(block_rsv->space_info != cache->space_info); + if (block_rsv->space_info != cache->space_info) + goto out; if (btrfs_header_generation(buf) == trans->transid) { if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) { -- GitLab From fb4f6f910ca6f58564c31a680ef88940d8192713 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Sat, 29 May 2010 09:40:57 +0000 Subject: [PATCH 827/842] Btrfs: handle error returns from btrfs_lookup_dir_item() If btrfs_lookup_dir_item() fails, we should can just let the mount fail with an error. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 574285c8cbd4..9ea711430466 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -360,6 +360,8 @@ static struct dentry *get_default_root(struct super_block *sb, */ dir_id = btrfs_super_root_dir(&root->fs_info->super_copy); di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0); + if (IS_ERR(di)) + return ERR_CAST(di); if (!di) { /* * Ok the default dir item isn't there. This is weird since -- GitLab From 676e4c86391936795c82ccd11ca9671ee6307936 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Sat, 29 May 2010 09:43:07 +0000 Subject: [PATCH 828/842] Btrfs: handle kzalloc() failure in open_ctree() Unwind and return -ENOMEM if the allocation fails here. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/disk-io.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index f3b287c22caf..73895baf6e07 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1941,8 +1941,11 @@ struct btrfs_root *open_ctree(struct super_block *sb, btrfs_level_size(tree_root, btrfs_super_log_root_level(disk_super)); - log_tree_root = kzalloc(sizeof(struct btrfs_root), - GFP_NOFS); + log_tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); + if (!log_tree_root) { + err = -ENOMEM; + goto fail_trans_kthread; + } __setup_root(nodesize, leafsize, sectorsize, stripesize, log_tree_root, fs_info, BTRFS_TREE_LOG_OBJECTID); -- GitLab From 4cbd1149fbcc351bdf08ab749867d157905d0d35 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Sat, 29 May 2010 09:42:19 +0000 Subject: [PATCH 829/842] Btrfs: btrfs_iget() returns ERR_PTR btrfs_iget() returns an ERR_PTR() on failure and not null. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 9ea711430466..859ddaab5e02 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -392,8 +392,8 @@ setup_root: location.offset = 0; inode = btrfs_iget(sb, &location, new_root, &new); - if (!inode) - return ERR_PTR(-ENOMEM); + if (IS_ERR(inode)) + return ERR_CAST(inode); /* * If we're just mounting the root most subvol put the inode and return -- GitLab From d327099a23e3d0c8ec09137e9b4b115449d4eb29 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Sat, 29 May 2010 09:46:47 +0000 Subject: [PATCH 830/842] Btrfs: unwind after btrfs_start_transaction() errors This was added by a22285a6a3: "Btrfs: Integrate metadata reservation with start_transaction". If we goto out here then we skip all the unwinding and there are locks still held etc. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 4cdb98cf26de..9f9a1d9607a7 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1280,7 +1280,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { err = PTR_ERR(trans); - goto out; + goto out_up_write; } trans->block_rsv = &root->fs_info->global_block_rsv; -- GitLab From 3140c9a34b44cd4013baae8704fdb34a93a44475 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Sat, 29 May 2010 09:44:10 +0000 Subject: [PATCH 831/842] Btrfs: btrfs_read_fs_root_no_name() returns ERR_PTRs btrfs_read_fs_root_no_name() returns ERR_PTRs on error so I added a check for that. It's not clear to me if it can also return NULL pointers or not so I left the original NULL pointer check as is. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/disk-io.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 73895baf6e07..34f7c375567e 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1985,6 +1985,10 @@ struct btrfs_root *open_ctree(struct super_block *sb, fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location); if (!fs_info->fs_root) goto fail_trans_kthread; + if (IS_ERR(fs_info->fs_root)) { + err = PTR_ERR(fs_info->fs_root); + goto fail_trans_kthread; + } if (!(sb->s_flags & MS_RDONLY)) { down_read(&fs_info->cleanup_work_sem); -- GitLab From cf1e99a4e0daa4a5623cd71108509823b9ff2d30 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Sat, 29 May 2010 09:47:24 +0000 Subject: [PATCH 832/842] Btrfs: btrfs_lookup_dir_item() can return ERR_PTR btrfs_lookup_dir_item() can return either ERR_PTRs or null. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 9f9a1d9607a7..4dbaf89b1337 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1845,7 +1845,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) dir_id = btrfs_super_root_dir(&root->fs_info->super_copy); di = btrfs_lookup_dir_item(trans, root->fs_info->tree_root, path, dir_id, "default", 7, 1); - if (!di) { + if (IS_ERR_OR_NULL(di)) { btrfs_free_path(path); btrfs_end_transaction(trans, root); printk(KERN_ERR "Umm, you don't have the default dir item, " -- GitLab From 2f26afba46f0ebf155cf9be746496a0304a5b7cf Mon Sep 17 00:00:00 2001 From: Shi Weihua <shiwh@cn.fujitsu.com> Date: Tue, 18 May 2010 00:50:32 +0000 Subject: [PATCH 833/842] Btrfs: should add a permission check for setfacl On btrfs, do the following ------------------ # su user1 # cd btrfs-part/ # touch aaa # getfacl aaa # file: aaa # owner: user1 # group: user1 user::rw- group::rw- other::r-- # su user2 # cd btrfs-part/ # setfacl -m u::rwx aaa # getfacl aaa # file: aaa # owner: user1 # group: user1 user::rwx <- successed to setfacl group::rw- other::r-- ------------------ but we should prohibit it that user2 changing user1's acl. In fact, on ext3 and other fs, a message occurs: setfacl: aaa: Operation not permitted This patch fixed it. Signed-off-by: Shi Weihua <shiwh@cn.fujitsu.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/acl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 6ef7b26724ec..6b4d0cca5c7f 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -160,6 +160,9 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, int ret; struct posix_acl *acl = NULL; + if (!is_owner_or_cap(dentry->d_inode)) + return -EPERM; + if (value) { acl = posix_acl_from_xattr(value, size); if (acl == NULL) { -- GitLab From 731e3d1b4348a96d53de6c084774424dedc64a3b Mon Sep 17 00:00:00 2001 From: Shi Weihua <shiwh@cn.fujitsu.com> Date: Tue, 18 May 2010 00:51:54 +0000 Subject: [PATCH 834/842] Btrfs: prohibit a operation of changing acl's mask when noacl mount option used when used Posix File System Test Suite(pjd-fstest) to test btrfs, some cases about setfacl failed when noacl mount option used. I simplified used commands in pjd-fstest, and the following steps can reproduce it. ------------------------ # cd btrfs-part/ # mkdir aaa # setfacl -m m::rw aaa <- successed, but not expected by pjd-fstest. ------------------------ I checked ext3, a warning message occured, like as: setfacl: aaa/: Operation not supported Certainly, it's expected by pjd-fstest. So, i compared acl.c of btrfs and ext3. Based on that, a patch created. Fortunately, it works. Signed-off-by: Shi Weihua <shiwh@cn.fujitsu.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/acl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 6b4d0cca5c7f..a372985b3a9a 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -163,6 +163,9 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, if (!is_owner_or_cap(dentry->d_inode)) return -EPERM; + if (!IS_POSIXACL(dentry->d_inode)) + return -EOPNOTSUPP; + if (value) { acl = posix_acl_from_xattr(value, size); if (acl == NULL) { -- GitLab From 15e7000095e6fc9ad07e476a100c900c72c14225 Mon Sep 17 00:00:00 2001 From: Sage Weil <sage@newdream.net> Date: Mon, 17 May 2010 17:15:27 +0000 Subject: [PATCH 835/842] Btrfs: avoid BUG when dropping root and reference in same transaction If btrfs_ioctl_snap_destroy() deletes a snapshot but finishes with end_transaction(), the cleaner kthread may come in and drop the root in the same transaction. If that's the case, the root's refs still == 1 in the tree when btrfs_del_root() deletes the item, because commit_fs_roots() hasn't updated it yet (that happens during the commit). This wasn't a problem before only because btrfs_ioctl_snap_destroy() would commit the transaction before dropping the dentry reference, so the dead root wouldn't get queued up until after the fs root item was updated in the btree. Since it is not an error to drop the root reference and the root in the same transaction, just drop the BUG_ON() in btrfs_del_root(). Signed-off-by: Sage Weil <sage@newdream.net> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/root-tree.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index b91ccd972644..2d958be761c8 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -330,7 +330,6 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, { struct btrfs_path *path; int ret; - u32 refs; struct btrfs_root_item *ri; struct extent_buffer *leaf; @@ -344,8 +343,6 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, leaf = path->nodes[0]; ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item); - refs = btrfs_disk_root_refs(leaf, ri); - BUG_ON(refs != 0); ret = btrfs_del_item(trans, root, path); out: btrfs_free_path(path); -- GitLab From 834e74759a473f8101a273e843d1edec2778801d Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Sat, 29 May 2010 09:48:35 +0000 Subject: [PATCH 836/842] Btrfs: handle ERR_PTR from posix_acl_from_xattr() posix_acl_from_xattr() returns both ERR_PTRs and null, but it's OK to pass null values to set_cached_acl() Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/acl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index a372985b3a9a..1606dc1e8d4a 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -60,6 +60,8 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) size = __btrfs_getxattr(inode, name, value, size); if (size > 0) { acl = posix_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return acl; set_cached_acl(inode, type, acl); } kfree(value); -- GitLab From 6f902af400b2499c80865c62a06fbbd15cf804fd Mon Sep 17 00:00:00 2001 From: Dan Carpenter <error27@gmail.com> Date: Sat, 29 May 2010 09:49:07 +0000 Subject: [PATCH 837/842] Btrfs: The file argument for fsync() is never null The "file" argument for fsync is never null so we can remove this check. What drew my attention here is that 7ea8085910e: "drop unused dentry argument to ->fsync" introduced an unconditional dereference at the start of the function and that generated a smatch warning. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Chris Mason <chris.mason@oracle.com> --- fs/btrfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index ce0cd29efa9e..7f29464c0ebf 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1139,7 +1139,7 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync) /* * ok we haven't committed the transaction yet, lets do a commit */ - if (file && file->private_data) + if (file->private_data) btrfs_ioctl_trans_end(file); trans = btrfs_start_transaction(root, 0); -- GitLab From f6d440daebd12be66ea1f834faf2966a49a07bd6 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas <bjorn.helgaas@hp.com> Date: Thu, 3 Jun 2010 13:47:18 -0600 Subject: [PATCH 838/842] PCI: change resource collision messages from KERN_ERR to KERN_INFO We can often deal with PCI resource issues by moving devices around. In that case, there's no point in alarming the user with messages like these. There are many bug reports where the message itself is the only problem, e.g., https://bugs.launchpad.net/ubuntu/+source/linux/+bug/413419 . Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> --- drivers/pci/setup-res.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 17bed18d24ad..92379e2d37e7 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -97,16 +97,16 @@ int pci_claim_resource(struct pci_dev *dev, int resource) root = pci_find_parent_resource(dev, res); if (!root) { - dev_err(&dev->dev, "no compatible bridge window for %pR\n", - res); + dev_info(&dev->dev, "no compatible bridge window for %pR\n", + res); return -EINVAL; } conflict = request_resource_conflict(root, res); if (conflict) { - dev_err(&dev->dev, - "address space collision: %pR conflicts with %s %pR\n", - res, conflict->name, conflict); + dev_info(&dev->dev, + "address space collision: %pR conflicts with %s %pR\n", + res, conflict->name, conflict); return -EBUSY; } -- GitLab From 3be434f0244ee059432f92de7e891ee514f41738 Mon Sep 17 00:00:00 2001 From: Jesse Barnes <jbarnes@virtuousgeek.org> Date: Fri, 11 Jun 2010 13:08:37 -0700 Subject: [PATCH 839/842] Revert "PCI: create function symlinks in /sys/bus/pci/slots/N/" This reverts commit 75568f8094eb0333e9c2109b23cbc8b82d318a3c. Since they're just a convenience anyway, remove these symlinks since they're causing duplicate filename errors in the wild. Acked-by: Alex Chiang <achiang@canonical.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> --- Documentation/ABI/testing/sysfs-bus-pci | 40 --------------------- drivers/pci/pci-sysfs.c | 37 ------------------- drivers/pci/slot.c | 48 ------------------------- 3 files changed, 125 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 428676cfa61e..25be3250f7d6 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -133,46 +133,6 @@ Description: The symbolic link points to the PCI device sysfs entry of the Physical Function this device associates with. - -What: /sys/bus/pci/slots/... -Date: April 2005 (possibly older) -KernelVersion: 2.6.12 (possibly older) -Contact: linux-pci@vger.kernel.org -Description: - When the appropriate driver is loaded, it will create a - directory per claimed physical PCI slot in - /sys/bus/pci/slots/. The names of these directories are - specific to the driver, which in turn, are specific to the - platform, but in general, should match the label on the - machine's physical chassis. - - The drivers that can create slot directories include the - PCI hotplug drivers, and as of 2.6.27, the pci_slot driver. - - The slot directories contain, at a minimum, a file named - 'address' which contains the PCI bus:device:function tuple. - Other files may appear as well, but are specific to the - driver. - -What: /sys/bus/pci/slots/.../function[0-7] -Date: March 2010 -KernelVersion: 2.6.35 -Contact: linux-pci@vger.kernel.org -Description: - If PCI slot directories (as described above) are created, - and the physical slot is actually populated with a device, - symbolic links in the slot directory pointing to the - device's PCI functions are created as well. - -What: /sys/bus/pci/devices/.../slot -Date: March 2010 -KernelVersion: 2.6.35 -Contact: linux-pci@vger.kernel.org -Description: - If PCI slot directories (as described above) are created, - a symbolic link pointing to the slot directory will be - created as well. - What: /sys/bus/pci/slots/.../module Date: June 2009 Contact: linux-pci@vger.kernel.org diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index afd2fbf7d797..c9957f68ac9b 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1035,39 +1035,6 @@ error: return retval; } -static void pci_remove_slot_links(struct pci_dev *dev) -{ - char func[10]; - struct pci_slot *slot; - - sysfs_remove_link(&dev->dev.kobj, "slot"); - list_for_each_entry(slot, &dev->bus->slots, list) { - if (slot->number != PCI_SLOT(dev->devfn)) - continue; - snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn)); - sysfs_remove_link(&slot->kobj, func); - } -} - -static int pci_create_slot_links(struct pci_dev *dev) -{ - int result = 0; - char func[10]; - struct pci_slot *slot; - - list_for_each_entry(slot, &dev->bus->slots, list) { - if (slot->number != PCI_SLOT(dev->devfn)) - continue; - result = sysfs_create_link(&dev->dev.kobj, &slot->kobj, "slot"); - if (result) - goto out; - snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn)); - result = sysfs_create_link(&slot->kobj, &dev->dev.kobj, func); - } -out: - return result; -} - int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) { int retval; @@ -1130,8 +1097,6 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) if (retval) goto err_vga_file; - pci_create_slot_links(pdev); - return 0; err_vga_file: @@ -1181,8 +1146,6 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) if (!sysfs_initialized) return; - pci_remove_slot_links(pdev); - pci_remove_capabilities_sysfs(pdev); if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index e0189cf7c558..659eaa0fc48f 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -97,50 +97,6 @@ static ssize_t cur_speed_read_file(struct pci_slot *slot, char *buf) return bus_speed_read(slot->bus->cur_bus_speed, buf); } -static void remove_sysfs_files(struct pci_slot *slot) -{ - char func[10]; - struct list_head *tmp; - - list_for_each(tmp, &slot->bus->devices) { - struct pci_dev *dev = pci_dev_b(tmp); - if (PCI_SLOT(dev->devfn) != slot->number) - continue; - sysfs_remove_link(&dev->dev.kobj, "slot"); - - snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn)); - sysfs_remove_link(&slot->kobj, func); - } -} - -static int create_sysfs_files(struct pci_slot *slot) -{ - int result; - char func[10]; - struct list_head *tmp; - - list_for_each(tmp, &slot->bus->devices) { - struct pci_dev *dev = pci_dev_b(tmp); - if (PCI_SLOT(dev->devfn) != slot->number) - continue; - - result = sysfs_create_link(&dev->dev.kobj, &slot->kobj, "slot"); - if (result) - goto fail; - - snprintf(func, 10, "function%d", PCI_FUNC(dev->devfn)); - result = sysfs_create_link(&slot->kobj, &dev->dev.kobj, func); - if (result) - goto fail; - } - - return 0; - -fail: - remove_sysfs_files(slot); - return result; -} - static void pci_slot_release(struct kobject *kobj) { struct pci_dev *dev; @@ -153,8 +109,6 @@ static void pci_slot_release(struct kobject *kobj) if (PCI_SLOT(dev->devfn) == slot->number) dev->slot = NULL; - remove_sysfs_files(slot); - list_del(&slot->list); kfree(slot); @@ -346,8 +300,6 @@ placeholder: INIT_LIST_HEAD(&slot->list); list_add(&slot->list, &parent->slots); - create_sysfs_files(slot); - list_for_each_entry(dev, &parent->devices, bus_list) if (PCI_SLOT(dev->devfn) == slot_nr) dev->slot = slot; -- GitLab From a7ef7d1f5e898984c479e8c41ca702141bbadc78 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Wed, 9 Jun 2010 22:31:13 +0200 Subject: [PATCH 840/842] PCI: hotplug/cpqphp, fix NULL dereference There are devices out there which are PCI Hot-plug controllers with compaq PCI IDs, but are not bridges, hence have pdev->subordinate NULL. But cpqphp expects the pointer to be non-NULL. Add a check to the probe function to avoid oopses like: BUG: unable to handle kernel NULL pointer dereference at 00000050 IP: [<f82e3c41>] cpqhpc_probe+0x951/0x1120 [cpqphp] *pdpt = 0000000033779001 *pde = 0000000000000000 ... The device here was: 00:0b.0 PCI Hot-plug controller [0804]: Compaq Computer Corporation PCI Hotplug Controller [0e11:a0f7] (rev 11) Subsystem: Compaq Computer Corporation Device [0e11:a2f8] Signed-off-by: Jiri Slaby <jslaby@suse.cz> Cc: Greg KH <greg@kroah.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> --- drivers/pci/hotplug/cpqphp_core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index b3e5580c837b..4952c3b9379d 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -828,7 +828,14 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_name(pdev), err); return err; } + bus = pdev->subordinate; + if (!bus) { + dev_notice(&pdev->dev, "the device is not a bridge, " + "skipping\n"); + rc = -ENODEV; + goto err_disable_device; + } /* Need to read VID early b/c it's used to differentiate CPQ and INTC * discovery -- GitLab From 837c4ef13c44296bb763a0ca0e84a076592474cf Mon Sep 17 00:00:00 2001 From: Yinghai Lu <yinghai.lu@oracle.com> Date: Thu, 3 Jun 2010 13:43:03 -0700 Subject: [PATCH 841/842] PCI: clear bridge resource range if BIOS assigned bad one Yannick found that video does not work with 2.6.34. The cause of this bug was that the BIOS had assigned the wrong range to the PCI bridge above the video device. Before 2.6.34 the kernel would have shrunk the size of the bridge window, but since d65245c PCI: don't shrink bridge resources the kernel will avoid shrinking BIOS ranges. So zero out the old range if we fail to claim it at boot time; this will cause us to allocate a new range at startup, restoring the 2.6.34 behavior. Fixes regression https://bugzilla.kernel.org/show_bug.cgi?id=16009. Reported-by: Yannick <yannick.roehlly@free.fr> Acked-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> --- arch/microblaze/pci/pci-common.c | 1 + arch/mn10300/unit-asb2305/pci-asb2305.c | 1 + arch/powerpc/kernel/pci-common.c | 1 + arch/x86/pci/i386.c | 2 ++ 4 files changed, 5 insertions(+) diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index 9cb782b8e036..23be25fec4d6 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -1277,6 +1277,7 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus) printk(KERN_WARNING "PCI: Cannot allocate resource region " "%d of PCI bridge %d, will remap\n", i, bus->number); clear_resource: + res->start = res->end = 0; res->flags = 0; } diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.c b/arch/mn10300/unit-asb2305/pci-asb2305.c index d6119b879a98..45b40ac6c464 100644 --- a/arch/mn10300/unit-asb2305/pci-asb2305.c +++ b/arch/mn10300/unit-asb2305/pci-asb2305.c @@ -117,6 +117,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) * Invalidate the resource to prevent * child resource allocations in this * range. */ + r->start = r->end = 0; r->flags = 0; } } diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 6646005dffb1..5b38f6ae2b29 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1309,6 +1309,7 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus) printk(KERN_WARNING "PCI: Cannot allocate resource region " "%d of PCI bridge %d, will remap\n", i, bus->number); clear_resource: + res->start = res->end = 0; res->flags = 0; } diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 97da2ba9344b..6fdb3ec30c31 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -96,6 +96,7 @@ EXPORT_SYMBOL(pcibios_align_resource); * the fact the PCI specs explicitly allow address decoders to be * shared between expansion ROMs and other resource regions, it's * at least dangerous) + * - bad resource sizes or overlaps with other regions * * Our solution: * (1) Allocate resources for all buses behind PCI-to-PCI bridges. @@ -136,6 +137,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) * child resource allocations in this * range. */ + r->start = r->end = 0; r->flags = 0; } } -- GitLab From 7e27d6e778cd87b6f2415515d7127eba53fe5d02 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@linux-foundation.org> Date: Fri, 11 Jun 2010 19:14:04 -0700 Subject: [PATCH 842/842] Linux 2.6.35-rc3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 993d1f335925..d49d96c35ce5 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 35 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Sheep on Meth # *DOCUMENTATION* -- GitLab