I am working with a P5040 and communicating with a variety of peripherals via the eLBC. The eight chip selects are configured as follows:
0 -> NOR via GPCM
1-> NAND via FCM
2 -> UPMA
3 -> UPMA
4 -> UPMA
5 -> UPMB
6 -> UPMB
7 -> UPMB
As some of you will have guessed, I'm communicating with three identical devices, so that CS2/5, CS3/6 and CS4/7 form the three links.
For the most part this is working very nicely. I am able to concurrently access all devices without paying too much attention to locking. The only locking I have provided in my (Linux kernel) driver is at the chip select level - 6 mutexes, one per chip select.
This works fine for the normal read/write usage, but on occasion I need to generate some slightly different waveforms on UPMA. Roughly one in every 500 transactions will be this non standard waveform. I have placed it in an unused area of UPMA and issued a UPM run command to start it.
Incidentally I'm piggybacking on the existing UPM run code in the Linux kernel - my code to basically looks like
mutex_lock
mutex_lock(chip_select[234]_mutex);
fsl_upm_start_pattern(...);
fsl_upm_run_pattern(...);
fsl_upm_end_pattern(...);
mutex_unlock(chip_select[234]_mutex);
When I'm only communicating with a single device (eg exercising chip select 2 only) this works beautifully. I see my waveforms on a scope and data is sent/received correctly.
I have problems in two cases:
1. If I try to exercise multiple chip selects concurrently - eg use of UPMA by both CS2 and CS3 by two different threads. Each thread will be performing reads, writes and occasional upm_run commands. Now my transactions timeout.
2. If I try to access NAND while CS2 is issuing UPMA run commands the NAND reports errors to /var/log/messages
fsl,elbc-fcm-nand fffa0000.nand: command failed: fir 4125e000 fcr 30000000 status 2 mdr 0
For problem 1 I initially suspected that the upm_start/run/end sequence was being preempted - eg thread 1 would get as far as fsl_upm_start_pattern, then a write from thread 2 would cause the upm_run_pattern to be issues to the incorrect chip select. I added per-upm locking, so that my code now looked like
mutex_lock(upmA_mutex)
mutex_lock(chip_select[234]_mutex);
fsl_upm_start_pattern(...);
fsl_upm_run_pattern(...);
fsl_upm_end_pattern(...);
mutex_unlock(chip_select[234]_mutex);
mutex_unlock(upmA_mutex);
Now I could guarantee that the next write to hit a UPM A chip select would be the one caused by fsl_upm_run_pattern.
This did not fix the issue.
A few references:
fsl_upm_start_pattern:
Linux/arch/powerpc/include/asm/fsl_lbc.h - Linux Cross Reference - Free Electrons
fsl_upm_run_pattern:
Linux/arch/powerpc/sysdev/fsl_lbc.c - Linux Cross Reference - Free Electrons
fsl_upm_end_pattern:
Linux/arch/powerpc/include/asm/fsl_lbc.h - Linux Cross Reference - Free Electrons
U-boot versions of the above:
u-boot-fslc/fsl_upm.c at patches-2015.01 · Freescale/u-boot-fslc · GitHub
Question: Are there any further things I need to consider to be able to safely issue UPM run commands to multiple chip selects sharing the same UPM?
Question: The FCM driving the NAND appears to use the FCM special operations mode, which is a bit similar to UPM run. Can they be used concurrently, or do I need sufficient locking as to prevent FCM special operations and UPM run commands being issued at the same time?
Question: Is the UPM run guaranteed to have completed by the time fsl_upm_end_pattern returns?
Question: Do I need to monitor the eLBC interrupt and LTESR to detect completion of the UPM run command?
Question: The P5040 Reference manual states that writes to MxMR must be followed by a readback to ensure they have taken effect before a dummy write is issued. This appears to be done in the U-boot source, but not in the kernel functions linked above. Is this a kernel bug?