code: plan9front

Download patch

ref: 0a7d581eec1319c643337d302176b3f9ba565ea5
parent: 6901fbd5e924a3d05c116289092f3be8f1a290d7
author: adventuresin9 <adventuresin9@gmail.com>
date: Thu Apr 4 18:23:19 EDT 2024

mt7688: add devarch and i2c

--- /dev/null
+++ b/sys/src/9/mt7688/devarch.c
@@ -1,0 +1,338 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "io.h"
+
+enum {
+	Qdir = 0,
+	Qbase,
+
+	Qmax = 16,
+};
+
+typedef long Rdwrfn(Chan*, void*, long, vlong);
+
+static Rdwrfn *readfn[Qmax];
+static Rdwrfn *writefn[Qmax];
+
+static Dirtab archdir[Qmax] = {
+	".",		{ Qdir, 0, QTDIR },	0,	0555,
+};
+
+Lock archwlock;	/* the lock is only for changing archdir */
+QLock plock;
+int narchdir = Qbase;
+
+/*
+ * Add a file to the #P listing.  Once added, you can't delete it.
+ * You can't add a file with the same name as one already there,
+ * and you get a pointer to the Dirtab entry so you can do things
+ * like change the Qid version.  Changing the Qid path is disallowed.
+ */
+Dirtab*
+addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
+{
+	int i;
+	Dirtab d;
+	Dirtab *dp;
+
+	memset(&d, 0, sizeof d);
+	strcpy(d.name, name);
+	d.perm = perm;
+
+	lock(&archwlock);
+	if(narchdir >= Qmax){
+		unlock(&archwlock);
+		return nil;
+	}
+
+	for(i=0; i<narchdir; i++)
+		if(strcmp(archdir[i].name, name) == 0){
+			unlock(&archwlock);
+			return nil;
+		}
+
+	d.qid.path = narchdir;
+	archdir[narchdir] = d;
+	readfn[narchdir] = rdfn;
+	writefn[narchdir] = wrfn;
+	dp = &archdir[narchdir++];
+	unlock(&archwlock);
+
+	return dp;
+}
+
+static Chan*
+archattach(char* spec)
+{
+	return devattach('P', spec);
+}
+
+Walkqid*
+archwalk(Chan* c, Chan *nc, char** name, int nname)
+{
+	return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
+}
+
+static int
+archstat(Chan* c, uchar* dp, int n)
+{
+	return devstat(c, dp, n, archdir, narchdir, devgen);
+}
+
+static Chan*
+archopen(Chan* c, int omode)
+{
+	return devopen(c, omode, archdir, narchdir, devgen);
+}
+
+static void
+archclose(Chan*)
+{
+}
+
+static long
+archread(Chan *c, void *a, long n, vlong offset)
+{
+	Rdwrfn *fn;
+
+	switch((ulong)c->qid.path){
+	case Qdir:
+		return devdirread(c, a, n, archdir, narchdir, devgen);
+
+	default:
+		if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
+			return fn(c, a, n, offset);
+		error(Eperm);
+		break;
+	}
+
+	return 0;
+}
+
+static long
+archwrite(Chan *c, void *a, long n, vlong offset)
+{
+	Rdwrfn *fn;
+
+	if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
+		return fn(c, a, n, offset);
+	error(Eperm);
+
+	return 0;
+}
+
+void archinit(void);
+
+Dev archdevtab = {
+	'P',
+	"arch",
+
+	devreset,
+	archinit,
+	devshutdown,
+	archattach,
+	archwalk,
+	archstat,
+	archopen,
+	devcreate,
+	archclose,
+	archread,
+	devbread,
+	archwrite,
+	devbwrite,
+	devremove,
+	devwstat,
+};
+
+
+static long
+cputyperead(Chan*, void *a, long n, vlong offset)
+{
+	u32int pridval, conf0val, conf1val;
+	u8int compop, compid, procid, revision;
+	u8int major, minor, patch;
+	u8int fpu, cop2, tlbs, coher;
+	int icache, dcache;
+	char *procidstr, *endian, *writetype;
+
+	char *p;
+	int l;
+
+	pridval = prid();
+	conf0val = getconfig();
+	conf1val = getconfig1();
+
+	compop = (pridval >> 24) & 0xFF;
+	compid = (pridval >> 16) & 0xFF;
+	procid = (pridval >> 8) & 0xFF;
+	revision = pridval & 0xFF;
+
+	patch = revision & 0x3;
+	minor = (revision >> 2) & 0x7;
+	major = (revision >> 5) & 0x7;
+
+	switch(procid){
+	case 0x93:
+		procidstr = "24K";
+		break;
+	case 0x96:
+		procidstr = "24KE";
+		break;
+	case 0x97:
+		procidstr = "74K";
+		break;
+	case 0x99:
+		procidstr = "1004K";
+		break;
+	default:
+		procidstr = "missingno";
+		break;
+	}
+
+	coher = conf0val & 0x7;
+
+	switch(coher){
+	case 0:
+		writetype = "write-through";
+		break;
+	case 2:
+		writetype = "uncached";
+		break;
+	case 3:
+		writetype = "write-back";
+		break;
+	case 7:
+		writetype = "uncached accelerated";
+		break;
+	default:
+		writetype = "unknown";
+		break;
+	}
+
+	endian = conf0val & (1<<15)? "mips" : "spim";
+	fpu = conf1val & 0x1? 1 : 0;
+	cop2 = conf1val & 0x40? 1 : 0;
+	tlbs = ((conf1val >> 25) & 0x3F) + 1;
+	icache = (64 << ((conf1val >> 22) & 0x7)) / 8;
+	dcache = (64 << ((conf1val >> 13) & 0x7)) / 8;
+
+	p = smalloc(READSTR);
+	l = 0;
+
+	l += snprint(p+l, READSTR-l, "%s %s\n", endian, procidstr);
+	l += snprint(p+l, READSTR-l, "%uX %uX %d.%d.%d\n",
+		compid, compop, major, minor, patch);
+	l += snprint(p+l, READSTR-l, "%dkB icache, %dkB dcache, %s\n",
+		icache, dcache, writetype);
+	l += snprint(p+l, READSTR-l, "%d TLB entries\n", tlbs);
+	l += snprint(p+l, READSTR-l, "fpu: %s\n", fpu ? "yes" : "no");
+	l += snprint(p+l, READSTR-l, "cop2: %s\n", cop2 ? "yes" : "no");
+
+	n = readstr(offset, a, n, p);
+	free(p);
+	USED(l);
+
+	return n;
+}
+
+
+typedef struct Gate Gate;
+
+struct Gate {
+	char	*name;
+	u32int	cmask;
+	u32int	rmask;
+};
+
+static Gate gate[] = {
+	{"PWM		",	1<<31,	1<<31},
+	{"SDXC		",	1<<30,	1<<30},
+	{"Crypto		",	1<<29,	1<<29},
+	{"Mips Cnt	",	1<<28,	1<<28},
+	{"PCIE2		",	1<<26,	1<<26},
+	{"Uphy		",	1<<25,	0},
+	{"Ephy		",	0,		1<<24},
+	{"Ether		",	1<<23,	1<<23},
+	{"USB		",	0,		1<<22},
+	{"uart2		",	1<<20,	1<<20},
+	{"uart1		",	1<<19,	1<<19},
+	{"SPI		",	1<<18,	1<<18},
+	{"I2S		",	1<<17,	1<<17},
+	{"I²C		",	1<<16,	1<<16},
+	{"GDMA		",	1<<14,	1<<14},
+	{"PIO		",	1<<13,	1<<13},
+	{"uart		",	1<<12,	1<<12},
+	{"PCM		",	1<<11,	1<<11},
+	{"MC		",	1<<10,	1<<10},
+	{"Int		",	1<<9,	1<<9},
+	{"timer		",	1<<8,	1<<8},
+	{"HIF		",	0,		1<<5},
+	{"WiFI		",	0,		1<<4},
+	{"SPIs		",	0,		1<<3},
+	{"System		",	0,		1<<0},
+};
+
+
+static long
+sysctlread(Chan*, void *a, long n, vlong offset)
+{
+	u32int chipid1 = *IO(u32int, (SYSCTLBASE + 0x00));
+	u32int chipid2 = *IO(u32int, (SYSCTLBASE + 0x04));
+	u32int clocks = *IO(u32int, (SYSCTLBASE + 0x30));
+	u32int resets = *IO(u32int, (SYSCTLBASE + 0x34));
+
+	char chipid[8], *cstate, *rstate;
+
+	char *p;
+	int l, i;
+	
+	chipid[0] = chipid1 & 0xFF;
+	chipid[1] = (chipid1 >> 8) & 0xFF;
+	chipid[2] = (chipid1 >> 16) & 0xFF;
+	chipid[3] = (chipid1 >> 24) & 0xFF;
+	chipid[4] = chipid2 & 0xFF;
+	chipid[5] = (chipid2 >> 8) & 0xFF;
+	chipid[6] = (chipid2 >> 16) & 0xFF;
+	chipid[7] = (chipid2 >> 24) & 0xFF;
+
+	p = smalloc(READSTR);
+	l = 0;
+
+	l += snprint(p+l, READSTR-l, "chipID: %s\n", chipid);
+	l += snprint(p+l, READSTR-l, "device\t\tclock\treset\n");
+
+	for(i = 0; i < nelem(gate); i++){
+		if(gate[i].cmask == 0){
+			cstate = "n/a";
+		} else {
+			cstate = clocks & gate[i].cmask ? "on" : "off";
+		}
+
+		if(gate[i].rmask == 0){
+			rstate = "n/a";
+		} else {
+			rstate = resets & gate[i].rmask ? "on" : "off";
+		}
+
+		l += snprint(p+l, READSTR-l, "%s%s\t%s\n", gate[i].name, cstate, rstate);
+	}
+
+	n = readstr(offset, a, n, p);
+	free(p);
+
+	return n;
+}
+
+
+void
+archinit(void)
+{
+
+	addarchfile("cputype", 0444, cputyperead, nil);
+	addarchfile("sysctl", 0444, sysctlread, nil);
+
+}
--- /dev/null
+++ b/sys/src/9/mt7688/i2c7688.c
@@ -1,0 +1,237 @@
+/*
+ * I²C driver for MT7688
+ */
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"../port/error.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"io.h"
+#include	"../port/i2c.h"
+
+
+enum {
+	I²C_SM0CFG2	=	0x28,
+	I²C_SM0CTL0	=	0x40,
+	ctl0_strch	=	1<<0,
+	clt0_en		=	1<<1,
+	I²C_SM0CTL1	=	0x44,
+	ctl1_trig	=	1<<0,
+	ctl1_start	=	1<<4,
+	ctl1_write	=	2<<4,
+	ctl1_stop	=	3<<4,
+	ctl1_rnack	=	4<<4,
+	ctl1_rack	=	5<<4,
+	I²C_SM0D0	=	0x50,
+	I²C_SM0D1	=	0x54,
+};
+
+#define	ctl0_clkdiv(x)	(((x) & 0x7FF) << 16)
+
+#define i2crd(o)	(*IO(u32int, (I2CBASE + (o))))
+#define	i2cwr(o, v)	(*IO(u32int, (I2CBASE + (o))) = (v))
+
+int i2cdebug = 0;
+
+
+typedef struct Ctlr Ctlr;
+struct Ctlr
+{
+	int		clkdiv;
+};
+
+
+static void
+reset(Ctlr *ctlr)
+{
+	i2cwr(I²C_SM0CTL0, ctl0_strch | clt0_en | ctl0_clkdiv(ctlr->clkdiv));
+	i2cwr(I²C_SM0CFG2, 0x0);
+
+	if(i2cdebug)
+		print("i2c reset: %lux\n", i2crd(I²C_SM0CTL0));
+}
+
+
+static int
+init(I2Cbus *bus)
+{
+	Ctlr *ctlr = bus->ctlr;
+
+/*
+ *	Base clock on MT7688 is 40MHz
+ *	To get the standard speed for I²C of 100kHz,
+ *	40MHz / 100kHz (and -1 to round up)
+ */
+
+	ctlr->clkdiv = 40000000 / (bus->speed - 1);
+
+	reset(ctlr);
+
+	return 0;
+}
+
+
+static void
+i2cstop(void)
+{
+	i2cwr(I²C_SM0CTL1, ctl1_stop | ctl1_trig);
+}
+
+
+static int
+i2cbusy(void)
+{
+	u32int buf;
+	int t;
+
+	for(t = 0; t < 1000; t++){
+		buf = i2crd(I²C_SM0CTL1);
+		if((buf & ctl1_trig) == 0){
+			return 0;
+		}
+		delay(1);
+	}
+
+	i2cstop();
+	return 1;
+}
+
+
+static int
+i2cstart(u32int flag, u32int bytes)
+{
+	if(bytes > 0)
+		bytes = bytes - 1;
+
+	i2cwr(I²C_SM0CTL1, ctl1_trig | flag | bytes << 8);
+
+	if(i2cbusy()){
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static int
+i2cack(u32int bytes)
+{
+	u32int buf, ack, expect;
+
+	expect = (1 << bytes) - 1;
+	buf = i2crd(I²C_SM0CTL1);
+	ack = (buf >> 16) & 0xFF;
+
+	if(i2cdebug)
+		print("want; %d - got: %d - \n", expect, ack);
+
+	if(ack == expect){
+		return 0;
+	}
+
+	i2cstop();
+	return 1;
+}
+
+
+static int
+io(I2Cdev *dev, uchar *pkt, int olen, int ilen)
+{
+	int oΔ, iΔ, i, bytes;
+	u16int addr, last;
+	u32int data[2];
+
+
+	if(i2cdebug){
+		int alen = 1;
+		if(olen > alen && (pkt[0] & 0xF8) == 0xF0)
+			alen++;
+
+		if(alen > 1){
+			addr = pkt[1] | (pkt[0] << 8);
+		} else {
+			addr = pkt[0];
+		}
+
+		print("addr: %uX - ", addr>>1);
+	}
+
+	if(i2cbusy()){
+		print("I²C not ready\n");
+		return 0;
+	}
+
+	if(i2cstart(ctl1_start, 0)){
+		print("I²C no start\n");
+		return 0;
+	}
+
+	i = 0;
+	oΔ = olen;
+	iΔ = ilen;
+
+	if(i2cdebug)
+		print("total out: %d - in: %d - ", oΔ, iΔ);
+
+	while(oΔ){
+		bytes = (oΔ >= 8) ? 8 : oΔ;
+		data[0] = 0;
+		data[1] = 0;
+		memmove(data, &pkt[i], bytes);
+		i2cwr(I²C_SM0D0, data[0]);
+		i2cwr(I²C_SM0D1, data[1]);
+		if(i2cstart(ctl1_write, bytes)){
+			print("I²C timeout\n");
+			return 0;
+		}
+		if(i2cack(bytes)){
+			if(i2cdebug)
+				print("I²C write failed\n");
+			return 0;
+		}
+		i += bytes;
+		oΔ -= bytes;
+	}
+
+	while(iΔ){
+		bytes = (iΔ >= 8) ? 8 : iΔ;
+		data[0] = 0;
+		data[1] = 0;
+		last = (iΔ < 8) ? ctl1_rnack : ctl1_rack;
+		if(i2cstart(last, bytes)){
+			print("I²C timeout\n");
+			return 0;
+		}
+		data[0] = i2crd(I²C_SM0D0);
+		data[1] = i2crd(I²C_SM0D1);
+		memmove(&pkt[i], data, bytes);
+		if(last == ctl1_rack){
+			if(i2cack(bytes)){
+				if(i2cdebug)
+					print("I²C read failed\n");
+				return 0;
+			}
+		}
+		i += bytes;
+		iΔ -= bytes;
+	}
+
+	if(i2cdebug)
+		print("return: %d \n", i);
+
+	i2cstop();
+
+	return i;
+}
+
+
+static Ctlr ctlr1;
+
+
+void
+i2c7688link(void)
+{
+	static I2Cbus i2c1 = {"i2c1", 400000, &ctlr1, init, io};
+	addi2cbus(&i2c1);
+}