Commit d51e2d53 authored by Jeroen Vreeken's avatar Jeroen Vreeken
Browse files

Add qed

parent 02339b0e
......@@ -21,6 +21,7 @@
#include <inttypes.h>
#include <unistd.h>
#define AM335X_SYSCLK 100000000
#define AM335X_ADC_BASE 0x44e0d000
#define AM335X_ADC_SIZE 0x00002000
......@@ -33,25 +34,61 @@
#define AM335X_PWMSS_REG_IDVER 0x000
#define AM335X_PWMSS_IDVER_SCHEME_GET(x) (((x) & 0xc0000000) >> 30)
#define AM335X_PWMSS_IDVER_FUNC_GET(x) (((x) & 0x0fff0000) >> 16)
#define AM335X_PWMSS_IDVER_FUNC 0x000
#define AM335X_PWMSS_IDVER_FUNC 0x740
#define AM335X_PWMSS_IDVER_X_MAJOR_GET(x) (((x) & 0x00000700) >> 8)
#define AM335X_PWMSS_IDVER_Y_MINOR_GET(x) (((x) & 0x0000001f) )
#define AM335X_PWMSS_REG_SYSCONFIG 0x004
#define AM335X_PWMSS_REG_CLKCONFIG 0x008
#define AM335X_PWMSS_CLKCONFIG_EPWMCLK_EN 0x00000100
#define AM335X_PWMSS_CLKCONFIG_EPWMCLKSTOP_REQ 0x00000200
#define AM335X_PWMSS_CLKCONFIG_EQEDCLK_EN 0x00000010
#define AM335X_PWMSS_CLKCONFIG_EQEDCLKSTOP_REQ 0x00000020
#define AM335X_PWMSS_REG_CLKSTATUS 0x00c
#define AM335X_PWMSS_REG_EPWM_TBCTL 0x200
#define AM335X_PWMSS_EPWM_TBCTL_CLKDIV_SET(x) ((x) << 10)
#define AM335X_PWMSS_EPWM_TBCTL_CLKDIV_MAX 7
#define AM335X_PWMSS_EPWM_TBCTL_SYNC0SEL_DIS 0x00000030
#define AM335X_PWMSS_EPWM_TBCTL_CTRMODE_UP 0x00000000
#define AM335X_PWMSS_EPWM_TBCTL_CTRMODE_DN 0x00000001
#define AM335X_PWMSS_EPWM_TBCTL_CTRMODE_UD 0x00000002
#define AM335X_PWMSS_EPWM_TBCTL_CTRMODE_SF 0x00000003
#define AM335X_PWMSS_REG_EPWM_TBSTS 0x202
#define AM335X_PWMSS_REG_EPWM_TBPHSHR 0x204
#define AM335X_PWMSS_REG_EPWM_TBPHS 0x206
#define AM335X_PWMSS_REG_EPWM_TBCNT 0x208
#define AM335X_PWMSS_REG_EPWM_TBPRD 0x20a
#define AM335X_PWMSS_EPWM_TBPRD_MAX 0xffff
#define AM335X_PWMSS_REG_EPWM_CMPCTL 0x20e
#define AM335X_PWMSS_REG_EPWM_CMPAHR 0x210
#define AM335X_PWMSS_REG_EPWM_CMPA 0x212
#define AM335X_PWMSS_REG_EPWM_CMPB 0x214
#define AM335X_PWMSS_REG_EPWM_AQCTLA 0x216
#define AM335X_PWMSS_REG_EPWM_AQCTLB 0x218
#define AM335X_PWMSS_EPWM_AQCTLA_CBD_NOP 0x0000
#define AM335X_PWMSS_EPWM_AQCTLA_CBD_CLR 0x0400
#define AM335X_PWMSS_EPWM_AQCTLA_CBD_SET 0x0800
#define AM335X_PWMSS_EPWM_AQCTLA_CBD_TGL 0x0c00
#define AM335X_PWMSS_EPWM_AQCTLA_CBU_NOP 0x0000
#define AM335X_PWMSS_EPWM_AQCTLA_CBU_CLR 0x0100
#define AM335X_PWMSS_EPWM_AQCTLA_CBU_SET 0x0200
#define AM335X_PWMSS_EPWM_AQCTLA_CBU_TGL 0x0300
#define AM335X_PWMSS_EPWM_AQCTLA_CAD_NOP 0x0000
#define AM335X_PWMSS_EPWM_AQCTLA_CAD_CLR 0x0040
#define AM335X_PWMSS_EPWM_AQCTLA_CAD_SET 0x0080
#define AM335X_PWMSS_EPWM_AQCTLA_CAD_TGL 0x00c0
#define AM335X_PWMSS_EPWM_AQCTLA_CAU_NOP 0x0000
#define AM335X_PWMSS_EPWM_AQCTLA_CAU_CLR 0x0010
#define AM335X_PWMSS_EPWM_AQCTLA_CAU_SET 0x0020
#define AM335X_PWMSS_EPWM_AQCTLA_CAU_TGL 0x0030
#define AM335X_PWMSS_EPWM_AQCTLA_PRD_NOP 0x0000
#define AM335X_PWMSS_EPWM_AQCTLA_PRD_CLR 0x0004
#define AM335X_PWMSS_EPWM_AQCTLA_PRD_SET 0x0008
#define AM335X_PWMSS_EPWM_AQCTLA_PRD_TGL 0x000c
#define AM335X_PWMSS_EPWM_AQCTLA_ZRO_NOP 0x0000
#define AM335X_PWMSS_EPWM_AQCTLA_ZRO_CLR 0x0001
#define AM335X_PWMSS_EPWM_AQCTLA_ZRO_SET 0x0002
#define AM335X_PWMSS_EPWM_AQCTLA_ZRO_TGL 0x0003
#define AM335X_PWMSS_REG_EPWM_AQSFRC 0x21a
#define AM335X_PWMSS_REG_EPWM_AQCSFRC 0x21c
#define AM335X_PWMSS_REG_EPWM_DBCTL 0x21e
......@@ -59,6 +96,8 @@
#define AM335X_PWMSS_REG_EPWM_DBFED 0x222
#define AM335X_PWMSS_REG_EPWM_TZSEL 0x224
#define AM335X_PWMSS_REG_EPWM_TZCTL 0x228
#define AM335X_PWMSS_EPWM_TZCTL_TZA_NOP 0x00000003
#define AM335X_PWMSS_EPWM_TZCTL_TZB_NOP 0x0000000c
#define AM335X_PWMSS_REG_EPWM_TZEINT 0x22a
#define AM335X_PWMSS_REG_EPWM_TZFLG 0x22c
#define AM335X_PWMSS_REG_EPWM_TZCLR 0x22e
......@@ -71,6 +110,32 @@
#define AM335X_PWMSS_REG_EPWM_PCCTL 0x23c
#define AM335X_PWMSS_REG_EPWM_HRCNFG 0x2c0
#define AM335X_PWMSS_REG_ECEP_QPOSCNT 0x180
#define AM335X_PWMSS_REG_ECEP_QPOSINIT 0x184
#define AM335X_PWMSS_REG_ECEP_QPOSMAX 0x188
#define AM335X_PWMSS_REG_ECEP_QPOSCMP 0x18c
#define AM335X_PWMSS_REG_ECEP_QPOSILAT 0x190
#define AM335X_PWMSS_REG_ECEP_QPOSSLAT 0x194
#define AM335X_PWMSS_REG_ECEP_QPOSLAT 0x198
#define AM335X_PWMSS_REG_ECEP_QUTMR 0x19c
#define AM335X_PWMSS_REG_ECEP_QUPRD 0x1a0
#define AM335X_PWMSS_REG_ECEP_QWDTMR 0x1a4
#define AM335X_PWMSS_REG_ECEP_QWDPRD 0x1a6
#define AM335X_PWMSS_REG_ECEP_QDECCTL 0x1a8
#define AM335X_PWMSS_REG_ECEP_QEPCTL 0x1aa
#define AM335X_PWMSS_REG_ECEP_QCAPCTL 0x1ac
#define AM335X_PWMSS_REG_ECEP_QPOSCTL 0x1ae
#define AM335X_PWMSS_REG_ECEP_QEINT 0x1b0
#define AM335X_PWMSS_REG_ECEP_QFLG 0x1b2
#define AM335X_PWMSS_REG_ECEP_QCLR 0x1b4
#define AM335X_PWMSS_REG_ECEP_QFRC 0x1b6
#define AM335X_PWMSS_REG_ECEP_QEPSTS 0x1b8
#define AM335X_PWMSS_REG_ECEP_QCTMR 0x1ba
#define AM335X_PWMSS_REG_ECEP_QCPRD 0x1bc
#define AM335X_PWMSS_REG_ECEP_QCTMRLAT 0x1be
#define AM335X_PWMSS_REG_ECEP_QCPRDLAT 0x1c0
#define AM335X_PWMSS_REG_ECEP_REVID 0x1dc
#define AM335X_PWMSS_ECEP_REVID 0x44d31103
#define AM335X_ADC_REG_REVISION 0x000
#define AM335X_ADC_REVISION_SCHEME_GET(x) (((x) & 0xc0000000) >> 30)
......
......@@ -26,24 +26,119 @@
#include <fcntl.h>
#include <inttypes.h>
#include <unistd.h>
#include <math.h>
struct controller_block_private {
float *in;
uint16_t tbprd; // period
double freq;
bool sym;
void *base;
};
static void pwm_calculate(struct controller_block *pwm)
{
struct controller_block_private *priv = pwm->private;
float in;
uint16_t cmp;
uint16_t tbprd;
bool sign;
void *base = priv->base;
tbprd = priv->tbprd;
in = *priv->in;
sign = signbit(in);
cmp = fmax(fabsf(in * tbprd), tbprd);
if (sign) {
am335x_write16(base, AM335X_PWMSS_REG_EPWM_CMPA, 0);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_CMPB, cmp);
} else {
am335x_write16(base, AM335X_PWMSS_REG_EPWM_CMPA, cmp);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_CMPB, 0);
}
}
static void set_freq(struct controller_block *pwm)
{
struct controller_block_private *priv = pwm->private;
void *base = priv->base;
int clkdiv = 0;
int div = 1;
double period, freq;
uint16_t tbprd;
/* double divider for symmetric use */
period = AM335X_SYSCLK / (priv->freq * ( priv->sym ? 2.0 : 1.0));
while (period > AM335X_PWMSS_EPWM_TBPRD_MAX) {
clkdiv++;
div *= 2;
period /= 2.0;
if (clkdiv == AM335X_PWMSS_EPWM_TBCTL_CLKDIV_MAX)
break;
}
tbprd = period;
am335x_write16(base, AM335X_PWMSS_REG_EPWM_TBCTL,
AM335X_PWMSS_EPWM_TBCTL_CLKDIV_SET(clkdiv) |
AM335X_PWMSS_EPWM_TBCTL_SYNC0SEL_DIS |
AM335X_PWMSS_EPWM_TBCTL_CTRMODE_UD);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_CMPCTL, 0);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_AQCTLA,
AM335X_PWMSS_EPWM_AQCTLA_CBD_NOP |
AM335X_PWMSS_EPWM_AQCTLA_CBU_NOP |
AM335X_PWMSS_EPWM_AQCTLA_CAD_SET |
AM335X_PWMSS_EPWM_AQCTLA_CAU_CLR |
AM335X_PWMSS_EPWM_AQCTLA_PRD_NOP |
AM335X_PWMSS_EPWM_AQCTLA_PRD_NOP );
am335x_write16(base, AM335X_PWMSS_REG_EPWM_AQCTLB,
AM335X_PWMSS_EPWM_AQCTLA_CAD_NOP |
AM335X_PWMSS_EPWM_AQCTLA_CAU_NOP |
AM335X_PWMSS_EPWM_AQCTLA_CBD_SET |
AM335X_PWMSS_EPWM_AQCTLA_CBU_CLR |
AM335X_PWMSS_EPWM_AQCTLA_PRD_NOP |
AM335X_PWMSS_EPWM_AQCTLA_PRD_NOP );
am335x_write16(base, AM335X_PWMSS_REG_EPWM_AQSFRC, 0);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_TBPRD, tbprd);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_CMPA, 0);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_CMPB, 0);
priv->tbprd = tbprd;
freq = AM335X_SYSCLK / (tbprd * div * ( priv->sym ? 2.0 : 1.0));
log_send(LOG_T_DEBUG,
"%s: Frequency: %gHz, period: %d ticks, divider: %d",
pwm->name, freq, tbprd, div);
priv->freq = freq;
}
static struct controller_block_param_list params[] = {
{ "frequency", false },
{ "symmetrical", false },
{ NULL },
};
static void param_set(struct controller_block *pwm, int param, va_list val)
{
switch (param) {
case 0:
pwm->private->freq = va_arg(val, double);
set_freq(pwm);
break;
case 1:
pwm->private->sym = va_arg(val, int);
set_freq(pwm);
break;
}
}
static struct controller_block_interm_list interms[] = {
......@@ -105,6 +200,17 @@ struct controller_block * block_am335x_pwm_create(char *name, va_list ap)
goto err_rev;
}
am335x_write16(base, AM335X_PWMSS_REG_EPWM_PCCTL, 0);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_DBCTL, 0);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_TZCTL,
AM335X_PWMSS_EPWM_TZCTL_TZA_NOP |
AM335X_PWMSS_EPWM_TZCTL_TZB_NOP );
am335x_write16(base, AM335X_PWMSS_REG_EPWM_TZEINT, 0);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_ETSEL, 0);
am335x_write16(base, AM335X_PWMSS_REG_EPWM_HRCNFG, 0);
if (!(pwm = controller_block_alloc("am355x_pwm", name, sizeof(struct controller_block_private))))
goto err_alloc;
......@@ -113,6 +219,15 @@ struct controller_block * block_am335x_pwm_create(char *name, va_list ap)
pwm->private->base = base;
pwm->private->sym = true;
pwm->private->freq = 10000;
set_freq(pwm);
am335x_write32(base, AM335X_PWMSS_REG_CLKCONFIG,
(am335x_read32(base, AM335X_PWMSS_REG_CLKCONFIG) &
~AM335X_PWMSS_CLKCONFIG_EPWMCLKSTOP_REQ) |
AM335X_PWMSS_CLKCONFIG_EPWMCLK_EN);
pwm->calculate = pwm_calculate;
if (controller_block_param_list_init(pwm, params))
......
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2014
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "am335x.h"
#include <controller/controller_block.h>
#include <log/log.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inttypes.h>
#include <unistd.h>
#include <math.h>
struct controller_block_private {
int32_t cnt;
void *base;
};
static void qed_calculate(struct controller_block *qed)
{
struct controller_block_private *priv = qed->private;
void *base = priv->base;
int32_t cnt;
cnt = am335x_read32(base, AM335X_PWMSS_REG_ECEP_QPOSCNT);
priv->cnt = cnt;
}
static struct controller_block_param_list params[] = {
{ NULL },
};
static void param_set(struct controller_block *qed, int param, va_list val)
{
}
static struct controller_block_outterm_list outterms[] = {
{ "count", CONTROLLER_BLOCK_TERM_SINT32, offsetof(struct controller_block_private, cnt) },
{ NULL },
};
struct controller_block * block_am335x_qed_create(char *name, va_list ap)
{
struct controller_block *qed;
int fd;
void *base;
uint32_t reg;
int qed_nr;
size_t offset;
qed_nr = va_arg(ap, int);
if (qed_nr < 0 || qed_nr > 2) {
log_send(LOG_T_ERROR, "%s: qed%d is not valid. (valid: 0-2)",
name, qed_nr);
return NULL;
}
switch (qed_nr) {
case 0:
offset = AM335X_PWMSS0_BASE;
break;
case 1:
offset = AM335X_PWMSS1_BASE;
break;
case 2:
offset = AM335X_PWMSS2_BASE;
break;
}
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0 ) {
log_send(LOG_T_ERROR, "%s: Error opening /dev/mem", name);
close(fd);
return NULL;
}
base = mmap(NULL, AM335X_PWMSS_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, offset);
close(fd);
if (!base) {
log_send(LOG_T_ERROR, "Mapping QED failed");
return NULL;
}
log_send(LOG_T_DEBUG, "%s: QED mapped @ %p", name, base);
reg = am335x_read32(base, AM335X_PWMSS_REG_IDVER);
log_send(LOG_T_DEBUG,
"%s: IDVER: 0x%" PRIx32 ": func: 0x%03x rev: %d.%d",
name, reg, AM335X_PWMSS_IDVER_FUNC_GET(reg),
AM335X_PWMSS_IDVER_X_MAJOR_GET(reg),
AM335X_PWMSS_IDVER_Y_MINOR_GET(reg));
if (AM335X_PWMSS_IDVER_FUNC_GET(reg) != AM335X_PWMSS_IDVER_FUNC) {
log_send(LOG_T_ERROR, "Unexpected functional number");
goto err_rev;
}
reg = am335x_read32(base, AM335X_PWMSS_REG_ECEP_REVID);
log_send(LOG_T_DEBUG, "%s: REVID: 0x%" PRIx32, name, reg);
if (reg != AM335X_PWMSS_ECEP_REVID) {
log_send(LOG_T_ERROR, "Unexpected REVID");
goto err_rev;
}
if (!(qed = controller_block_alloc("am355x_qed", name, sizeof(struct controller_block_private))))
goto err_alloc;
if (controller_block_outterm_list_init(qed, outterms))
goto err_outterm;
qed->private->base = base;
am335x_write32(base, AM335X_PWMSS_REG_ECEP_QPOSCNT, 0);
am335x_write32(base, AM335X_PWMSS_REG_ECEP_QPOSINIT, 0);
am335x_write32(base, AM335X_PWMSS_REG_CLKCONFIG,
(am335x_read32(base, AM335X_PWMSS_REG_CLKCONFIG) &
~AM335X_PWMSS_CLKCONFIG_EQEDCLKSTOP_REQ) |
AM335X_PWMSS_CLKCONFIG_EQEDCLK_EN);
qed->calculate = qed_calculate;
if (controller_block_param_list_init(qed, params))
goto err_param;
qed->param_set = param_set;
controller_block_add(qed);
return qed;
err_param:
err_outterm:
controller_block_free(qed);
err_alloc:
err_rev:
munmap(base, AM335X_PWMSS_SIZE);
return NULL;
}
......@@ -3,7 +3,8 @@ BLOCK_TARGETS := $(LIBDIR)/libam335x.la
BLOCK_SRCS := \
$(DIR)/block_am335x_adc.c \
$(DIR)/block_am335x_pwm.c
$(DIR)/block_am335x_pwm.c \
$(DIR)/block_am335x_qed.c
BLOCK_OBJS := $(BLOCK_SRCS:.c=.lo)
......
......@@ -290,6 +290,7 @@ int controller_block_sample_init(void)
}
}
calculates = calloc(sizeof(struct calculate_func), 1);
for (i = 0; i < nr_blocks; i++) {
if (blocks[i]->calculate) {
log_send(LOG_T_DEBUG,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment