[U-Boot] [PATCH] inka4x0: Add hardware diagnosis functions for inka4x0
Detlev Zundel
dzu at denx.de
Wed Mar 25 16:07:21 CET 2009
Hi Wolfgang,
> Dear Detlev Zundel,
>
> In message <1237914158-15693-6-git-send-email-dzu at denx.de> you wrote:
>> This patch adds advanced diagnosis functions for the inka4x0 board.
>>
>> Signed-off-by: Andreas Pfefferle <ap at denx.de>
>> Signed-off-by: Detlev Zundel <ap at denx.de>
> ...
>> + extern int inkadiag_init_r (void);
>> + /*
>> + * The command table used for the subcommands of inkadiag
>> + * needs to be relocated manually.
>> + */
>
> Incorrect multiline comment style?
Nothing escapes the eye of an eagle ;)
>> +}
>> +
>> int misc_init_f (void)
>> {
>> char tmp[10];
>> diff --git a/board/inka4x0/inkadiag.c b/board/inka4x0/inkadiag.c
>> new file mode 100644
>> index 0000000..bdbf652
> ...
>> +#define LED_HIGH(NUM) \
>> + do { \
>> + out_be32((unsigned *)MPC5XXX_GPT##NUM##_ENABLE, \
>> + in_be32((unsigned *)MPC5XXX_GPT##NUM##_ENABLE) | 0x10); \
>> + } while (0)
>
> Please use:
>
> setbits_be32 ((unsigned *)MPC5XXX_GPT##NUM##_ENABLE, 0x10);
>
> instead (and so on in the rest of the code).
Done.
>> + struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio *)MPC5XXX_GPIO;
>> + if (which == 1) {
>> + /* drawer1 */
>> + if (state) {
>> + gpio->simple_dvo &= ~0x1000;
>> + udelay(1);
>> + gpio->simple_dvo |= 0x1000;
>> + } else {
>> + gpio->simple_dvo |= 0x1000;
>> + udelay(1);
>> + gpio->simple_dvo &= ~0x1000;
>> + }
>> + }
>> + if (which == 2) {
>> + /* drawer 2 */
>> + if (state) {
>> + gpio->simple_dvo &= ~0x2000;
>> + udelay(1);
>> + gpio->simple_dvo |= 0x2000;
>> + } else {
>> + gpio->simple_dvo |= 0x2000;
>> + udelay(1);
>> + gpio->simple_dvo &= ~0x2000;
>
> Please use accessor functions to write to I/O ports.
Fixed.
>> +static int ser_init(volatile struct mpc5xxx_psc *psc, int baudrate)
>> +{
>> + unsigned long baseclk;
>> + int div;
>> +
>> + /* reset PSC */
>> + psc->command = PSC_SEL_MODE_REG_1;
>
> Should we not use accessor function to access the device registers
> (here and in the following code) ?
Indeed we should. But here we go, I can understand, why this wasn't
done the first time around. The new code looks like this:
/* reset PSC */
out_8(&psc->command, PSC_SEL_MODE_REG_1);
/* select clock sources */
out_be16(&psc->psc_clock_select, 0);
baseclk = (gd->ipb_clk + 16) / 32;
/* switch to UART mode */
out_be32(&psc->sicr, 0);
/* configure parity, bit length and so on */
out_8(&psc->mode, PSC_MODE_8_BITS | PSC_MODE_PARNONE);
out_8(&psc->mode, PSC_MODE_ONE_STOP);
/* set up UART divisor */
div = (baseclk + (baudrate / 2)) / baudrate;
out_8(&psc->ctur, (div >> 8) & 0xff);
out_8(&psc->ctlr, div & 0xff);
/* disable all interrupts */
out_be16(&psc->psc_imr, 0);
/* reset and enable Rx/Tx */
out_8(&psc->command, PSC_RST_RX);
out_8(&psc->command, PSC_RST_TX);
out_8(&psc->command, PSC_RX_ENABLE | PSC_TX_ENABLE);
Look at the wonderful mix of out_{8,be16,be32}. What a heart refreshing
break from the monotonic coding routine :(
Actully this is due to to mpc5xxx.h:
struct mpc5xxx_psc {
volatile u8 mode; /* PSC + 0x00 */
volatile u8 reserved0[3];
union { /* PSC + 0x04 */
volatile u16 status;
volatile u16 clock_select;
} sr_csr;
#define psc_status sr_csr.status
#define psc_clock_select sr_csr.clock_select
volatile u16 reserved1;
volatile u8 command; /* PSC + 0x08 */
volatile u8 reserved2[3];
union { /* PSC + 0x0c */
volatile u8 buffer_8;
volatile u16 buffer_16;
volatile u32 buffer_32;
} buffer;
#define psc_buffer_8 buffer.buffer_8
#define psc_buffer_16 buffer.buffer_16
#define psc_buffer_32 buffer.buffer_32
union { /* PSC + 0x10 */
volatile u8 ipcr;
volatile u8 acr;
} ipcr_acr;
#define psc_ipcr ipcr_acr.ipcr
#define psc_acr ipcr_acr.acr
volatile u8 reserved3[3];
union { /* PSC + 0x14 */
volatile u16 isr;
volatile u16 imr;
} isr_imr;
Git-blame points the finger to someone called 'wd'. Maybe he knows
about the advantages of such structure definitions?
On second check the corresponding header file in Linux (mpc52xx_uart.h) has
stuff like this introduced by Kumar Gala, maybe he can enlighten me?
To be honest, I wouldn't even dare accessing memory mapped registers in
the non-native size, but maybe I'm missing something here.
>> +static int do_inkadiag_serial(cmd_tbl_t *cmdtp, int flag, int argc,
>> + char *argv[]) {
>> + if (argc < 5) {
>> + cmd_usage(cmdtp);
>> + return 1;
>> + }
>> +
>> + argc--;
>> + argv++;
>> +
>> + unsigned int num = simple_strtol(argv[0], NULL, 0);
>
> Please NEVER declare variables right in the middle of the code!!
I won't, I PROMISE.
> Did this actually pass a compile test?
Heck, do you think I dare send a patch without compiling?
>> + if (mode & 4) {
>> + /* set data terminal ready */
>> + serial_out(num, UART_MCR, UART_MCR_DTR);
>> + udelay(10);
>> + /* check data set ready and carrier detect */
>> + if ((serial_in(num, UART_MSR) &
>> + (UART_MSR_DSR | UART_MSR_DCD))
>> + != (UART_MSR_DSR | UART_MSR_DCD))
>> + return -1;
>> + }
>> +
>> + /* write each message-character, read it back, and display it */
>> + int i, len = strlen(argv[3]);
>
> Ditto. Please make sure to fix this globally.
I believe I succeeded.
>> + for (i = 0; i < len; ++i) {
>> + int j = 0;
>> + while ((serial_in(num, UART_LSR) & UART_LSR_THRE) ==
>> + 0x00) {
>
> This is actually difficult to read. Please reconsider indentation /
> line wrapping / adding a blank line.
The switch to using struct NS16650 allowed for nicer layout without
violating line length.
>> + if (j++ > CONFIG_SYS_HZ)
>> + break;
>> + udelay(10);
>> + }
>> + unsigned char data = serial_in(num, UART_RX);
>> + printf("%c", data);
>> + }
>> + printf("\n\n");
>> + serial_out(num, UART_MCR, 0x00);
>> + } else {
>> + int address = 0;
>> + int irq;
>> +
>> + switch (num) {
>> + case 8:
>> + address = MPC5XXX_PSC6;
>> + irq = MPC5XXX_PSC6_IRQ;
>> + break;
>> + case 9:
>> + address = MPC5XXX_PSC3;
>> + irq = MPC5XXX_PSC3_IRQ;
>> + break;
>> + case 10:
>> + address = MPC5XXX_PSC2;
>> + irq = MPC5XXX_PSC2_IRQ;
>> + break;
>> + case 11:
>> + address = MPC5XXX_PSC1;
>> + irq = MPC5XXX_PSC1_IRQ;
>> + break;
>> + }
>
> "irq" seems to be unused (accept for the assignments) in this code.
> Wasn't there a compiler warning?
Nope.
>> +#define BUZZER_GPT (MPC5XXX_GPT + 0x60) /* GPT6 */
>> +static void buzzer_turn_on(unsigned int freq)
>> +{
>> + struct mpc5xxx_gpt *gpt = (struct mpc5xxx_gpt *)(BUZZER_GPT);
>> +
>> + const u32 prescale = gd->ipb_clk / freq / 128;
>> + const u32 count = 128;
>> + const u32 width = 64;
>> +
>> + gpt->cir = (prescale << 16) | count;
>> + gpt->pwmcr = width << 16;
>> + gpt->emsr = 3; /* Timer enabled for PWM */
>
> Accessor functions?
Yep.
>> +}
>> +
>> +static void buzzer_turn_off(void)
>> +{
>> + struct mpc5xxx_gpt *gpt = (struct mpc5xxx_gpt *)(BUZZER_GPT);
>> + gpt->emsr = 0;
>
> Accessor functions?
Again, not a question.
>> +}
>> +
>> +static int do_inkadiag_buzzer(cmd_tbl_t *cmdtp, int flag, int argc,
>> + char *argv[]) {
>> +
>> + if (argc != 3) {
>> + cmd_usage(cmdtp);
>> + return 1;
>> + }
>> +
>> + argc--;
>> + argv++;
>> +
>> + unsigned int period = simple_strtol(argv[0], NULL, 0);
>
> Declaration in the middle of the code.
Fixed.
>> + if (!period)
>> + printf("Zero period is senseless\n");
>> + argc--;
>> + argv++;
>> +
>> + unsigned int freq = simple_strtol(argv[0], NULL, 0);
>
> Declaration in the middle of the code.
What insolence! Fixed.
>> + /* avoid zero prescale in buzzer_turn_on() */
>> + if (freq > gd->ipb_clk / 128) {
>> + printf("%dHz exceeds maximum (%ldHz)\n", freq,
>> + gd->ipb_clk / 128);
>> + } else if (!freq)
>> + printf("Zero frequency is senseless\n");
>> + else
>> + buzzer_turn_on(freq);
>> +
>> + clear_ctrlc();
>> + int prev = disable_ctrlc(0);
>> +
>> + printf("Buzzing for %d ms. Type ^C to abort!\n\n", period);
>> +
>> + int i = 0;
>
> Declaration in the middle of the code.
Fixed.
>> + while (!ctrlc() && (i++ < CONFIG_SYS_HZ))
>> + udelay(period);
>> +
>> + clear_ctrlc();
>> + disable_ctrlc(prev);
>> +
>> + buzzer_turn_off();
>> +
>> + return 0;
>> +}
>> +
>> +static int do_inkadiag_help(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
>> +
>> +cmd_tbl_t cmd_inkadiag_sub[] = {
>> + U_BOOT_CMD_MKENT(io, 1, 1, do_inkadiag_io, "read digital input",
>> + "<drawer1|drawer2|other> [value] - get or set specified signal\n"),
>> + U_BOOT_CMD_MKENT(serial, 4, 1, do_inkadiag_serial, "test serial port",
>> + "<num> <mode> <baudrate> <msg> - test uart num [0..11] in mode\n"
>> + "and baudrate with msg\n"),
>> + U_BOOT_CMD_MKENT(buzzer, 2, 1, do_inkadiag_buzzer, "activate buzzer",
>> + "<period> <freq> - turn buzzer on for period ms with freq hz\n"),
>> + U_BOOT_CMD_MKENT(help, 4, 1, do_inkadiag_help, "get help",
>> + "[command] - get help for command\n"),
>> +};
>
> Lines too long.
Personally I do not think that the new version is any more readable. To
fix the "problem", I can split the string or violate indentation. As
the first seems very unattractive from a reading point of view, I
actually willingly decided for the latter. I hope you don't criticize
that in the next round.
>> +static int do_inkadiag_help(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) {
>> + extern int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp,
>> + int flag, int argc, char *argv[]);
>> + /* do_help prints command name - we prepend inkadiag to our subcommands! */
>
> Lines too long.
Again I believe the new version is harder to read, but I don't really
care.
Cheers
Detlev
--
We have a live-manual. It's called emacs-devel at gnu.org.
You can stick to just reading it, but you can skip to a specific chapter
by simply sending an email asking for it ;-)
-- Stefan Monnier
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-40 Fax: (+49)-8142-66989-80 Email: dzu at denx.de
More information about the U-Boot
mailing list