raspberrypi / linux

Kernel source tree for Raspberry Pi-provided kernel builds. Issues unrelated to the linux kernel should be posted on the community forum at https://forums.raspberrypi.com/
Other
11.02k stars 4.95k forks source link

ARCH_BCM270x: Moving more devices to DT #936

Closed notro closed 9 years ago

notro commented 9 years ago

This is a list of the devices in arch/arm/mach-bcm2709/bcm2709.c that isn't loaded through Device Tree:

I have made a patch for the following devices: bcm2708_fb_device, bcm2708_usb_device, bcm2708_alsa_devices[0-7], bcm2835_thermal_device Patch: https://gist.github.com/notro/882b88430626269d0572 (the patch is for Pi2 against rpi-4.0.y)

Audio: Should we use 2708 in the compatibility string to avoid a possible clash with a future mainline driver?

    audio@0 {
        compatible = "bcrm,bcm2835-audio";
        compatible = "bcrm,bcm2708-audio";
    };

Are these in use: bcm2708_systemtimer_device, bcm2708_powerman_device ?

I can make a PR if this is useful. Comments are welcome.

notro commented 9 years ago

Changing the usb driver removes the need to change dma-mapping.h:

-       buf = dma_to_virt(&urb->dev->dev, urb->transfer_dma);
+       buf = (void *)__bus_to_virt((unsigned long)urb->transfer_dma);

Next step is to find out why urb->transfer_buffer (buf) sometimes is NULL. Because include/linux/usb.h indicates that it should always be set:

 * @transfer_buffer:  This identifies the buffer to (or from) which the I/O
 *      request will be performed unless URB_NO_TRANSFER_DMA_MAP is set
 *      (however, do not leave garbage in transfer_buffer even then).
 *      This buffer must be suitable for DMA; allocate it with
 *      kmalloc() or equivalent.  For transfers to "in" endpoints, contents
 *      of this buffer will be modified.  This buffer is used for the data
 *      stage of control transfers.
popcornmix commented 9 years ago

Ping @P33M about dma_to_virt and urb->transfer_dma

P33M commented 9 years ago

The rationale behind the urb->transfer_dma and urb->transfer_buffer is here:

http://lxr.free-electrons.com/source/include/linux/usb.h#L1315

Perhaps this function may be of use (and avoids void * casts)

http://lxr.free-electrons.com/ident?i=usb_hcd_map_urb_for_dma

notro commented 9 years ago

usb_hcd_map_urb_for_dma

Usb core calls this function.

I have tracked down the issue to control messages that have no buffer. And clearly the new value that dwc_otg_urb_enqueue assignes to buf is wrong:

[    5.777776] usb_control_msg: data=  (null), size=0
[    5.807121]     usb_hcd_submit_urb: map and enqueue
[    5.837748] usb_hcd_map_urb_for_dma: buf=  (null), len=0, sgs=0, URB_NO_TRANSFER_DMA_MAP=0
[    5.867765]         usb_endpoint_xfer_control: uses_pio_for_control=0, uses_dma=1, HCD_LOCAL_MEM=0
[    5.900545]                 urb->setup_dma=0x5afafbe0, urb->transfer_dma=0x00000000
[    5.933451] usb 1-1: dwc_otg_urb_enqueue: buf is NULL, new buf=80000000, urb->transfer_dma=0x00000000

So I removed the (if clause and) statement: buf = dma_to_virt(...)

[    6.437742] usb 1-1.4: dwc_otg_urb_enqueue: buf is NULL, new buf=  (null), urb->transfer_dma=0x00000000

And no immediate ill effects. Network and keyboard is working.

@P33M comment?

notro commented 9 years ago

I hadn't fully surfaced when I wrote the previous post, just to be clear: urb->transfer_buffer (buf) might be used as-is (no need to use dma_to_virt).

notro commented 9 years ago

I have looked at all the places where transfer_dma is used, looking for situations where transfer_buffer might not be set. Since this is what the comment in dwc_otg_urb_enqueue() would indicate.

I found this drivers/usb/isp1760/isp1760-hcd.c (code is pre 2011):

1403         if (!urb->transfer_buffer && urb->transfer_buffer_length) {
1404                 /* XXX This looks like usb storage / SCSI bug */
1405                 dev_err(hcd->self.controller,
1406                                 "buf is null, dma is %08lx len is %d\n",
1407                                 (long unsigned)urb->transfer_dma,
1408                                 urb->transfer_buffer_length);
1409                 WARN_ON(1);
1410         }

transfer_buffer is also set to NULL in usb_sg_init() if scatter/gather is used. But drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c expressively disables this:

int hcd_init(dwc_bus_dev_t *_dev)
{
[...]
    hcd->self.sg_tablesize = 0;

So to stay safe, maybe something like this:

    if (hcd->self.uses_dma && !buf && urb->transfer_buffer_length) {
        buf = (void *)__bus_to_virt((unsigned long)urb->transfer_dma);
        dev_warn_once(&urb->dev->dev,
                  "USB transfer_buffer was NULL, will use __bus_to_virt(%pad)=%p\n",
                  &urb->transfer_dma, buf);
    }

__bus_to_virt might not work correctly on ARCH_BCM2835, so I would like to limit it's use.

notro commented 9 years ago

@anholt has made a firmware driver for accessing properties through the just accepted mailbox driver: [PATCH 2/3 v2] ARM: bcm2835: Add the Raspberry Pi firmware driver I took that driver and made it work with drivers/mailbox/bcm2708-vcio.c. The patch to do this is quite small: https://gist.github.com/notro/80347b194004109ca572

Included in that patch is a way to set Revision (/proc/cpuinfo) for ARCH_BCM2835, and to turn on USB power.

The patched firmware driver can also be used without Device Tree. I will make a PR when the firmware driver is accepted in mainline.

There is also a new Device Tree property to set Serial (/proc/cpuinfo) in linux-next: ARM: 8355/1: arch: Show the serial number from devicetree in cpuinfo I will pick this up later.

pelwell commented 9 years ago

It seems odd to use the property interface to query the board revision since it is already available from DT as "/system/linux,revision", which is set by the firmware.

Re: serial number - Does this mean they are abandoning "/system/linux,serial", which is also set by the firmware?

notro commented 9 years ago

I had forgotten about those properties entirely. Yes, it's better/faster to use "/system/linux,revision".

There was an attempt to get system_rev from DT: [PATCH v2 1/2] arm: devtree: Set system_rev from DT revision http://lists.infradead.org/pipermail/linux-arm-kernel/2015-February/326534.html

Does this mean they are abandoning "/system/linux,serial"

I don't know who you refer to as they, but the property is non-standard. So keeping it would mean carrying a kernel patch to read it.

pelwell commented 9 years ago

Is there a reason why you didn't include i2c-bcm2835 in this list? I'm not asking you to add it, but it would be useful for us on the Compute Module which needs more flexible pin configuration, and I want to make sure I haven't missed a gotcha that has already occurred to you.

notro commented 9 years ago

When I made the list I looked at moving MACH_BCM2708 devices to DT, and i2c-bcm2835 isn't used here. Then I expanded focus to include ARCH_BCM2835 and i2c-bcm2835 is already used there. That's why the driver hasn't shown up in this issue.

I know there have been some changes to i2c-bcm2708 that haven't gone into mainline. I don't know the details, except that one of the changes broke "large" transfers: #865 I have very little experience with i2c.

notro commented 9 years ago

I'm going to do onboard audio now. But I'm not sure where to put the DT devices. Should I put them in bcm2708_common.dtsi and have them enabled by default? Should they be placed under the sound node? Should each device have a label perhaps?

        audio@0 {
            compatible = "brcm,bcm2835-audio";
        };

        audio@1 {
            compatible = "brcm,bcm2835-audio";
        };

        audio@2 {
            compatible = "brcm,bcm2835-audio";
        };

        audio@3 {
            compatible = "brcm,bcm2835-audio";
        };

        audio@4 {
            compatible = "brcm,bcm2835-audio";
        };

        audio@5 {
            compatible = "brcm,bcm2835-audio";
        };

        audio@6 {
            compatible = "brcm,bcm2835-audio";
        };

        audio@7 {
            compatible = "brcm,bcm2835-audio";
        };
notro commented 9 years ago

I can't put them inside the sound node.

pelwell commented 9 years ago

Why?

notro commented 9 years ago

It's because of_platform_populate->of_platform_bus_create skips nodes that doesn't have a compatible property. And sound doesn't have one.

notro commented 9 years ago

I wonder, could we use a DT property to specify the number of channels? This way we would only need one DT device, and this could be the sound node itself.

notro commented 9 years ago

What about this solution: https://gist.github.com/notro/dafa5f7f29aa237113b1

Device Tree:

    sound: sound {
        compatible = "brcm,bcm2835-audio";
        channels = <8>;
    };
pelwell commented 9 years ago

I think that isn't going to work in the general case, because that slot has been used for external audio card drivers:

    fragment@0 {
        target = <&sound>;
        __overlay__ {
            compatible = "hifiberry,hifiberry-dac";
            i2s-controller = <&i2s>;
            status = "okay";
        };
    };

What I have done for other audio platform devices is to place them at the top level, e.g. from hifiberry-dac-overlay.dts:

    fragment@2 {
        target-path = "/";
        __overlay__ {
            pcm5102a-codec {
                #sound-dai-cells = <0>;
                compatible = "ti,pcm5102a";
                status = "okay";
            };
        };
    };

but it would be nice to find a better way.

Is it just me or is the "sound" node poorly documented?

notro commented 9 years ago

Ok, so sound is taken. After a few minutes of looking around, sound seems to be a "connection" node:

    sound {
        compatible = "nvidia,harmony-sound";
        i2s-controller = <&i2s1>;
        i2s-codec = <&wm8903>;
    };
};

..., and the sound node
represents not a device, but rather how other devices are connected
together to create the audio subsystem.

What about this?

/ {
[...]
    alsa: alsa {
        compatible = "brcm,bcm2835-audio";
        channels = <8>;
    };

@popcornmix what do you think about my approach? https://gist.github.com/notro/dafa5f7f29aa237113b1

Testing

This works for me on ARCH_BCM2835:

$ speaker-test -c2 -t wav

But this hangs (working fine on a standard kernel):

$ omxplayer /usr/share/scratch/Media/Sounds/Vocals/Singer2.wav
Audio codec pcm_s16le channels 1 samplerate 11025 bitspersample 16
Subtitle count: 0, state: off, index: 1, delay: 0

Nothing happens

$ ps as
[...]
 2256 ?        S      0:00 [VCHIQka-0]
 2480 ?        Ss     0:00 sshd: pi [priv]
 2482 ?        S      0:00 sshd: pi@pts/0
 2483 pts/0    Ss     0:01 -bash
 2501 pts/0    S+     0:00 /bin/bash /usr/bin/omxplayer /usr/share/scratch/Media/Sounds/Vocals/Singer2.wav
 2507 ?        Ss     0:00 dbus-daemon --fork --print-address 5 --print-pid 6 --session
 2510 pts/0    Sl+    0:00 /usr/bin/omxplayer.bin /usr/share/scratch/Media/Sounds/Vocals/Singer2.wav

$ top
  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND
 2529 pi        20   0  4676 2448 2092 R   1.0  0.5   0:00.23 top
 2510 pi        20   0  102m  10m 9652 S   0.3  2.5   0:02.22 omxplayer.bin

Ctrl-C doesn't stop omxplayer. But killall does. Nothing in the kernel log.

Then without rebooting I try speaker-test again, but now this hangs also:

$ speaker-test -c2 -t wav

speaker-test 1.0.25

Playback device is default
Stream parameters are 48000Hz, S16_LE, 2 channels
WAV file(s)

Ctrl-C works.

Kernel log:

$ dmesg
[46206.371564] vc_vchi_audio_init:295 vc_vchi_audio_init: failed to open VCHI service connection (status=-1)
[46206.371612] vc_vchi_audio_init:308 vc_vchi_audio_init: closing 0:   (null)
[46206.371628] vc_vchi_audio_init:314 vc_vchi_audio_init: error
[46206.371642] bcm2835_audio_open_connection:406 bcm2835_audio_open_connection: failed to initialize audio service
popcornmix commented 9 years ago

omxplayer doesn't use alsa. If it is is hanging then either something is hosed (e.g. vchiq is not reliable), or the previous failed alsa use has killed the GPU in some way.

Does omxplayer work from a clean boot?

notro commented 9 years ago

Does omxplayer work from a clean boot?

Not with the ARCH_BCM2835 kernel. Can I turn on some debug output in omxplayer? Would it help to turn on some logging in /sys/kernel/debug/vchiq/log?

popcornmix commented 9 years ago

omxplayer -g will produce a log called "omxplayer.log" but I suspect it will fail early. @pelwell can explain the best way of getting vchiq logging.

notro commented 9 years ago
$ cat omxplayer.log
13:06:58 T:438508298   DEBUG: DllBcm: Using omx system library
13:06:58 T:438516269   DEBUG: DllOMX: Using omx system library
13:06:58 T:438519176   DEBUG: DllAvFormat: Using libavformat system library
13:06:58 T:438535420   DEBUG: DBus connection succeeded
13:06:58 T:438543856   DEBUG: Keyboard: DBus connection succeeded
13:06:58 T:438544595   DEBUG: OMXThread::Create - Thread with id -1304312768 started
13:06:58 T:438545057   DEBUG: DllAvUtilBase: Using libavutil system library
13:06:58 T:438545307   DEBUG: DllAvCodec: Using libavcodec system library
13:06:58 T:438545493   DEBUG: DllAvFormat: Using libavformat system library
13:06:58 T:438809418 WARNING: main - Ignoring video in audio filetype:/usr/share/scratch/Media/Sounds/Vocals/Singer2.wav
13:06:58 T:438818900   DEBUG: COMXCoreComponent::Initialize OMX.broadcom.clock input port 80 output port 81 m_handle 0x204a040
13:06:58 T:438820218   DEBUG: OMXClock::OMXStop
13:06:58 T:438821038   DEBUG: OMXClock::OMXSetSpeed(0.00) pause_resume:1
13:06:58 T:438822412   DEBUG: OMXThread::Create - Thread with id -1312701376 started
13:06:58 T:438823278   DEBUG: DllAvUtilBase: Using libavutil system library
13:06:58 T:438823554   DEBUG: DllAvCodec: Using libavcodec system library
13:06:58 T:438823737   DEBUG: DllAvFormat: Using libavformat system library
13:06:58 T:438823912   DEBUG: DllAvUtilBase: Using libavutil system library
13:06:58 T:438824095   DEBUG: DllAvCodec: Using libavcodec system library
13:06:58 T:438824254   DEBUG: DllAvFormat: Using libswresample system library
13:06:58 T:438825180    INFO: COMXAudioCodecOMX::GetChannelMap - FFmpeg reported 1 channels, but the layout contains 0 ignoring
13:06:58 T:438825538   DEBUG: DllAvUtilBase: Using libavutil system library
13:06:58 T:438825747   DEBUG: COMXAudio::SetCodingType OMX_AUDIO_CodingPCM
13:06:58 T:438826042    INFO: CPCMRemap: I channel map: CE
13:06:58 T:438826258   DEBUG: CPCMRemap: Mapping mono audio to front left and front right
13:06:58 T:438826525    INFO: CPCMRemap: O channel map: FL,FR
13:06:58 T:438826723   DEBUG: CPCMRemap: Downmix normalization is disabled
13:06:58 T:438826889   DEBUG: CPCMRemap: Mapping mono audio to front left and front right
13:06:58 T:438827171   DEBUG: CPCMRemap: FL = CE(0.707107)
13:06:58 T:438827470   DEBUG: CPCMRemap: FR = CE(0.707107)
13:06:58 T:438835967   DEBUG: COMXCoreComponent::Initialize OMX.broadcom.audio_decode input port 120 output port 121 m_handle 0x204a200
13:06:58 T:438844965   DEBUG: COMXCoreComponent::AllocInputBuffers component(OMX.broadcom.audio_decode) - port(120), nBufferCountMin(4), nBufferCountActual(16), nBufferSize(32768), nBufferAlignmen(16)
13:06:58 T:438863315   DEBUG: COMXAudio::Initialize Input bps 16 samplerate 11025 channels 1 buffer size 66150 bytes per second 22050
13:06:58 T:438863672   DEBUG: pcm->direction      : input
13:06:58 T:438863862   DEBUG: pcm->nPortIndex     : 0
13:06:58 T:438864020   DEBUG: pcm->eNumData       : 0
13:06:58 T:438864190   DEBUG: pcm->eEndian        : 1
13:06:58 T:438864364   DEBUG: pcm->bInterleaved   : 1
13:06:58 T:438864522   DEBUG: pcm->nBitPerSample  : 16
13:06:58 T:438864681   DEBUG: pcm->ePCMMode       : 0
13:06:58 T:438864854   DEBUG: pcm->nChannels      : 1
13:06:58 T:438865012   DEBUG: pcm->nSamplingRate  : 11025
13:06:58 T:438865175   DEBUG: OMX_AUDIO_ChannelCF
13:06:58 T:438865354   DEBUG: COMXAudio::Initialize device omx:local passthrough 0 hwdecode 0
13:06:58 T:438866228   DEBUG: OMXThread::Create - Thread with id -1322654656 started
13:06:58 T:438866688  NOTICE: OMXClock using audio as reference
13:06:58 T:438867693   DEBUG: OMXClock::OMXReset audio / video : 1 / 0 wait mask 0->1 state : 2->1
13:06:58 T:438869532   DEBUG: Popped message member: NameAcquired interface: org.freedesktop.DBus type: 4 path: /org/freedesktop/DBus
13:06:58 T:438870938 WARNING: Unhandled dbus message, member: NameAcquired interface: org.freedesktop.DBus type: 4 path: /org/freedesktop/DBus
13:06:58 T:438872012   DEBUG: Normal M:0 (A:-4503599627370496 V:0) P:1 A:0.00 V:0.00/T:0.20 (0,0,0,1) A:0% V:0% (0.00,28.26)
13:06:58 T:438873815    INFO: CDVDPlayerAudio::Decode dts:0 pts:0 size:4096
13:06:58 T:438877465   DEBUG: COMXAudioCodecOMX::Decode(0x205f4d8,4096) format=1(1) chan=1 samples=2048 size=4096 data=0x2060500,(nil),(nil),(nil),(nil),(nil),(nil),(nil)
13:06:58 T:438877972   DEBUG: COMXAudioCodecOMX::GetData size=4096/4096 line=4096/4096 buf=0x2061508, desired=32768
13:06:58 T:438878217    INFO: CDVDPlayerAudio::Decode dts:185760 pts:185760 size:4096
13:06:58 T:438878682    INFO: CDVDPlayerAudio::Decode dts:371519 pts:371519 size:4096
13:06:58 T:438879184    INFO: CDVDPlayerAudio::Decode dts:557279 pts:557279 size:4096
13:06:58 T:438879637    INFO: CDVDPlayerAudio::Decode dts:743039 pts:743039 size:4096
13:06:58 T:438880041    INFO: CDVDPlayerAudio::Decode dts:928798 pts:928798 size:4096
13:06:58 T:438880483    INFO: CDVDPlayerAudio::Decode dts:1114558 pts:1114558 size:4096
13:06:58 T:438881053    INFO: CDVDPlayerAudio::Decode dts:1300317 pts:1300317 size:4096
13:06:58 T:438881847   DEBUG: COMXAudio::Decode ADec : setStartTime 0.000000
pelwell commented 9 years ago

..., and the sound node represents not a device, but rather how other devices are connected together to create the audio subsystem.

I found that documentation, and although it is a reasonable statement I didn't find the reality lives up to it. What it seems to be is a place to instantiate a driver for a single audio system, made up of a number of codec and Digital Audio Interconnect devices. This works fine provided you have only one.

Although there are existing overlays that use "/sound" as their node, I am open to changing them if we can come up with a better solution. It would mean synchronising changes of kernel and DTB/overlay, but it wouldn't be the first time.

Things that you (or I) could try:

  1. What happens if the compatible string exists but doesn't result in a module being loaded? e.g. "brcm,bcm2708" or "brcm,bcm2835"?
  2. If bcm2835-audio claims "/sound", does the OF framework create platform devices for subnodes? If so, we could use bcm2835-audio as both the container and source of some sound devices (in the event that "channels" is non-zero).
pelwell commented 9 years ago

ARM-side VCHIQ logging:

  1. Ensure that debugfs is mounted on /sys/kernel/debug, and conveniently accessible:
sudo mount -t debugfs nodev /sys/kernel/debug
sudo chmod a+rwx /sys/kernel/debug
  1. Change some logging levels:
# Higher level, with some message content
sudo sh -c "echo info >/sys/kernel/debug/vchiq/log/msg"

# Low level, no message content
sudo sh -c "echo info >/sys/kernel/debug/vchiq/log/core"

# Low level, probably too verbose
sudo sh -c "echo trace >/sys/kernel/debug/vchiq/log/core"

# For user-space interactions
sudo sh -c "echo trace >/sys/kernel/debug/vchiq/log/arm"

Output available via dmesg.

VC-side VCHIQ logging:

# Higher level, with some message content
vcgencmd vcos log set vchiq_msg info

# Low level, no message content
vcgencmd vcos log set vchiq_core info

# Low level, probably too verbose
vcgencmd vcos log set vchiq_core trace

Output available via sudo vcdbg log msg

If you bear in mind that the protocol is symmetric you will understand that there is a lot of duplication between the two sides. I would suggest starting with

vcgencmd vcos log set vchiq_core info
sudo sh -c "echo trace >/sys/kernel/debug/vchiq/log/arm"

and seeing where that gets you.

notro commented 9 years ago

This is my understanding of how devices are collected from DT:

static void __init bcm2708_dt_init(void)
    ret = of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);

of_default_bus_match_table

 27 const struct of_device_id of_default_bus_match_table[] = {
 28         { .compatible = "simple-bus", },
 29 #ifdef CONFIG_ARM_AMBA
 30         { .compatible = "arm,amba-bus", },
 31 #endif /* CONFIG_ARM_AMBA */
 32         {} /* Empty terminated list */
 33 };

of_platform_bus_create() is called on all root node children. If there is no compatible property, that node is skipped. If compatible is not in _of_default_bus_matchtable, it does not look at child nodes. But on the soc node (simple-bus), it will continue to collect child devices inside that node (of_match_node).

414         dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
415         if (!dev || !of_match_node(matches, bus))
416                 return 0;
417
418         for_each_child_of_node(bus, child) {
419                 pr_debug("   create child: %s\n", child->full_name);
420                 rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
421                 if (rc) {
422                         of_node_put(child);
423                         break;
424                 }
425         }

But what about SPI devices inside the SPI controller node? SPI core adds the child devices as SPI devices using of_register_spi_devices when the SPI master is registered.

AFAICT our current use of the sound node is how it's meant to be used. The driver sets up a connection between the various sound components.

I have looked at the sound node drivers in sound/soc/bcm/ and they are almost identical. Maybe they could be merged into one driver and the differences be expressed as DT properties? And if something can't be expressed as a property, it could have a compatible string for that setup adding the special function that is needed.

Back to alsa, we could have this unified sound component driver also run of_platform_populate(NULL, NULL, NULL, NULL) on the sound node to add the alsa child node it contains. Making this work:

    sound: sound {
        alsa: alsa {
            compatible = "brcm,bcm2835-audio";
            channels = <8>;
        };
    };

I'm not sure if this kosher though since sound is not a bus, so maybe we should just keep the alsa node a sibling to the sound node.

pelwell commented 9 years ago

Our multichannel VPU+PWM ALSA driver is independent of any external sound card, and it is the closest we have to an SOC sound component (the I2S driver also sort-of qualifies, and that is instantiated in /soc). Having to make all sound card drivers aware of the possible existence of this ALSA component seems wrong. ALSA seems capable of pulling together components from multiple entities at the level of sound cards, so why should we have to force them into multiple mutually exclusive artificial hierarchies in this way?

I would say that this PWM ALSA driver should either: a) be the root node of the sound hierarchy, one which can cause up to 8 VPU+PWM output devices to be added, and that calls of_platform_populate for any child nodes, or b) there should be yet another driver that exists solely to call of_platform_populate on all child nodes.

b) is conceptually cleaner, but seems like overkill. As the common element to all 2835-based systems (with Pi firmware), bcm2835-audio is a good candidate to be a parent for optional sound cards, so I prefer option a) (if it can be made to work).

For example:

    sound: sound {
        compatible = "brcm,bcm2835-audio";
        channels = <8>; // We could change this name to something more descriptive, e.g. "brcm,pwm-channels"
        status = "okay";

        hifiberry-dac {
            compatible = "hifiberry,hifiberry-dac";
            i2s-controller = <&i2s>;
            status = "okay";
        };

        pcm5102a-codec {
            #sound-dai-cells = <0>;
            compatible = "ti,pcm5102a";
            status = "okay";
        };
    };

To disable the PWM output, set channels to 0.

notro commented 9 years ago

Having to make all sound card drivers aware of the possible existence of this ALSA component seems wrong.

This was not my intention. I was thinking of unifying the "sound connection drivers" (ex. hifiberry_dac) into one driver which could then scan for devices.

I have spent some time looking at this and the sound node doesn't seem to be a special kind of node. 'sound' is just the preferred name for the sound device/card node. And this node can be quite complex on SoC's.

Reading http://devicetree.org/SoC_Audio more closely:

A top-level, virtual "sound" node to represent each ALSA (or other OS audio infrastructure) "card"

I understand this as one sound node per card. We have one onboard pwm card and one possible external card that uses i2s. Two sound devices/cards.

So I suggest we continue to use the sound node as we do now, and add the alsa node as a sibling:

    /* Onboard audio */
    audio: audio {
        compatible = "brcm,bcm2835-audio";
        brcm,pwm-channels = <8>;
    };

    /* External sound card */
    sound: sound {
    };

A stripped down simple-card could be used as a template for a unified virtual sound driver if that is desireable:

It could have been used as a replacement for hifiberry_amp and rpi-dac if it wasn't for their use of snd_soc_dai_set_bclk_ratio().

pelwell commented 9 years ago

Yes, reading that brief guide again I think you are right. How messy though, with no container and no naming convention.

A more complete unified driver would need a way of representing ALSA volume controls, switches, power controls and LEDs using DT - it's no surprise that simple-card sticks to the digital domain with no gain controls - but it would be very satisfying to delete those drivers.

Let's go with your proposal above - "audio" and "sound" as siblings.

notro commented 9 years ago

I don't have vc-mem yet, so I'll wait with omxplayer problem until I have gotten vc-mem in place. I can't imagine that the problem has anything to do with DT support in the sound driver. So I'll proceed and make a PR.

This is the ARM side trace when starting omxplayer: https://gist.github.com/notro/60e978bde75f6ad9b6de

pelwell commented 9 years ago

If you only have access to ARM-side logging then you should enable a bit more of the ARM-side VCHIQ logging. These two

sudo sh -c "echo info >/sys/kernel/debug/vchiq/log/arm"
sudo sh -c "echo info >/sys/kernel/debug/vchiq/log/core"

are probably sufficient, since the previous log didn't show any abnormal termination.

notro commented 9 years ago

New log: https://gist.github.com/notro/2f9b503e2675c191b557

notro commented 9 years ago

Should I put the audio node in bcm2708_common.dtsi disabled and then enable it in bcm2708-rpi*.dts, or should I just put it directly in bcm2708-rpi*.dts?

pelwell commented 9 years ago

Put it in bcm2708_common.dtsi - it is a feature common to BCM2835 and BCM2836, even if it isn't used.

pelwell commented 9 years ago

The logging doesn't show any obvious errors, just an absence of data arriving. Annoyingly the logging level required to see arriving data is "trace", whereas for outbound data it is only "info". I've just pushed a patch that changes the logging level for inbound data to "info", for future cases.

Fortunately the test fails quickly, so lets just up the levels one more time:

sudo sh -c "echo trace >/sys/kernel/debug/vchiq/log/arm"
sudo sh -c "echo info >/sys/kernel/debug/vchiq/log/msg"
notro commented 9 years ago

Log: https://gist.github.com/notro/cd2aa8ac5a2520e90b2e

pelwell commented 9 years ago

The interesting thread in the log is the DISP service, in that the final message from it goes unanswered. Annotating the trace with a bit of protocol decoding gives:

[ 1435.167092] vchiq: Sent: 00000000: 08 00 00 00                                     display_open
[ 1435.167116] vchiq: Sent Msg DATA(5) to DISP s:2 d:5 len:8
[ 1435.167259] vchiq: Rcvd Msg DATA(5) from DISP s:5 d:2 len:4
[ 1435.167284] vchiq: Rcvd: 00000000: 00 00 00 10                                     ....
[ 1435.173698] vchiq: Sent: 00000000: 0e 00 00 00                                     display_get_info
[ 1435.173721] vchiq: Sent Msg DATA(5) to DISP s:2 d:5 len:8
[ 1435.173863] vchiq: Rcvd Msg DATA(5) from DISP s:5 d:2 len:20
[ 1435.173897] vchiq: Rcvd: 00000000: 00 00 00 00 d0 02 00 00 e0 01 00 00 00 00 00 00 ................
[ 1435.174773] vchiq: Sent: 00000000: 0f 00 00 80                                     display_close
[ 1435.174795] vchiq: Sent Msg DATA(5) to DISP s:2 d:5 len:8
[ 1435.278515] vchiq: Sent: 00000000: 08 00 00 00                                     display_open
[ 1435.278538] vchiq: Sent Msg DATA(5) to DISP s:2 d:5 len:8
[ 1435.278686] vchiq: Rcvd Msg DATA(5) from DISP s:5 d:2 len:4
[ 1435.278726] vchiq: Rcvd: 00000000: 00 00 00 10                                     ....
[ 1435.280477] vchiq: Sent: 00000000: 10 00 00 00                                     update_start
[ 1435.280500] vchiq: Sent Msg DATA(5) to DISP s:2 d:5 len:8
[ 1435.280633] vchiq: Rcvd Msg DATA(5) from DISP s:5 d:2 len:4
[ 1435.280657] vchiq: Rcvd: 00000000: 6f 00 00 40                                     o..@
[ 1435.282306] vchiq: Sent: 00000000: 13 00 00 00                                     element_add
[ 1435.282343] vchiq: Sent Msg DATA(5) to DISP s:2 d:5 len:108
[ 1435.282485] vchiq: Rcvd Msg DATA(5) from DISP s:5 d:2 len:4
[ 1435.282509] vchiq: Rcvd: 00000000: 01 0c 00 20                                     ...
[ 1435.283749] vchiq: Sent: 00000000: 12 00 00 00                                     update_submit_sync
[ 1435.283771] vchiq: Sent Msg DATA(5) to DISP s:2 d:5 len:8

This show that there is no response to the update_submit_sync. VCHIQ knows nothing of the dispserve protocol, and all replies are sent in the same way.

There are two likely explanations: 1) The underlying update_submit_sync call never completes, so the VPU never tries to send a reply. 2) For some reason all VCHIQ traffic from the VPU have ceased, and that could also be because the transmissions aren't getting through.

As a general test of VCHIQ, try running vchiq_test -p, verifying that it runs all the way to:

ping (size 4088, 1000 async, 1000 oneway) -> 241749.953125us

before stopping.

If that passes, we can rule out case 2) by adding some background traffic:

while true; do vcgencmd version; sleep 1; done

With this running, restart the test with the same logging as before and we'll see how the results differ.

notro commented 9 years ago
$ sudo sh -c "echo trace >/sys/kernel/debug/vchiq/log/arm"
$ sudo sh -c "echo info >/sys/kernel/debug/vchiq/log/msg"
$ sudo dmesg -C
$ vchiq_test -p
Ping test - service:echo, iters:1000, version 3
^C
$

dmesg: https://gist.github.com/notro/1a234a49512f63cf25d8

I'll do vc-mem now. But I would like to boot directly from the VC bootloader without u-boot. This is because vc-mem gets it's parameters from the kernel commandline.

For this I need USB power turned on. I see 2 solutions:

pelwell commented 9 years ago

Interesting log. It looks as though it just ground to a halt after a few pings.

While ping_test is stalled, can you capture the output from cat /dev/vchiq?

notro commented 9 years ago
$ cat /dev/vchiq
State 0: CONNECTED
  tx_pos=1f0(@dc87a1f0), rx_pos=1a0(@dc85a1a0)
  Version: 8 (min 3)
  Stats: ctrl_tx_count=4, ctrl_rx_count=4, error_count=0
  Slots: 30 available (29 data), 0 recyclable, 0 stalls (0 data)
  Platform: 2835 (VC master)
  Local: slots 34-64 tx_pos=1f0 recycle=1f
    Slots claimed:
    DEBUG: SLOT_HANDLER_COUNT = 29(1d)
    DEBUG: SLOT_HANDLER_LINE = 2041(7f9)
    DEBUG: PARSE_LINE = 2016(7e0)
    DEBUG: PARSE_HEADER = -595222128(dc85a190)
    DEBUG: PARSE_MSGID = 84045824(5027000)
    DEBUG: AWAIT_COMPLETION_LINE = 778(30a)
    DEBUG: DEQUEUE_MESSAGE_LINE = 940(3ac)
    DEBUG: SERVICE_CALLBACK_LINE = 357(165)
    DEBUG: MSG_QUEUE_FULL_COUNT = 0(0)
    DEBUG: COMPLETION_QUEUE_FULL_COUNT = 0(0)
  Remote: slots 2-32 tx_pos=1a0 recycle=1f
    Slots claimed:
      2: 24/23
    DEBUG: SLOT_HANDLER_COUNT = 28(1c)
    DEBUG: SLOT_HANDLER_LINE = 1844(734)
    DEBUG: PARSE_LINE = 1820(71c)
    DEBUG: PARSE_HEADER = 1533682144(5b6a21e0)
    DEBUG: PARSE_MSGID = 83886119(5000027)
    DEBUG: AWAIT_COMPLETION_LINE = 0(0)
    DEBUG: DEQUEUE_MESSAGE_LINE = 0(0)
    DEBUG: SERVICE_CALLBACK_LINE = 0(0)
    DEBUG: MSG_QUEUE_FULL_COUNT = 0(0)
    DEBUG: COMPLETION_QUEUE_FULL_COUNT = 0(0)
Instance dadbc800: pid 2297, connected,  completions 0/16
Service 0: OPEN (ref 2) 'echo' remote 39 (msg use 23/3840, slot use 1/15)
  Bulk: tx_pending=0 (size 0), rx_pending=0 (size 0)
  Ctrl: tx_count=16, tx_bytes=100, rx_count=16, rx_bytes=16
  Bulk: tx_count=0, tx_bytes=0, rx_count=0, rx_bytes=0
  0 quota stalls, 0 slot stalls, 0 bulk stalls, 0 aborted, 0 errors
  instance dadbc800, 0/64 messages (dequeue pending)
Service 1: LISTENING (ref 1) 'KEEP' remote n/a (msg use 0/3840, slot use 0/15)
  Bulk: tx_pending=0 (size 0), rx_pending=0 (size 0)
  Ctrl: tx_count=0, tx_bytes=0, rx_count=0, rx_bytes=0
  Bulk: tx_count=0, tx_bytes=0, rx_count=0, rx_bytes=0
  0 quota stalls, 0 slot stalls, 0 bulk stalls, 0 aborted, 0 errors
  instance dacaf920
notro commented 9 years ago

I was quite easy to move the power driver, so I'll do that. drivers/power was the wrong place, so I moved it to drivers/soc/bcm2835. So I'll make a PR for that, then I'll do one for vc-mem.

@pelwell With those in place it's possible to boot ARC_BCM2835 directly from VC and with vc-mem in place, I think it's better that you continue with tracking down where/why this fails at your leisure.

pelwell commented 9 years ago

Thanks, that's appreciated. It's on my list.

notro commented 9 years ago

ARCH_BCM2835 is not able to halt, it just reboots. This change fixes that:

+static int calc_rsts(int partition)
+{
+   return PM_PASSWORD |
+       ((partition & (1 << 0))  << 0) |
+       ((partition & (1 << 1))  << 1) |
+       ((partition & (1 << 2))  << 2) |
+       ((partition & (1 << 3))  << 3) |
+       ((partition & (1 << 4))  << 4) |
+       ((partition & (1 << 5))  << 5);
+}
+
/*
 * We can't really power off, but if we do the normal reset scheme, and
 * indicate to bootcode.bin not to reboot, then most of the chip will be
 * powered off.
 */
static void bcm2835_power_off(void)
{
    u32 val;

    /*
     * We set the watchdog hard reset bit here to distinguish this reset
     * from the normal (full) reset. bootcode.bin will not reboot after a
     * hard reset.
     */
    val = readl_relaxed(wdt_regs + PM_RSTS);
    val &= ~PM_RSTC_WRCFG_MASK;
    val |= PM_PASSWORD | PM_RSTS_HADWRH_SET;
+
+   /* partition 63 is special code for HALT the bootloader knows not to boot*/
+   val = calc_rsts(63);
+
    writel_relaxed(val, wdt_regs + PM_RSTS);

    /* Continue with normal reset mechanism */
    bcm2835_restart(REBOOT_HARD, "");
}

What's the reasoning behind the calc_rsts() formula?

bcm2835_power_off() reads PM_RSTS and uses part of that value when writing back, but arch/arm/mach-bcm2708/bcm2708.c only writes. Care to elaboarate on this?

popcornmix commented 9 years ago

There are 6 bits of "state" that are preserved over a reset in the PM_RSTS register. We use them for signalling information to bootcode.bin over a reset.

NOOBS writes a partition number before rebooting to support multiboot. 63 is treated as a magic number to indicate we don't want to reboot (i.e. we are halting).

calc_rsts is historical. Looks like (PM_PASSWORD | (partition & 0x3f)) would be equivalent. I suspect that earlier we only allocated a few of the bits, so it did a non-linear mapping of bits.

notro commented 9 years ago

Looks like (PM_PASSWORD | (partition ^ 0x3f)) would be equivalent.

That would not give the same value:

63 == 0x3f == 0b11111
calc_rsts(63) & 0xffff = 0x555 == 010101010101 (every other bit is used)

63 ^ 0x3f = 0

Is get_rsts being masked somehow, because I don't get the 0x555 value back:

Power on
$ vcgencmd get_rsts
get_rsts=1000  == 0001 0000 0000 0000 == BIT(12)

Reboot
$ vcgencmd get_rsts
get_rsts=1020  == 0001 0000 0010 0000 == BIT(12) | BIT(5)

PM_RSTS flags

12 HADPOR Had a power-on reset
5  HADWRF Had a watchdog full reset

Ref: https://github.com/raspberrypi/linux/issues/932

popcornmix commented 9 years ago

The ^ was corrected to an & just after I posted it yesterday.

notro commented 9 years ago

This did not work, it rebooted instead of halting:

    val = PM_PASSWORD | (63 & 0x3f);
$ vcgencmd get_rsts
get_rsts=37

I expected to get 0x3f here, but bit 3 is zero: PM_RSTS 3 - Unused R

popcornmix commented 9 years ago

Sorry I misread calc_rsts. The six-bit partition is spread into bits 0, 2, 4, 6, 8, 10 of RSTS.

I don't believe we want to preserve anything in there so I'd say:

static void bcm2835_power_off(void)
{
   /* partition 63 is special code for HALT the bootloader knows not to boot*/
    u32 val = calc_rsts(63);
    writel_relaxed(val, wdt_regs + PM_RSTS);

    /* Continue with normal reset mechanism */
    bcm2835_restart(REBOOT_HARD, "");
}

looks right.

notro commented 9 years ago

BCM270x Device Tree status

These arch/arm/mach-bcm270x/bcm270x.c devices have not been moved to Device Tree.

uart0

AMBA_DEVICE(uart0, "dev:f1", UART0, NULL);

static struct amba_device *amba_devs[] __initdata = {
    &uart0_device,
};

        amba_device_register(d, &iomem_resource);

See #910

bcm2708_systemtimer

    bcm_register_device(&bcm2708_systemtimer_device);

This device does not have a matching driver. It's intended role seems to have been fulfilled by bcm2708_clocksource_init(). On BCM2709 it is disabled because SYSTEM_TIMER is not defined.

serial8250

    bcm_register_device(&bcm2708_uart1_device);

The driver for this device is not enabled (SERIAL_8250). Only the Compute Module has access to the necessary pins if I'm not mistaken.

To simplify the life for those wanting to use this, I suggest adding a DT node. I have tried to construct one based on bcm2708_uart1_platform_data. This is not tested.

        uart1: uart@7e215040 {
            compatible = "ns16550";
            reg = <0x7e215040 0x40>;
            interrupts = <1 29>;
            clock-frequency = <500000000>; // a regular clocks property can also be used
            reg-shift = <2>;
            no-loopback-test;
            status = "disabled";
        };

kconfig: SERIAL_8250 SERIAL_OF_PLATFORM

Links: https://www.kernel.org/doc/Documentation/devicetree/bindings/serial/8250.txt http://lxr.free-electrons.com/source/drivers/tty/serial/of_serial.c http://lxr.free-electrons.com/source/drivers/tty/serial/8250/

bcm2708_powerman

    bcm_register_device(&bcm2708_powerman_device);

This device does not have a matching driver. It was probably meant to be used with the bcm2708-power module.

bcm2835_hwmon

    bcm_register_device(&bcm2835_hwmon_device);

The matching bcm2835_hwmon driver is not enabled (can't be used alongside bcm2835-thermal):

pelwell commented 9 years ago

The 8250/pl011 UART (uart1) can use the same pins as the mini UART (uart0), but not at the same time. If you configure GPIOs 14-15 (and 16-17 if you want RTS/CTS) to ALT5 then you will lose ttyAMA0, but gain a way to use UART1.