omap3: Optimize detection of cpu revision
cover omap3: Optimize detection of cpu revision
Each call to get_cpu_rev() leads to repetitive execution of code to detect the cpu revision.
This patchset ensures that mechanism to detect revision is not executed each time; instead a stored value is returned.
Since, revision info is needed in s_init(), the function to identify cpu revision needs to be called twice. At the moment, it is necessary/ unavoidable.
Sanjeev Premi (2):
omap3: Identify the CPU in arch_cpu_init()
omap3: Identify cpu in s_init()
cpu/arm_cortexa8/omap3/board.c | 2 + cpu/arm_cortexa8/omap3/sys_info.c | 73 ++++++++++++++++++++++---------- include/asm-arm/arch-omap3/sys_proto.h | 3 +- include/configs/omap3_beagle.h | 2 + include/configs/omap3_evm.h | 2 + include/configs/omap3_overo.h | 2 + include/configs/omap3_pandora.h | 2 + include/configs/omap3_zoom1.h | 2 + include/configs/omap3_zoom2.h | 2 + 9 files changed, 66 insertions(+), 24 deletions(-)
PATCH 1/2 omap3: Identify the CPU in arch_cpu_init()
The function get_cpu_rev() is called multiple times during execution resulting in probe into the IDCODE register to extract the revision information.
This patch does the following:
- Moves the steps to identify static cpu information into arch_cpu_init().
- Updates configs for all omap3 boards to define CONFIG_ARCH_CPU_INIT.
- Updates get_cpu_rev() to return value calculated in arch_cpu_init().
- Since revision isn't expected to be longer than 8bits, get_cpu_rev() return a u8 value instead of u32.
--- cpu/arm_cortexa8/omap3/sys_info.c | 60 +++++++++++++++++++------------ include/asm-arm/arch-omap3/sys_proto.h | 2 +- include/configs/omap3_beagle.h | 2 + include/configs/omap3_evm.h | 2 + include/configs/omap3_overo.h | 2 + include/configs/omap3_pandora.h | 2 + include/configs/omap3_zoom1.h | 2 + include/configs/omap3_zoom2.h | 2 + 8 files changed, 50 insertions(+), 24 deletions(-)
cpu/arm_cortexa8/omap3/sys_info.c +37 -23
@@ -41,6 +41,41 @@ static char *rev_s[CPU_3XX_MAX_REV] = {"3.0" , "3.1"}; +static u8 cpu_revision; + +/** +* Perform architecture specific initialization. +* +* Currently, it identifies the cpu revision. +*/ +int arch_cpu_init (void ) +{ +u32 cpuid =0 ; +struct ctrl_id *id_base; + +/* +* On ES1.0 the IDCODE register is not exposed on L4 +* so using CPU ID to differentiate between ES1.0 and > ES1.0. +*/ + __asm__ __volatile__("mrc p15, 0, %0, c0, c0, 0" :"=r" (cpuid)); +if ((cpuid &0xf ) ==0x0 ) { + cpu_revision =CPU_3XX_ES10 ; + }else { +/* Decode the IDs on > ES1.0 */ + id_base = (struct ctrl_id *)OMAP34XX_ID_L4_IO_BASE ; + + cpuid =readl (&id_base->idcode); + + cpu_revision = (cpuid >>CPU_3XX_ID_SHIFT ) &0xf ; + +/* Some early ES2.0 seem to report rev 0, fix this */ +if (cpu_revision ==0 ) + cpu_revision =CPU_3XX_ES20 ; + } + +return 0 ; +} +/***************************************************************** * dieid_num_r(void) - read and set die ID *****************************************************************/
@@ -78,30 +113,9 @@ u32 get_cpu_type(void)/****************************************** * get_cpu_rev(void) - extract version info ******************************************/ -u32 get_cpu_rev (void ) +u8 get_cpu_rev (void ) { -u32 cpuid =0 ; -struct ctrl_id *id_base; - -/* -* On ES1.0 the IDCODE register is not exposed on L4 -* so using CPU ID to differentiate between ES1.0 and > ES1.0. -*/ - __asm__ __volatile__("mrc p15, 0, %0, c0, c0, 0" :"=r" (cpuid)); -if ((cpuid &0xf ) ==0x0 ) -return CPU_3XX_ES10 ; -else { -/* Decode the IDs on > ES1.0 */ - id_base = (struct ctrl_id *)OMAP34XX_ID_L4_IO_BASE ; - - cpuid = (readl (&id_base->idcode) >>CPU_3XX_ID_SHIFT ) &0xf ; - -/* Some early ES2.0 seem to report ID 0, fix this */ -if (cpuid ==0 ) - cpuid =CPU_3XX_ES20 ; - -return cpuid; - } +return cpu_revision; }/****************************************************
include/asm-arm/arch-omap3/sys_proto.h +1 -1
@@ -40,7 +40,7 @@ void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base,void watchdog_init (void );void set_muxconf_regs (void ); -u32 get_cpu_rev (void ); +u8 get_cpu_rev (void );u32 get_mem_type (void );u32 get_sysboot_value (void );u32 is_gpmc_muxed (void );
include/configs/omap3_beagle.h +2 -0
@@ -28,6 +28,8 @@#ifndef __CONFIG_H#define __CONFIG_H +#define CONFIG_ARCH_CPU_INIT 1 +/* * High Level Configuration Options */
include/configs/omap3_evm.h +2 -0
@@ -33,6 +33,8 @@#ifndef __CONFIG_H#define __CONFIG_H +#define CONFIG_ARCH_CPU_INIT 1 +/* * High Level Configuration Options */
include/configs/omap3_overo.h +2 -0
@@ -20,6 +20,8 @@#ifndef __CONFIG_H#define __CONFIG_H +#define CONFIG_ARCH_CPU_INIT 1 +/* * High Level Configuration Options */
include/configs/omap3_pandora.h +2 -0
@@ -23,6 +23,8 @@#ifndef __CONFIG_H#define __CONFIG_H +#define CONFIG_ARCH_CPU_INIT 1 +/* * High Level Configuration Options */
include/configs/omap3_zoom1.h +2 -0
@@ -29,6 +29,8 @@#ifndef __CONFIG_H#define __CONFIG_H +#define CONFIG_ARCH_CPU_INIT 1 +/* * High Level Configuration Options */
include/configs/omap3_zoom2.h +2 -0
@@ -30,6 +30,8 @@#ifndef __CONFIG_H#define __CONFIG_H +#define CONFIG_ARCH_CPU_INIT 1 +/* * High Level Configuration Options */
Signature · 1 line
1.6.2.2
PATCH 2/2 omap3: Identify cpu in s_init()
In reply to Sanjeev PremiWhen s_init() is called, the silicon version hasn't yet been identified. This would lead to incorrect index in the DPLL table.
This patch ensures that silicon is identified as first step in s_init().
When called from s_init(), the globals updated in the function identify_cpu() lie in 'relocated' address space.
So, identify_cpu() is called again in arch_cpu_init().
--- cpu/arm_cortexa8/omap3/board.c | 2 ++ cpu/arm_cortexa8/omap3/sys_info.c | 17 +++++++++++++++-- include/asm-arm/arch-omap3/sys_proto.h | 1 + 3 files changed, 18 insertions(+), 2 deletions(-)
cpu/arm_cortexa8/omap3/board.c +2 -0
@@ -193,6 +193,8 @@ void s_init(void) {int in_sdram =is_running_in_sdram (); +identify_cpu (); +watchdog_init ();try_unlock_memory ();
cpu/arm_cortexa8/omap3/sys_info.c +15 -2
@@ -44,11 +44,11 @@ static char *rev_s[CPU_3XX_MAX_REV] = {static u8 cpu_revision;/** -* Perform architecture specific initialization. +* Identify the silicon * * Currently, it identifies the cpu revision. */ -int arch_cpu_init (void ) +void identify_cpu (void ) {u32 cpuid =0 ;struct ctrl_id *id_base;
@@ -72,6 +72,19 @@ int arch_cpu_init (void)if (cpu_revision ==0 ) cpu_revision =CPU_3XX_ES20 ; } +} + +/** +* Perform architecture specific initialization +*/ +int arch_cpu_init (void ) +{ +/* +* The identification done in s_init is 'lost' due to +* relocation. The variable contents are not same. +* Function identify_cpu() is called again. +*/ +identify_cpu ();return 0 ; }
include/asm-arm/arch-omap3/sys_proto.h +1 -0
@@ -40,6 +40,7 @@ void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base,void watchdog_init (void );void set_muxconf_regs (void ); +void identify_cpu (void );u8 get_cpu_rev (void );u32 get_mem_type (void );u32 get_sysboot_value (void );
Signature · 1 line
1.6.2.2
cover omap3: Optimize detection of cpu revision
In reply to Sanjeev PremiQuoted 12 lines · Sanjeev Premi
Each call to
get_cpu_rev()leads to repetitive execution of code to detect the cpu revision.This patchset ensures that mechanism to detect revision is not executed each time; instead a stored value is returned.
Since, revision info is needed in
s_init(), the function to identify cpu revision needs to be called twice. At the moment, it is necessary/ unavoidable.
Is there some other reason to read this register only once? This function is not used frequently and i do not think the complexity of optimizing is necessary.
Tom
Premi
cover omap3: Optimize detection of cpu revision
Quoted 23 lines
-----Original Message-----
From: Tom [mailto:Tom.Rix at windriver.com]
Sent: Tuesday, December 15, 2009 10:44 PM
To: Premi, Sanjeev
Cc: u-boot at lists.denx.de
Subject: Re: [U-Boot] [PATCH 0/2] omap3: Optimize detection of cpu revisionQuoted 12 lines · Sanjeev Premi
Each call to
get_cpu_rev()leads to repetitive execution of code to detect the cpu revision.This patchset ensures that mechanism to detect revision is not executed each time; instead a stored value is returned.
Since, revision info is needed in
s_init(), the function to identify cpu revision needs to be called twice. At the moment, it is necessary/ unavoidable.
Quoted 3 lines
Is there some other reason to read this register only once? This function is not used frequently and i do not think the complexity of optimizing is necessary.
As more processors and revision specific code gets added, there will be more occurrences for this check.
I have just posted patches for basic support for the AM35x processors. Now, the cpurev for this silicon is ES1.0; but have otherwise similar features that the OMAP35x ES3.1 si (I am not accounting other IP differences between the processors here).
Also, I don't believe there is any complexity added as the contents of register are being read and saved in a global variable for use later.
Best regards,
Sanjeev
Quoted 3 lines
Tom
cover omap3: Optimize detection of cpu revision
Dear "Premi, Sanjeev",
Quoted 4 lines · In message <[email protected]> you…
Also, I don't believe there is any complexity added as the contents of register are being read and saved in a global variable for use later.
Global variables are a bad thing if there is not really a good reason to hav ethem. Here it makes no sense to me. Execution time seems uncritical, and there is no kind of hardware wear involved with readin the registers, so like Tom I don't see a reason for this "optimization".
Best regards,
Wolfgang Denk
Signature · 4 lines
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de How does a project get to be a year late? ... One day at a time.
Premi
cover omap3: Optimize detection of cpu revision
In reply to Sanjeev PremiQuoted 23 lines
-----Original Message-----
From: Premi, Sanjeev
Sent: Tuesday, December 15, 2009 6:48 PM
To: u-boot at lists.denx.de
Cc: Premi, Sanjeev
Subject: [PATCH 0/2] omap3: Optimize detection of cpu revisionEach call to
get_cpu_rev()leads to repetitive execution of code to detect the cpu revision.This patchset ensures that mechanism to detect revision is not executed each time; instead a stored value is returned.
Since, revision info is needed in
s_init(), the function to identify cpu revision needs to be called twice. At the moment, it is necessary/ unavoidable.Sanjeev Premi (2):
omap3: Identify the CPU inarch_cpu_init()
omap3: Identify cpu ins_init()
Quoted 13 lines
cpu/arm_cortexa8/omap3/board.c | 2 + cpu/arm_cortexa8/omap3/sys_info.c | 73 ++++++++++++++++++++++---------- include/asm-arm/arch-omap3/sys_proto.h | 3 +- include/configs/omap3_beagle.h | 2 + include/configs/omap3_evm.h | 2 + include/configs/omap3_overo.h | 2 + include/configs/omap3_pandora.h | 2 + include/configs/omap3_zoom1.h | 2 + include/configs/omap3_zoom2.h | 2 + 9 files changed, 66 insertions(+), 24 deletions(-)
Sandeep, Tom,
Any comments on this series on your queue..
Best regards,
Sanjeev
Paulraj
cover omap3: Optimize detection of cpu revision
Quoted 39 lines
Quoted 25 lines
-----Original Message-----
From: Premi, Sanjeev
Sent: Tuesday, December 15, 2009 6:48 PM
To: u-boot at lists.denx.de
Cc: Premi, Sanjeev
Subject: [PATCH 0/2] omap3: Optimize detection of cpu revisionEach call to
get_cpu_rev()leads to repetitive execution of code to detect the cpu revision.This patchset ensures that mechanism to detect revision is not executed each time; instead a stored value is returned.
Since, revision info is needed in
s_init(), the function to identify cpu revision needs to be called twice. At the moment, it is necessary/ unavoidable.Sanjeev Premi (2):
omap3: Identify the CPU inarch_cpu_init()
omap3: Identify cpu ins_init()Quoted 13 lines
cpu/arm_cortexa8/omap3/board.c | 2 + cpu/arm_cortexa8/omap3/sys_info.c | 73 ++++++++++++++++++++++---------- include/asm-arm/arch-omap3/sys_proto.h | 3 +- include/configs/omap3_beagle.h | 2 + include/configs/omap3_evm.h | 2 + include/configs/omap3_overo.h | 2 + include/configs/omap3_pandora.h | 2 + include/configs/omap3_zoom1.h | 2 + include/configs/omap3_zoom2.h | 2 + 9 files changed, 66 insertions(+), 24 deletions(-)
Quoted 3 lines
Sandeep, Tom,
Any comments on this series on your queue..
Sanjeev,
Wolfgang had some comments on this.
http://www.mail-archive.com/u-boot at lists.denx.de/msg26568.html
Quoted 7 lines
Best regards,
Sanjeev
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot
Premi
cover omap3: Optimize detection of cpu revision
Quoted 47 lines
-----Original Message-----
From: Paulraj, Sandeep
Sent: Thursday, January 07, 2010 9:02 PM
To: Premi, Sanjeev; u-boot at lists.denx.de
Subject: RE: [PATCH 0/2] omap3: Optimize detection of cpu revisionQuoted 40 lines
Quoted 24 lines
-----Original Message-----
From: Premi, Sanjeev
Sent: Tuesday, December 15, 2009 6:48 PM
To: u-boot at lists.denx.de
Cc: Premi, Sanjeev
Subject: [PATCH 0/2] omap3: Optimize detection of cpu revisionEach call to
get_cpu_rev()leads to repetitive execution of code to detect the cpu revision.This patchset ensures that mechanism to detect revision is not executed each time; instead a stored value is returned.
Since, revision info is needed in
s_init(), the function to identify cpu revision needs to be called twice. At the moment, it is necessary/ unavoidable.Sanjeev Premi (2):
omap3: Identify the CPU inarch_cpu_init()
omap3: Identify cpu ins_init()Quoted 13 lines
cpu/arm_cortexa8/omap3/board.c | 2 + cpu/arm_cortexa8/omap3/sys_info.c | 73 ++++++++++++++++++++++---------- include/asm-arm/arch-omap3/sys_proto.h | 3 +- include/configs/omap3_beagle.h | 2 + include/configs/omap3_evm.h | 2 + include/configs/omap3_overo.h | 2 + include/configs/omap3_pandora.h | 2 + include/configs/omap3_zoom1.h | 2 + include/configs/omap3_zoom2.h | 2 + 9 files changed, 66 insertions(+), 24 deletions(-)Sandeep, Tom,
Quoted 7 lines
Quoted 1 line
Any comments on this series on your queue..
Sanjeev,
Wolfgang had some comments on this.
http://www.mail-archive.com/u-boot at lists.denx.de/msg26568.html
Sorry missed that one.
Will respond.
~sanjeev
Quoted 9 lines
Quoted 8 lines
Best regards,
Sanjeev
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot
Premi
cover omap3: Optimize detection of cpu revision
In reply to PaulrajQuoted 45 lines
-----Original Message-----
From: Paulraj, Sandeep
Sent: Thursday, January 07, 2010 9:02 PM
To: Premi, Sanjeev; u-boot at lists.denx.de
Subject: RE: [PATCH 0/2] omap3: Optimize detection of cpu revisionQuoted 40 lines
Quoted 24 lines
-----Original Message-----
From: Premi, Sanjeev
Sent: Tuesday, December 15, 2009 6:48 PM
To: u-boot at lists.denx.de
Cc: Premi, Sanjeev
Subject: [PATCH 0/2] omap3: Optimize detection of cpu revisionEach call to
get_cpu_rev()leads to repetitive execution of code to detect the cpu revision.This patchset ensures that mechanism to detect revision is not executed each time; instead a stored value is returned.
Since, revision info is needed in
s_init(), the function to identify cpu revision needs to be called twice. At the moment, it is necessary/ unavoidable.Sanjeev Premi (2):
omap3: Identify the CPU inarch_cpu_init()
omap3: Identify cpu ins_init()Quoted 13 lines
cpu/arm_cortexa8/omap3/board.c | 2 + cpu/arm_cortexa8/omap3/sys_info.c | 73 ++++++++++++++++++++++---------- include/asm-arm/arch-omap3/sys_proto.h | 3 +- include/configs/omap3_beagle.h | 2 + include/configs/omap3_evm.h | 2 + include/configs/omap3_overo.h | 2 + include/configs/omap3_pandora.h | 2 + include/configs/omap3_zoom1.h | 2 + include/configs/omap3_zoom2.h | 2 + 9 files changed, 66 insertions(+), 24 deletions(-)Sandeep, Tom,
Quoted 8 lines
Quoted 1 line
Any comments on this series on your queue..
Sanjeev,
Wolfgang had some comments on this.
http://www.mail-archive.com/u-boot at lists.denx.de/msg26568.html
Did not find this mail in my inbox (may be reason to miss it earlier). Anyway, pasting it below to maintain context:
Quoted 9 lines
Dear "Premi, Sanjeev",
In message <[email protected]>
Quoted 4 lines · you
Also, I don't believe there is any complexity added as the contents of register are being read and saved in a global variable for use later.
Quoted 5 lines
Global variables are a bad thing if there is not really a good reason to hav ethem. Here it makes no sense to me. Execution time seems uncritical, and there is no kind of hardware wear involved with readin the registers, so like Tom I don't see a reason for this "optimization".
Tom, Denx,
As this patch stands, there isn't much code to optimize; but the change was meant as enabler for the next set of processors. The register and mechanism is same ...just interpretation will differ.
There is already a patchset for AM35x devices and there will new patches for OMAP36x.
Also, I believe faster execution time is always better; not just in critical sections of code. I possibly used "global" quite loosely; while responding earlier. The variable cpu_revision (being discussed) here is actually a 'static'. (See patch 1/2).
But, if we feel otherwise, I can revert to executing detection mechanism each time in the function.
However, are their any comments on remainder of the patch e.g. moving the cpu identification eary in the u-boot exectuion. The DPLL settings etc will depend upon the si identification.
Best regards,
Sanjeev
Quoted 3 lines
Best regards,
Wolfgang Denk
Best regards,
Sanjeev
Quoted 8 lines
Quoted 7 lines
Best regards,
Sanjeev
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot
cover omap3: Optimize detection of cpu revision
Quoted 81 lines · Sanjeev
Quoted 41 lines
-----Original Message-----
From: Paulraj, Sandeep
Sent: Thursday, January 07, 2010 9:02 PM
To: Premi, Sanjeev; u-boot at lists.denx.de
Subject: RE: [PATCH 0/2] omap3: Optimize detection of cpu revisionQuoted 36 lines
Quoted 36 lines
-----Original Message-----
From: Premi, Sanjeev
Sent: Tuesday, December 15, 2009 6:48 PM
To: u-boot at lists.denx.de
Cc: Premi, Sanjeev
Subject: [PATCH 0/2] omap3: Optimize detection of cpu revisionEach call to
get_cpu_rev()leads to repetitive execution of code to detect the cpu revision.This patchset ensures that mechanism to detect revision is not executed each time; instead a stored value is returned.
Since, revision info is needed in
s_init(), the function to identify cpu revision needs to be called twice. At the moment, it is necessary/ unavoidable.Sanjeev Premi (2):
omap3: Identify the CPU inarch_cpu_init()
omap3: Identify cpu ins_init()cpu/arm_cortexa8/omap3/board.c | 2 + cpu/arm_cortexa8/omap3/sys_info.c | 73 ++++++++++++++++++++++---------- include/asm-arm/arch-omap3/sys_proto.h | 3 +- include/configs/omap3_beagle.h | 2 + include/configs/omap3_evm.h | 2 + include/configs/omap3_overo.h | 2 + include/configs/omap3_pandora.h | 2 + include/configs/omap3_zoom1.h | 2 + include/configs/omap3_zoom2.h | 2 + 9 files changed, 66 insertions(+), 24 deletions(-)Quoted 9 lines
Quoted 3 lines
Sandeep, Tom,
Any comments on this series on your queue..
Sanjeev,
Wolfgang had some comments on this.
http://www.mail-archive.com/u-boot at lists.denx.de/msg26568.html
Did not find this mail in my inbox (may be reason to miss it earlier). Anyway, pasting it below to maintain context:
Quoted 4 lines
Dear "Premi, Sanjeev",
In message <[email protected]> you wrote:
Quoted 8 lines
Quoted 3 lines
Also, I don't believe there is any complexity added as the contents of register are being read and saved in a global variable for use later.
Global variables are a bad thing if there is not really a good reason to hav ethem. Here it makes no sense to me. Execution time seems uncritical, and there is no kind of hardware wear involved with readin the registers, so like Tom I don't see a reason for this "optimization".
Tom, Denx,
As this patch stands, there isn't much code to optimize; but the change was meant as enabler for the next set of processors. The register and mechanism is same ...just interpretation will differ.
There is already a patchset for AM35x devices and there will new patches for OMAP36x.
Also, I believe faster execution time is always better; not just in critical sections of code. I possibly used "global" quite loosely; while responding earlier. The variable
cpu_revision(being discussed) here is actually a 'static'. (See patch 1/2).
Quoted 7 lines
But, if we feel otherwise, I can revert to executing detection mechanism each time in the function.
However, are their any comments on remainder of the patch e.g. moving the cpu identification eary in the u-boot exectuion. The DPLL settings etc will depend upon the si identification.
I am not in favor of the patch.
Please remove it and rework your patchset.
Tom
Quoted 19 lines
Best regards,
SanjeevQuoted 2 lines
Best regards,
Wolfgang DenkBest regards,
SanjeevQuoted 6 lines
Quoted 6 lines
Best regards,
Sanjeev
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot
cover omap3: Optimize detection of cpu revision
In reply to PremiDear Sanjeev,
Quoted 5 lines · in message <[email protected]> you…
Also, I believe faster execution time is always better; not just in critical sections of code. I possibly used "global" quite loosely; while responding earlier. The variable
cpu_revision(being discussed) here is actually a 'static'. (See patch 1/2).
So how much faster is reading this variable compared to reading from the register?
Can you really measure _any_ difference?
Quoted 2 lines
But, if we feel otherwise, I can revert to executing detection mechanism each time in the function.
Please undo this.
Best regards,
Wolfgang Denk
Signature · 5 lines
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Ernest asks Frank how long he has been working for the company.
"Ever since they threatened to fire me."