linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Ryan Mallon <ryan@bluewatersys.com>
To: Alexey Charkov <alchark@gmail.com>
Cc: "Russell King - ARM Linux" <linux@arm.linux.org.uk>,
	linux-arm-kernel@lists.infradead.org,
	vt8500-wm8505-linux-kernel@googlegroups.com,
	"Eric Miao" <eric.y.miao@gmail.com>,
	"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
	"Albin Tonnerre" <albin.tonnerre@free-electrons.com>,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 1/6 v9] ARM: Add basic architecture support for VIA/WonderMedia 85xx SoC's
Date: Tue, 21 Dec 2010 11:23:03 +1300	[thread overview]
Message-ID: <4D0FD747.9020700@bluewatersys.com> (raw)
In-Reply-To: <AANLkTin4XqbGwznp56Xjt_zest6rxNmir0QDJWTySY4+@mail.gmail.com>

On 12/21/2010 10:48 AM, Alexey Charkov wrote:
> 2010/12/20 Ryan Mallon <ryan@bluewatersys.com>:
>> On 12/21/2010 08:54 AM, Alexey Charkov wrote:
>>> This adds support for the family of Systems-on-Chip produced initially
>>> by VIA and now its subsidiary WonderMedia that have recently become
>>> widespread in lower-end Chinese ARM-based tablets and netbooks.
>>>
>>> Support is included for both VT8500 and WM8505, selectable by a
>>> configuration switch at kernel build time.
>>>
>>> Included are basic machine initialization files, register and
>>> interrupt definitions, support for the on-chip interrupt controller,
>>> high-precision OS timer, GPIO lines, necessary macros for early debug,
>>> pulse-width-modulated outputs control, as well as platform device
>>> configurations for the specific drivers implemented elsewhere.
>>>
>>> Signed-off-by: Alexey Charkov <alchark@gmail.com>
>>
>> Hi Alexey,
>>
>> Quick review below.

> <snip>
>>> +void __init wmt_set_resources(void)
>>> +{
>>> +     resources_lcdc[0].start = wmt_current_regs->lcdc;
>>> +     resources_lcdc[0].end = wmt_current_regs->lcdc + SZ_1K - 1;
>>> +     resources_lcdc[1].start = wmt_current_irqs->lcdc;
>>> +     resources_lcdc[1].end = wmt_current_irqs->lcdc;
>>
>> Ah, this makes more sense. But why have all the indirection? The
>> wmt_regmaps table could just be replaced with #defines and then have
>> separate device files for the VT8500 and the WM8505. This would also
>> make clearer which variants have which peripherals.
>>
> 
> This was the way I implemented it originally. However, Arnd made quite
> a valid suggestion to allow runtime selection of the chip variant,
> thus registers and interrupts need to be held in an indexed data type
> instead of just compile-time macros. In addition, there is now some
> overall movement towards unification of binary kernel images for
> different ARM variants (as far as I can see), so this would be
> required in any case.
> 
> Furthermore, as with many unbranded Chinese products, it's somewhat
> difficult to reliably determine the exact chip version used in your
> netbook without disassembling it. Reading a hardware register for
> identification is easier :)

Okay, that makes sense. I still think there must be a better way than
having a massive indirect table with all the values. Why not detect the
variant in the core code and then have something like:

int init_devices(void)
{
	int board_type = detect_board_type();

	switch (board_type) {
	case BOARD_TYPE_VT8500:
		return vt8500_init_devices();

	case BOARD_TYPE_WM8505:
		return wm8500_init_devices();
	}

	pr_err("Unknown board type\n");
	BUG(); /* panic()? */
	while (1)
		;
}

Then you can have the peripheral setup for each of the variants in their
own files and use #defines. It may get tricky in a couple of places if
you need to be able to access some value directly which is different on
each of the variants, but that can be handled on a case by case basis.
The majority of the numbers will be passed into drivers via the resource
structs.

>>> +
>>> +void __init vt8500_map_io(void)
>>> +{
>>> +     wmt_current_regs = &wmt_regmaps[VT8500_INDEX];
>>> +     wmt_current_irqs = &wmt_irqs[VT8500_INDEX];
>>> +
>>> +     vt8500_io_desc[0].virtual = wmt_current_regs->mmio_regs_virt;
>>> +     vt8500_io_desc[0].pfn =
>>> +                     __phys_to_pfn(wmt_current_regs->mmio_regs_start);
>>> +     vt8500_io_desc[0].length = wmt_current_regs->mmio_regs_length;
>>> +
>>> +     iotable_init(vt8500_io_desc, ARRAY_SIZE(vt8500_io_desc));
>>> +}
>>> +
>>> +void __init wm8505_map_io(void)
>>> +{
>>> +     wmt_current_regs = &wmt_regmaps[WM8505_INDEX];
>>> +     wmt_current_irqs = &wmt_irqs[WM8505_INDEX];
>>> +
>>> +     vt8500_io_desc[0].virtual = wmt_current_regs->mmio_regs_virt;
>>> +     vt8500_io_desc[0].pfn =
>>> +                     __phys_to_pfn(wmt_current_regs->mmio_regs_start);
>>> +     vt8500_io_desc[0].length = wmt_current_regs->mmio_regs_length;
>>> +
>>> +     iotable_init(vt8500_io_desc, ARRAY_SIZE(vt8500_io_desc));
>>> +}
>>
>> Separate files. If more variants get added, this file will become
>> unwieldy very quickly.
>>
> 
> Is it really worthwhile to create separate files for single 12-line
> functions? After all, WonderMedia does not release new chips every now
> and then :)

I meant if you have the full peripheral initialisation for each variant
in its own file.

>>> +
>>> +void __init vt8500_reserve_mem(void)
>>> +{
>>> +#ifdef CONFIG_FB_VT8500
>>> +     panels[current_panel_idx].bpp = 16; /* Always use RGB565 */
>>> +     preallocate_fb(&panels[current_panel_idx], SZ_4M);
>>> +     vt8500_device_lcdc.dev.platform_data = &panels[current_panel_idx];
>>> +#endif
>>> +}
>>
>> Not sure if this should exist in the platform code or the framebuffer
>> driver. In the latter case it would automatically be CONFIG_FB_VT8500
>> and the platform_data can still be set in the platform code. Is there a
>> reason for this not to be in the framebuffer driver?
>>
> 
> I can't reserve memory via memblock from the driver, and usual runtime
> allocation functions can't handle it (need alignment to 4 megabytes in
> 8500, framebuffer sizes exceed 4 megabytes in 8505).

Can you use one of the initcalls from a driver to to the memblock
reserve? I don't know much about how memblock works. There are also the
various large page allocators in the works, but I don't think anything
has hit mainline yet.

>>> +#ifndef __ASM_ARCH_MEMORY_H
>>> +#define __ASM_ARCH_MEMORY_H
>>> +
>>> +/*
>>> + * Physical DRAM offset.
>>> + */
>>> +#define PHYS_OFFSET  UL(0x00000000)
>>
>> If you renamed this to PHYS_DRAM_OFFSET you wouldn't need the comment :-).
>>
> 
> I'm not the one who chooses :)

Oops, missed that :-).

>>> +void __init vt8500_init_irq(void)
>>> +{
>>> +     unsigned int i;
>>> +
>>> +     ic_regbase = ioremap(wmt_current_regs->ic0, SZ_64K);
>>> +
>>> +     if (ic_regbase) {
>>> +             /* Enable rotating priority for IRQ */
>>> +             writel((1 << 6), ic_regbase + 0x20);
>>> +             writel(0, ic_regbase + 0x24);
>>> +
>>> +             for (i = 0; i < wmt_current_irqs->nr_irqs; i++) {
>>> +                     /* Disable all interrupts and route them to IRQ */
>>> +                     writeb(0x00, ic_regbase + VT8500_IC_DCTR + i);
>>> +
>>> +                     set_irq_chip(i, &vt8500_irq_chip);
>>> +                     set_irq_handler(i, handle_level_irq);
>>> +                     set_irq_flags(i, IRQF_VALID);
>>> +             }
>>> +     } else {
>>> +             printk(KERN_ERR "Unable to remap the Interrupt Controller "
>>> +                             "registers, not enabling IRQs!\n");
>>
>> printk strings should be on a single line (can be > 80 columns) to make
>> grepping easier. You could also use the pr_ macros with pr_fmt set.
>>
> 
> Well, checkpatch.pl complained about that in the first place, so I
> split the line. Should I merge them back in all instances?

Yes. I think checkpatch has been changed to warn about spitting printk
strings across lines now.

> <snip>
> 
>>> diff --git a/arch/arm/mach-vt8500/pwm.c b/arch/arm/mach-vt8500/pwm.c
>>> new file mode 100644
>>> index 0000000..d1356a1
>>> --- /dev/null
>>> +++ b/arch/arm/mach-vt8500/pwm.c
>>
>> I'm not sure what the state of the various efforts to provide a common
>> pwm framework are, but you may want to check.
>>
> 
> I did before starting to write this code, found nothing.

Fair enough.

>>> +
>>> +static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask)
>>> +{
>>> +     int loops = 1000;
>>> +     while ((readb(reg) & bitmask) && --loops)
>>> +             cpu_relax();
>>
>> Ugh. If you are going to busy wait, can't you delay for a known amount
>> of time? Even better, can this be replaced with wait_event or some
>> equivalent?
>>
> 
> The delay should be on the order of several bus cycles, where udelay
> actually busy-waits, too. wait_event would be longer than that to set
> up, and there is no associated interrupt.

I meant if the hardware has some specific maximum wait time then you
could just delay that long. If there is no interrupt then wait_event and
friends probably aren't going to work.

Maybe convert this to a timed loop (i.e. 1 second timeout) using
jiffies. That way you are never dependent on cpu speed. You should
probably also emit a warning if the timeout is reached and the device
still claims to be busy.

>>> +}
>>> +
>>> +int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
>>> +{
>>> +     unsigned long long c;
>>> +     unsigned long period_cycles, prescale, pv, dc;
>>> +
>>> +     if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
>>> +             return -EINVAL;
>>> +
>>> +     c = 25000000/2; /* wild guess --- need to implement clocks */
>>> +     c = c * period_ns;
>>> +     do_div(c, 1000000000);
>>> +     period_cycles = c;
>>
>> This looks like it could be reworked to remove the do_div call.
>>
> 
> I just followed PXA implementation in this regard. Are there any
> specific suggestions? Note that c should not be a complie-time
> constant eventually, as this is the guessed PWM base frequency (should
> be read from the hardware, but the code for clocks is not yet in).

I didn't have a particular solution in mind, but often by changing the
units used and rearranging the math a bit you can often avoid having to
do horrible multiplies and divides.

For now at least you could avoid the do_div by assigning period_cycles
directly.

>>> +struct pwm_device *pwm_request(int pwm_id, const char *label)
>>> +{
>>> +     struct pwm_device *pwm;
>>> +     int found = 0;
>>> +
>>> +     mutex_lock(&pwm_lock);
>>> +
>>> +     list_for_each_entry(pwm, &pwm_list, node) {
>>> +             if (pwm->pwm_id == pwm_id) {
>>> +                     found = 1;
>>> +                     break;
>>> +             }
>>> +     }
>>> +
>>> +     if (found) {
>>> +             if (pwm->use_count == 0) {
>>> +                     pwm->use_count++;
>>> +                     pwm->label = label;
>>> +             } else
>>> +                     pwm = ERR_PTR(-EBUSY);
>>> +     } else
>>> +             pwm = ERR_PTR(-ENOENT);
>>> +
>>> +     mutex_unlock(&pwm_lock);
>>> +     return pwm;
>>> +}
>>
>> Maybe a bit clearer and more concise like this? Also replaces -ENOENT
>> (No such file or directory) with -ENODEV (No such device):
>>
>>        pwm = ERR_PTR(-ENODEV);
>>        mutex_lock(&pwm_lock);
>>
>>        list_for_each_entry(pwm, &pwm_list, node) {
>>                if (pwm->pwm_id == pwm_id) {
>>                        if (pwm->use_count != 0) {
>>                                pwm = ERR_PTR(-EBUSY);
>>                                break;
>>                        }
>>
>>                        pwm->use_count++;
>>                        pwm->label = label;
>>                        break;
>>                }
>>        }
>>
>>        mutex_unlock(&pwm_lock);
>>        return pwm;
>>
> 
> Isn't pwm overwritten inside the loop? -ENODEV will then be lost with
> this layout.

Oops, yes. You would need a second temporary pwm for the list iterator.
It's not a big deal anyway, just though it could be made more concise by
having all the code inside the loop.

>>> +static int __devinit pwm_probe(struct platform_device *pdev)
>>> +{
>>> +     struct pwm_device *pwms;
>>> +     struct resource *r;
>>> +     int ret = 0;
>>> +     int i;
>>> +
>>> +     pwms = kzalloc(sizeof(struct pwm_device) * VT8500_NR_PWMS, GFP_KERNEL);
>>> +     if (pwms == NULL) {
>>> +             dev_err(&pdev->dev, "failed to allocate memory\n");
>>> +             return -ENOMEM;
>>> +     }
>>
>> Devices should ideally be a single entity, so one platform device per pwm.
>>
> 
> We have 4 pwm outputs that share status registers, so they are not
> really separable.

Okay.

<snip>

>>> +static void vt8500_power_off(void)
>>> +{
>>> +     local_irq_disable();
>>
>> Is this necessary?
>>
> 
> Vendor's code disables interrupts. I believe my device refused to
> actually switch off without this.

Okay, fair enough.

> Thanks for the comments, Ryan!

No problem.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan@bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

  reply	other threads:[~2010-12-20 22:21 UTC|newest]

Thread overview: 91+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-11-07 16:28 [PATCH 1/6 v2] ARM: Add basic architecture support for VIA/WonderMedia 85xx SoC's Alexey Charkov
2010-11-07 16:28 ` [PATCH 2/6 v2] serial: Add support for UART on VIA VT8500 and compatibles Alexey Charkov
2010-11-07 23:08   ` Alan Cox
2010-11-08  0:58     ` [PATCH 2/6 v3] " Alexey Charkov
2010-11-08 10:46       ` Alan Cox
2010-11-08 17:33         ` [PATCH 2/6 v4] " Alexey Charkov
2010-11-07 16:28 ` [PATCH 3/6 v2] input: Add support for VIA VT8500 and compatibles in i8042 Alexey Charkov
2010-11-12 22:54   ` Alexey Charkov
2010-11-12 23:30     ` Dmitry Torokhov
2010-11-13  0:00       ` Alexey Charkov
2010-12-22 21:41       ` [PATCH 3/6 v3] " Alexey Charkov
2010-11-07 16:28 ` [PATCH 4/6 v2] usb: Add support for VIA VT8500 and compatibles in EHCI HCD Alexey Charkov
2010-11-07 16:28 ` [PATCH 5/6 v2] rtc: Add support for the RTC in VIA VT8500 and compatibles Alexey Charkov
2010-11-12 22:53   ` Alexey Charkov
2010-11-13 12:14   ` Lars-Peter Clausen
2010-11-13 23:56     ` [PATCH 5/6 v3] " Alexey Charkov
2010-11-14 15:50       ` Lars-Peter Clausen
2010-11-14 17:00         ` [PATCH 5/6 v4] " Alexey Charkov
2010-11-23 19:17           ` Alexey Charkov
2010-11-24 19:23             ` Lars-Peter Clausen
2010-11-24 22:47               ` [PATCH 5/6 v5] " Alexey Charkov
2010-11-07 16:28 ` [PATCH 6/6 v2] ARM: Add support for the display controllers in VT8500 and WM8505 Alexey Charkov
2010-11-08  4:17   ` Paul Mundt
2010-11-08 12:56     ` Alexey Charkov
2010-11-08 14:14     ` [PATCH 6/6 v3] " Alexey Charkov
2010-11-08 20:43       ` Paul Mundt
2010-11-08 21:15         ` Alexey Charkov
2010-11-08 21:30           ` Paul Mundt
2010-11-08 23:42             ` [PATCH 6/6 v4] " Alexey Charkov
2010-11-08 23:54               ` Paul Mundt
2010-11-09  0:03                 ` Alexey Charkov
2010-11-09  7:36                   ` Guennadi Liakhovetski
2010-11-09  9:39                   ` Paul Mundt
2010-11-09  9:49                     ` Alexey Charkov
2010-11-09 10:33         ` [PATCH 6/6 v3] " Russell King - ARM Linux
2010-11-09 10:51           ` Paul Mundt
2010-11-09 11:04             ` Russell King - ARM Linux
2010-11-09 13:02               ` Geert Uytterhoeven
2010-11-09 13:33                 ` Arnd Bergmann
2010-11-09 16:20                   ` Paul Mundt
2010-11-08  8:47   ` [PATCH 6/6 v2] " Arnd Bergmann
2010-11-09 10:23     ` Alexey Charkov
2010-11-09 15:03       ` Arnd Bergmann
2010-11-07 16:57 ` [PATCH 1/6 v2] ARM: Add basic architecture support for VIA/WonderMedia 85xx SoC's Russell King - ARM Linux
2010-11-07 17:08   ` Alexey Charkov
2010-11-07 17:17     ` Russell King - ARM Linux
2010-11-07 18:25       ` [PATCH 1/6 v3] " Alexey Charkov
2010-11-08 17:19       ` [PATCH 1/6 v4] " Alexey Charkov
2010-11-10 15:16         ` saeed bishara
2010-11-10 15:18           ` Russell King - ARM Linux
2010-11-10 15:20             ` saeed bishara
2010-11-11 21:23         ` [PATCH 1/6 v5] " Alexey Charkov
2010-11-11 23:49           ` Russell King - ARM Linux
2010-11-12 16:54             ` [PATCH 1/6 v6] " Alexey Charkov
2010-11-12 20:14               ` Alexey Charkov
2010-11-23 19:50             ` [PATCH 1/6 v7] " Alexey Charkov
2010-12-19 17:40             ` [PATCH 1/6 v8] " Alexey Charkov
2010-12-20 18:15               ` Arnd Bergmann
2010-12-20 19:15               ` Russell King - ARM Linux
2010-12-20 19:26                 ` Alexey Charkov
2010-12-20 19:54                 ` [PATCH 1/6 v9] " Alexey Charkov
2010-12-20 20:50                   ` Ryan Mallon
2010-12-20 21:48                     ` Alexey Charkov
2010-12-20 22:23                       ` Ryan Mallon [this message]
2010-12-20 23:00                         ` Alexey Charkov
2010-12-20 23:22                           ` Ryan Mallon
2010-12-20 23:49                             ` Alexey Charkov
2010-12-21  0:09                               ` Alexey Charkov
2010-12-21  2:32                               ` Ryan Mallon
2010-12-21 10:00                                 ` Alexey Charkov
2010-12-21 12:05                                   ` Arnd Bergmann
2010-12-21 19:39                                   ` Ryan Mallon
2010-12-22 21:18                                     ` [PATCH 1/6 v10] " Alexey Charkov
2010-12-22 21:52                                       ` Ryan Mallon
2010-12-22 22:02                                         ` Alexey Charkov
2010-12-22 22:32                                           ` Ryan Mallon
2010-12-22 22:25                                         ` [PATCH 1/6 v11] " Alexey Charkov
2010-12-22 22:59                                           ` Ryan Mallon
2010-12-22 23:38                                             ` [PATCH 1/6 v12] " Alexey Charkov
2010-12-28 14:52                                               ` Alexey Charkov
2011-01-15  0:53                                                 ` Alexey Charkov
2011-01-15  0:58                                                   ` Russell King - ARM Linux
2011-01-15  1:13                                                     ` Alexey Charkov
2011-01-21 10:43                                                       ` Russell King - ARM Linux
2011-07-06 12:34               ` [PATCH 1/6 v8] " Russell King - ARM Linux
2011-07-07  7:13                 ` Alexey Charkov
2011-07-07  7:54                   ` Arnd Bergmann
2011-07-07  7:59                     ` Russell King - ARM Linux
2011-07-07  8:05                       ` Arnd Bergmann
2010-11-07 17:00 ` [PATCH 1/6 v2] " Russell King - ARM Linux
2010-11-07 17:16   ` Alexey Charkov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4D0FD747.9020700@bluewatersys.com \
    --to=ryan@bluewatersys.com \
    --cc=albin.tonnerre@free-electrons.com \
    --cc=alchark@gmail.com \
    --cc=eric.y.miao@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@arm.linux.org.uk \
    --cc=u.kleine-koenig@pengutronix.de \
    --cc=vt8500-wm8505-linux-kernel@googlegroups.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).