acpi(4): GenericSerialBus OperationRegion support

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

acpi(4): GenericSerialBus OperationRegion support

Mark Kettenis
The diff below implements functionality that allows AML access to
devices that sit on an I2C bus.  Only a subset of the various access
methods is implemented; some of the missing ones are not a very good
fit for our AML implementation.  But this is enough to make reading
the battery status on the little Lenovo that mlarkin@ handed me at Elk
Lakes work.

Probably needs some wider testing.

After that's done, ok?


Index: dev/acpi/acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
retrieving revision 1.341
diff -u -p -r1.341 acpi.c
--- dev/acpi/acpi.c 27 Mar 2018 21:11:16 -0000 1.341
+++ dev/acpi/acpi.c 13 May 2018 13:49:46 -0000
@@ -920,6 +920,23 @@ acpi_register_gpio(struct acpi_softc *sc
 }
 
 void
+acpi_register_gsb(struct acpi_softc *sc, struct aml_node *devnode)
+{
+ struct aml_value arg[2];
+ struct aml_node *node;
+
+ /* Register GenericSerialBus address space. */
+ memset(&arg, 0, sizeof(arg));
+ arg[0].type = AML_OBJTYPE_INTEGER;
+ arg[0].v_integer = ACPI_OPREG_GSB;
+ arg[1].type = AML_OBJTYPE_INTEGER;
+ arg[1].v_integer = 1;
+ node = aml_searchname(devnode, "_REG");
+ if (node && aml_evalnode(sc, node, 2, arg, NULL))
+ printf("%s: _REG failed\n", node->name);
+}
+
+void
 acpi_attach(struct device *parent, struct device *self, void *aux)
 {
  struct bios_attach_args *ba = aux;
Index: dev/acpi/acpivar.h
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpivar.h,v
retrieving revision 1.89
diff -u -p -r1.89 acpivar.h
--- dev/acpi/acpivar.h 29 Nov 2017 22:51:01 -0000 1.89
+++ dev/acpi/acpivar.h 13 May 2018 13:49:46 -0000
@@ -333,6 +333,7 @@ void acpi_wakeup(void *);
 int acpi_gasio(struct acpi_softc *, int, int, uint64_t, int, int, void *);
 
 void acpi_register_gpio(struct acpi_softc *, struct aml_node *);
+void acpi_register_gsb(struct acpi_softc *, struct aml_node *);
 
 int acpi_set_gpehandler(struct acpi_softc *, int,
     int (*)(struct acpi_softc *, int, void *), void *, int);
Index: dev/acpi/amltypes.h
===================================================================
RCS file: /cvs/src/sys/dev/acpi/amltypes.h,v
retrieving revision 1.45
diff -u -p -r1.45 amltypes.h
--- dev/acpi/amltypes.h 8 May 2016 11:08:01 -0000 1.45
+++ dev/acpi/amltypes.h 13 May 2018 13:49:46 -0000
@@ -371,6 +371,8 @@ struct acpi_gpio {
  void (*intr_establish)(void *, int, int, int (*)(void *), void *);
 };
 
+struct i2c_controller;
+
 struct aml_node {
  struct aml_node *parent;
 
@@ -385,8 +387,9 @@ struct aml_node {
  u_int8_t *end;
 
  struct aml_value *value;
- struct acpi_pci  *pci;
+ struct acpi_pci *pci;
  struct acpi_gpio *gpio;
+ struct i2c_controller *i2c;
 };
 
 #define aml_bitmask(n) (1L << ((n) & 0x7))
Index: dev/acpi/dsdt.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v
retrieving revision 1.236
diff -u -p -r1.236 dsdt.c
--- dev/acpi/dsdt.c 29 Nov 2017 15:22:22 -0000 1.236
+++ dev/acpi/dsdt.c 13 May 2018 13:49:47 -0000
@@ -33,6 +33,8 @@
 #include <dev/acpi/amltypes.h>
 #include <dev/acpi/dsdt.h>
 
+#include <dev/i2c/i2cvar.h>
+
 #ifdef SMALL_KERNEL
 #undef ACPI_DEBUG
 #endif
@@ -2288,6 +2290,7 @@ aml_register_regionspace(struct aml_node
 
 void aml_rwgen(struct aml_value *, int, int, struct aml_value *, int, int);
 void aml_rwgpio(struct aml_value *, int, int, struct aml_value *, int, int);
+void aml_rwgsb(struct aml_value *, int, int, struct aml_value *, int, int);
 void aml_rwindexfield(struct aml_value *, struct aml_value *val, int);
 void aml_rwfield(struct aml_value *, int, int, struct aml_value *, int);
 
@@ -2512,6 +2515,96 @@ aml_rwgpio(struct aml_value *conn, int b
 }
 
 void
+aml_rwgsb(struct aml_value *conn, int bpos, int blen, struct aml_value *val,
+    int mode, int flag)
+{
+ union acpi_resource *crs = (union acpi_resource *)conn->v_buffer;
+ struct aml_node *node;
+ i2c_tag_t tag;
+ i2c_op_t op;
+ i2c_addr_t addr;
+ int cmdlen, buflen;
+ uint8_t cmd;
+ uint8_t *buf;
+ int err;
+
+ if (conn->type != AML_OBJTYPE_BUFFER || conn->length < 5 ||
+    AML_CRSTYPE(crs) != LR_SERBUS || AML_CRSLEN(crs) > conn->length ||
+    crs->lr_i2cbus.revid != 1 || crs->lr_i2cbus.type != LR_SERBUS_I2C)
+ aml_die("Invalid GenericSerialBus");
+ if (AML_FIELD_ACCESS(flag) != AML_FIELD_BUFFERACC ||
+    bpos & 0x3 || blen != 8)
+ aml_die("Invalid GenericSerialBus access");
+
+ node = aml_searchname(conn->node,
+    (char *)&crs->lr_i2cbus.vdata[crs->lr_i2cbus.tlength - 6]);
+
+ if (node == NULL || node->i2c == NULL)
+ aml_die("Could not find GenericSerialBus controller");
+
+ switch (((flag >> 6) & 0x3)) {
+ case 0: /* Normal */
+ switch (AML_FIELD_ATTR(flag)) {
+ case 0x02: /* AttribQuick */
+ cmdlen = 0;
+ buflen = 0;
+ break;
+ case 0x04: /* AttribSendReceive */
+ cmdlen = 0;
+ buflen = 1;
+ break;
+ case 0x06: /* AttribByte */
+ cmdlen = 1;
+ buflen = 1;
+ break;
+ case 0x08: /* AttribWord */
+ cmdlen = 1;
+ buflen = 2;
+ break;
+ default:
+ aml_die("unsupported access type 0x%x", flag);
+ break;
+ }
+ break;
+ case 1: /* AttribBytes */
+ cmdlen = 1;
+ buflen = AML_FIELD_ATTR(flag);
+ break;
+ case 2: /* AttribRawBytes */
+ cmdlen = 0;
+ buflen = AML_FIELD_ATTR(flag);
+ break;
+ default:
+ aml_die("unsupported access type 0x%x", flag);
+ break;
+ }
+
+ if (mode == ACPI_IOREAD) {
+ _aml_setvalue(val, AML_OBJTYPE_BUFFER, buflen + 2, NULL);
+ op = I2C_OP_READ_WITH_STOP;
+ } else {
+ op = I2C_OP_WRITE_WITH_STOP;
+ }
+
+ tag = node->i2c;
+ addr = crs->lr_i2cbus._adr;
+ cmd = bpos >> 3;
+ buf = val->v_buffer;
+
+ iic_acquire_bus(tag, 0);
+ err = iic_exec(tag, op, addr, &cmd, cmdlen, &buf[2], buflen, 0);
+ iic_release_bus(tag, 0);
+
+ /*
+ * The ACPI specification doesn't tell us what the status
+ * codes mean beyond implying that zero means success.  So use
+ * the error returned from the transfer.  All possible error
+ * numbers should fit in a single bit.
+ */
+ buf[0] = err;
+}
+
+void
 aml_rwindexfield(struct aml_value *fld, struct aml_value *val, int mode)
 {
  struct aml_value tmp, *ref1, *ref2;
@@ -2612,6 +2705,10 @@ aml_rwfield(struct aml_value *fld, int b
  aml_rwgpio(ref2, bpos, blen, val, mode,
     fld->v_field.flags);
  break;
+ case ACPI_OPREG_GSB:
+ aml_rwgsb(ref2, fld->v_field.bitpos + bpos, blen,
+    val, mode, fld->v_field.flags);
+ break;
  default:
  aml_rwgen(ref1, fld->v_field.bitpos + bpos, blen,
     val, mode, fld->v_field.flags);
@@ -2699,9 +2796,11 @@ aml_parsefieldlist(struct aml_scope *msc
  mscope->pos++;
  blen = aml_parselength(mscope);
  break;
- case 0x01: /* flags */
- mscope->pos += 3;
+ case 0x01: /* attrib */
+ mscope->pos++;
  blen = 0;
+ flags = aml_get8(mscope->pos++);
+ flags |= aml_get8(mscope->pos++) << 8;
  break;
  case 0x02: /* connection */
  mscope->pos++;
Index: dev/acpi/dwiic_acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/dwiic_acpi.c,v
retrieving revision 1.3
diff -u -p -r1.3 dwiic_acpi.c
--- dev/acpi/dwiic_acpi.c 19 Jan 2018 18:20:38 -0000 1.3
+++ dev/acpi/dwiic_acpi.c 13 May 2018 13:49:47 -0000
@@ -193,6 +193,9 @@ dwiic_acpi_attach(struct device *parent,
 
  config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
 
+ sc->sc_devnode->i2c = &sc->sc_i2c_tag;
+ acpi_register_gsb(sc->sc_acpi, sc->sc_devnode);
+
  return;
 }
 

Reply | Threaded
Open this post in threaded view
|

Re: acpi(4): GenericSerialBus OperationRegion support

Mike Larkin
On Sun, May 13, 2018 at 03:57:50PM +0200, Mark Kettenis wrote:
> The diff below implements functionality that allows AML access to
> devices that sit on an I2C bus.  Only a subset of the various access
> methods is implemented; some of the missing ones are not a very good
> fit for our AML implementation.  But this is enough to make reading
> the battery status on the little Lenovo that mlarkin@ handed me at Elk
> Lakes work.
>

Can you elaborate on what isn't a good fit? Just curious.

-ml

> Probably needs some wider testing.
>
> After that's done, ok?
>
>
> Index: dev/acpi/acpi.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
> retrieving revision 1.341
> diff -u -p -r1.341 acpi.c
> --- dev/acpi/acpi.c 27 Mar 2018 21:11:16 -0000 1.341
> +++ dev/acpi/acpi.c 13 May 2018 13:49:46 -0000
> @@ -920,6 +920,23 @@ acpi_register_gpio(struct acpi_softc *sc
>  }
>  
>  void
> +acpi_register_gsb(struct acpi_softc *sc, struct aml_node *devnode)
> +{
> + struct aml_value arg[2];
> + struct aml_node *node;
> +
> + /* Register GenericSerialBus address space. */
> + memset(&arg, 0, sizeof(arg));
> + arg[0].type = AML_OBJTYPE_INTEGER;
> + arg[0].v_integer = ACPI_OPREG_GSB;
> + arg[1].type = AML_OBJTYPE_INTEGER;
> + arg[1].v_integer = 1;
> + node = aml_searchname(devnode, "_REG");
> + if (node && aml_evalnode(sc, node, 2, arg, NULL))
> + printf("%s: _REG failed\n", node->name);
> +}
> +
> +void
>  acpi_attach(struct device *parent, struct device *self, void *aux)
>  {
>   struct bios_attach_args *ba = aux;
> Index: dev/acpi/acpivar.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/acpivar.h,v
> retrieving revision 1.89
> diff -u -p -r1.89 acpivar.h
> --- dev/acpi/acpivar.h 29 Nov 2017 22:51:01 -0000 1.89
> +++ dev/acpi/acpivar.h 13 May 2018 13:49:46 -0000
> @@ -333,6 +333,7 @@ void acpi_wakeup(void *);
>  int acpi_gasio(struct acpi_softc *, int, int, uint64_t, int, int, void *);
>  
>  void acpi_register_gpio(struct acpi_softc *, struct aml_node *);
> +void acpi_register_gsb(struct acpi_softc *, struct aml_node *);
>  
>  int acpi_set_gpehandler(struct acpi_softc *, int,
>      int (*)(struct acpi_softc *, int, void *), void *, int);
> Index: dev/acpi/amltypes.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/amltypes.h,v
> retrieving revision 1.45
> diff -u -p -r1.45 amltypes.h
> --- dev/acpi/amltypes.h 8 May 2016 11:08:01 -0000 1.45
> +++ dev/acpi/amltypes.h 13 May 2018 13:49:46 -0000
> @@ -371,6 +371,8 @@ struct acpi_gpio {
>   void (*intr_establish)(void *, int, int, int (*)(void *), void *);
>  };
>  
> +struct i2c_controller;
> +
>  struct aml_node {
>   struct aml_node *parent;
>  
> @@ -385,8 +387,9 @@ struct aml_node {
>   u_int8_t *end;
>  
>   struct aml_value *value;
> - struct acpi_pci  *pci;
> + struct acpi_pci *pci;
>   struct acpi_gpio *gpio;
> + struct i2c_controller *i2c;
>  };
>  
>  #define aml_bitmask(n) (1L << ((n) & 0x7))
> Index: dev/acpi/dsdt.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v
> retrieving revision 1.236
> diff -u -p -r1.236 dsdt.c
> --- dev/acpi/dsdt.c 29 Nov 2017 15:22:22 -0000 1.236
> +++ dev/acpi/dsdt.c 13 May 2018 13:49:47 -0000
> @@ -33,6 +33,8 @@
>  #include <dev/acpi/amltypes.h>
>  #include <dev/acpi/dsdt.h>
>  
> +#include <dev/i2c/i2cvar.h>
> +
>  #ifdef SMALL_KERNEL
>  #undef ACPI_DEBUG
>  #endif
> @@ -2288,6 +2290,7 @@ aml_register_regionspace(struct aml_node
>  
>  void aml_rwgen(struct aml_value *, int, int, struct aml_value *, int, int);
>  void aml_rwgpio(struct aml_value *, int, int, struct aml_value *, int, int);
> +void aml_rwgsb(struct aml_value *, int, int, struct aml_value *, int, int);
>  void aml_rwindexfield(struct aml_value *, struct aml_value *val, int);
>  void aml_rwfield(struct aml_value *, int, int, struct aml_value *, int);
>  
> @@ -2512,6 +2515,96 @@ aml_rwgpio(struct aml_value *conn, int b
>  }
>  
>  void
> +aml_rwgsb(struct aml_value *conn, int bpos, int blen, struct aml_value *val,
> +    int mode, int flag)
> +{
> + union acpi_resource *crs = (union acpi_resource *)conn->v_buffer;
> + struct aml_node *node;
> + i2c_tag_t tag;
> + i2c_op_t op;
> + i2c_addr_t addr;
> + int cmdlen, buflen;
> + uint8_t cmd;
> + uint8_t *buf;
> + int err;
> +
> + if (conn->type != AML_OBJTYPE_BUFFER || conn->length < 5 ||
> +    AML_CRSTYPE(crs) != LR_SERBUS || AML_CRSLEN(crs) > conn->length ||
> +    crs->lr_i2cbus.revid != 1 || crs->lr_i2cbus.type != LR_SERBUS_I2C)
> + aml_die("Invalid GenericSerialBus");
> + if (AML_FIELD_ACCESS(flag) != AML_FIELD_BUFFERACC ||
> +    bpos & 0x3 || blen != 8)
> + aml_die("Invalid GenericSerialBus access");
> +
> + node = aml_searchname(conn->node,
> +    (char *)&crs->lr_i2cbus.vdata[crs->lr_i2cbus.tlength - 6]);
> +
> + if (node == NULL || node->i2c == NULL)
> + aml_die("Could not find GenericSerialBus controller");
> +
> + switch (((flag >> 6) & 0x3)) {
> + case 0: /* Normal */
> + switch (AML_FIELD_ATTR(flag)) {
> + case 0x02: /* AttribQuick */
> + cmdlen = 0;
> + buflen = 0;
> + break;
> + case 0x04: /* AttribSendReceive */
> + cmdlen = 0;
> + buflen = 1;
> + break;
> + case 0x06: /* AttribByte */
> + cmdlen = 1;
> + buflen = 1;
> + break;
> + case 0x08: /* AttribWord */
> + cmdlen = 1;
> + buflen = 2;
> + break;
> + default:
> + aml_die("unsupported access type 0x%x", flag);
> + break;
> + }
> + break;
> + case 1: /* AttribBytes */
> + cmdlen = 1;
> + buflen = AML_FIELD_ATTR(flag);
> + break;
> + case 2: /* AttribRawBytes */
> + cmdlen = 0;
> + buflen = AML_FIELD_ATTR(flag);
> + break;
> + default:
> + aml_die("unsupported access type 0x%x", flag);
> + break;
> + }
> +
> + if (mode == ACPI_IOREAD) {
> + _aml_setvalue(val, AML_OBJTYPE_BUFFER, buflen + 2, NULL);
> + op = I2C_OP_READ_WITH_STOP;
> + } else {
> + op = I2C_OP_WRITE_WITH_STOP;
> + }
> +
> + tag = node->i2c;
> + addr = crs->lr_i2cbus._adr;
> + cmd = bpos >> 3;
> + buf = val->v_buffer;
> +
> + iic_acquire_bus(tag, 0);
> + err = iic_exec(tag, op, addr, &cmd, cmdlen, &buf[2], buflen, 0);
> + iic_release_bus(tag, 0);
> +
> + /*
> + * The ACPI specification doesn't tell us what the status
> + * codes mean beyond implying that zero means success.  So use
> + * the error returned from the transfer.  All possible error
> + * numbers should fit in a single bit.
> + */
> + buf[0] = err;
> +}
> +
> +void
>  aml_rwindexfield(struct aml_value *fld, struct aml_value *val, int mode)
>  {
>   struct aml_value tmp, *ref1, *ref2;
> @@ -2612,6 +2705,10 @@ aml_rwfield(struct aml_value *fld, int b
>   aml_rwgpio(ref2, bpos, blen, val, mode,
>      fld->v_field.flags);
>   break;
> + case ACPI_OPREG_GSB:
> + aml_rwgsb(ref2, fld->v_field.bitpos + bpos, blen,
> +    val, mode, fld->v_field.flags);
> + break;
>   default:
>   aml_rwgen(ref1, fld->v_field.bitpos + bpos, blen,
>      val, mode, fld->v_field.flags);
> @@ -2699,9 +2796,11 @@ aml_parsefieldlist(struct aml_scope *msc
>   mscope->pos++;
>   blen = aml_parselength(mscope);
>   break;
> - case 0x01: /* flags */
> - mscope->pos += 3;
> + case 0x01: /* attrib */
> + mscope->pos++;
>   blen = 0;
> + flags = aml_get8(mscope->pos++);
> + flags |= aml_get8(mscope->pos++) << 8;
>   break;
>   case 0x02: /* connection */
>   mscope->pos++;
> Index: dev/acpi/dwiic_acpi.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/acpi/dwiic_acpi.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 dwiic_acpi.c
> --- dev/acpi/dwiic_acpi.c 19 Jan 2018 18:20:38 -0000 1.3
> +++ dev/acpi/dwiic_acpi.c 13 May 2018 13:49:47 -0000
> @@ -193,6 +193,9 @@ dwiic_acpi_attach(struct device *parent,
>  
>   config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
>  
> + sc->sc_devnode->i2c = &sc->sc_i2c_tag;
> + acpi_register_gsb(sc->sc_acpi, sc->sc_devnode);
> +
>   return;
>  }
>  
>

Reply | Threaded
Open this post in threaded view
|

Re: acpi(4): GenericSerialBus OperationRegion support

Mark Kettenis
> Date: Sun, 13 May 2018 22:27:09 -0700
> From: Mike Larkin <[hidden email]>
>
> On Sun, May 13, 2018 at 03:57:50PM +0200, Mark Kettenis wrote:
> > The diff below implements functionality that allows AML access to
> > devices that sit on an I2C bus.  Only a subset of the various access
> > methods is implemented; some of the missing ones are not a very good
> > fit for our AML implementation.  But this is enough to make reading
> > the battery status on the little Lenovo that mlarkin@ handed me at Elk
> > Lakes work.
> >
>
> Can you elaborate on what isn't a good fit? Just curious.

Our i2c layer makes implementing the "Block" access types awkward, at
least for reads.  At least it isn't obvious to me what implementation
would work.

The AML interpreter makes implementing the "ProcessCall" interfaces
hard at least for reads as in that case the code doesn't see the
buffer that contains the values that have to be written.

We can probably find a way to make this work, but I don't seem to have
any devices that use these access types.

BTW, this stuff is important for the "suspend to idle" (S0ix) stuff.
Most platforms supporting S0ix have some sort of Power Management IC
(PMIC) ooked up over I2C that is involved in powering stuff down for
the deepest idle states.

> > Probably needs some wider testing.
> >
> > After that's done, ok?
> >
> >
> > Index: dev/acpi/acpi.c
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
> > retrieving revision 1.341
> > diff -u -p -r1.341 acpi.c
> > --- dev/acpi/acpi.c 27 Mar 2018 21:11:16 -0000 1.341
> > +++ dev/acpi/acpi.c 13 May 2018 13:49:46 -0000
> > @@ -920,6 +920,23 @@ acpi_register_gpio(struct acpi_softc *sc
> >  }
> >  
> >  void
> > +acpi_register_gsb(struct acpi_softc *sc, struct aml_node *devnode)
> > +{
> > + struct aml_value arg[2];
> > + struct aml_node *node;
> > +
> > + /* Register GenericSerialBus address space. */
> > + memset(&arg, 0, sizeof(arg));
> > + arg[0].type = AML_OBJTYPE_INTEGER;
> > + arg[0].v_integer = ACPI_OPREG_GSB;
> > + arg[1].type = AML_OBJTYPE_INTEGER;
> > + arg[1].v_integer = 1;
> > + node = aml_searchname(devnode, "_REG");
> > + if (node && aml_evalnode(sc, node, 2, arg, NULL))
> > + printf("%s: _REG failed\n", node->name);
> > +}
> > +
> > +void
> >  acpi_attach(struct device *parent, struct device *self, void *aux)
> >  {
> >   struct bios_attach_args *ba = aux;
> > Index: dev/acpi/acpivar.h
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/acpi/acpivar.h,v
> > retrieving revision 1.89
> > diff -u -p -r1.89 acpivar.h
> > --- dev/acpi/acpivar.h 29 Nov 2017 22:51:01 -0000 1.89
> > +++ dev/acpi/acpivar.h 13 May 2018 13:49:46 -0000
> > @@ -333,6 +333,7 @@ void acpi_wakeup(void *);
> >  int acpi_gasio(struct acpi_softc *, int, int, uint64_t, int, int, void *);
> >  
> >  void acpi_register_gpio(struct acpi_softc *, struct aml_node *);
> > +void acpi_register_gsb(struct acpi_softc *, struct aml_node *);
> >  
> >  int acpi_set_gpehandler(struct acpi_softc *, int,
> >      int (*)(struct acpi_softc *, int, void *), void *, int);
> > Index: dev/acpi/amltypes.h
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/acpi/amltypes.h,v
> > retrieving revision 1.45
> > diff -u -p -r1.45 amltypes.h
> > --- dev/acpi/amltypes.h 8 May 2016 11:08:01 -0000 1.45
> > +++ dev/acpi/amltypes.h 13 May 2018 13:49:46 -0000
> > @@ -371,6 +371,8 @@ struct acpi_gpio {
> >   void (*intr_establish)(void *, int, int, int (*)(void *), void *);
> >  };
> >  
> > +struct i2c_controller;
> > +
> >  struct aml_node {
> >   struct aml_node *parent;
> >  
> > @@ -385,8 +387,9 @@ struct aml_node {
> >   u_int8_t *end;
> >  
> >   struct aml_value *value;
> > - struct acpi_pci  *pci;
> > + struct acpi_pci *pci;
> >   struct acpi_gpio *gpio;
> > + struct i2c_controller *i2c;
> >  };
> >  
> >  #define aml_bitmask(n) (1L << ((n) & 0x7))
> > Index: dev/acpi/dsdt.c
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v
> > retrieving revision 1.236
> > diff -u -p -r1.236 dsdt.c
> > --- dev/acpi/dsdt.c 29 Nov 2017 15:22:22 -0000 1.236
> > +++ dev/acpi/dsdt.c 13 May 2018 13:49:47 -0000
> > @@ -33,6 +33,8 @@
> >  #include <dev/acpi/amltypes.h>
> >  #include <dev/acpi/dsdt.h>
> >  
> > +#include <dev/i2c/i2cvar.h>
> > +
> >  #ifdef SMALL_KERNEL
> >  #undef ACPI_DEBUG
> >  #endif
> > @@ -2288,6 +2290,7 @@ aml_register_regionspace(struct aml_node
> >  
> >  void aml_rwgen(struct aml_value *, int, int, struct aml_value *, int, int);
> >  void aml_rwgpio(struct aml_value *, int, int, struct aml_value *, int, int);
> > +void aml_rwgsb(struct aml_value *, int, int, struct aml_value *, int, int);
> >  void aml_rwindexfield(struct aml_value *, struct aml_value *val, int);
> >  void aml_rwfield(struct aml_value *, int, int, struct aml_value *, int);
> >  
> > @@ -2512,6 +2515,96 @@ aml_rwgpio(struct aml_value *conn, int b
> >  }
> >  
> >  void
> > +aml_rwgsb(struct aml_value *conn, int bpos, int blen, struct aml_value *val,
> > +    int mode, int flag)
> > +{
> > + union acpi_resource *crs = (union acpi_resource *)conn->v_buffer;
> > + struct aml_node *node;
> > + i2c_tag_t tag;
> > + i2c_op_t op;
> > + i2c_addr_t addr;
> > + int cmdlen, buflen;
> > + uint8_t cmd;
> > + uint8_t *buf;
> > + int err;
> > +
> > + if (conn->type != AML_OBJTYPE_BUFFER || conn->length < 5 ||
> > +    AML_CRSTYPE(crs) != LR_SERBUS || AML_CRSLEN(crs) > conn->length ||
> > +    crs->lr_i2cbus.revid != 1 || crs->lr_i2cbus.type != LR_SERBUS_I2C)
> > + aml_die("Invalid GenericSerialBus");
> > + if (AML_FIELD_ACCESS(flag) != AML_FIELD_BUFFERACC ||
> > +    bpos & 0x3 || blen != 8)
> > + aml_die("Invalid GenericSerialBus access");
> > +
> > + node = aml_searchname(conn->node,
> > +    (char *)&crs->lr_i2cbus.vdata[crs->lr_i2cbus.tlength - 6]);
> > +
> > + if (node == NULL || node->i2c == NULL)
> > + aml_die("Could not find GenericSerialBus controller");
> > +
> > + switch (((flag >> 6) & 0x3)) {
> > + case 0: /* Normal */
> > + switch (AML_FIELD_ATTR(flag)) {
> > + case 0x02: /* AttribQuick */
> > + cmdlen = 0;
> > + buflen = 0;
> > + break;
> > + case 0x04: /* AttribSendReceive */
> > + cmdlen = 0;
> > + buflen = 1;
> > + break;
> > + case 0x06: /* AttribByte */
> > + cmdlen = 1;
> > + buflen = 1;
> > + break;
> > + case 0x08: /* AttribWord */
> > + cmdlen = 1;
> > + buflen = 2;
> > + break;
> > + default:
> > + aml_die("unsupported access type 0x%x", flag);
> > + break;
> > + }
> > + break;
> > + case 1: /* AttribBytes */
> > + cmdlen = 1;
> > + buflen = AML_FIELD_ATTR(flag);
> > + break;
> > + case 2: /* AttribRawBytes */
> > + cmdlen = 0;
> > + buflen = AML_FIELD_ATTR(flag);
> > + break;
> > + default:
> > + aml_die("unsupported access type 0x%x", flag);
> > + break;
> > + }
> > +
> > + if (mode == ACPI_IOREAD) {
> > + _aml_setvalue(val, AML_OBJTYPE_BUFFER, buflen + 2, NULL);
> > + op = I2C_OP_READ_WITH_STOP;
> > + } else {
> > + op = I2C_OP_WRITE_WITH_STOP;
> > + }
> > +
> > + tag = node->i2c;
> > + addr = crs->lr_i2cbus._adr;
> > + cmd = bpos >> 3;
> > + buf = val->v_buffer;
> > +
> > + iic_acquire_bus(tag, 0);
> > + err = iic_exec(tag, op, addr, &cmd, cmdlen, &buf[2], buflen, 0);
> > + iic_release_bus(tag, 0);
> > +
> > + /*
> > + * The ACPI specification doesn't tell us what the status
> > + * codes mean beyond implying that zero means success.  So use
> > + * the error returned from the transfer.  All possible error
> > + * numbers should fit in a single bit.
> > + */
> > + buf[0] = err;
> > +}
> > +
> > +void
> >  aml_rwindexfield(struct aml_value *fld, struct aml_value *val, int mode)
> >  {
> >   struct aml_value tmp, *ref1, *ref2;
> > @@ -2612,6 +2705,10 @@ aml_rwfield(struct aml_value *fld, int b
> >   aml_rwgpio(ref2, bpos, blen, val, mode,
> >      fld->v_field.flags);
> >   break;
> > + case ACPI_OPREG_GSB:
> > + aml_rwgsb(ref2, fld->v_field.bitpos + bpos, blen,
> > +    val, mode, fld->v_field.flags);
> > + break;
> >   default:
> >   aml_rwgen(ref1, fld->v_field.bitpos + bpos, blen,
> >      val, mode, fld->v_field.flags);
> > @@ -2699,9 +2796,11 @@ aml_parsefieldlist(struct aml_scope *msc
> >   mscope->pos++;
> >   blen = aml_parselength(mscope);
> >   break;
> > - case 0x01: /* flags */
> > - mscope->pos += 3;
> > + case 0x01: /* attrib */
> > + mscope->pos++;
> >   blen = 0;
> > + flags = aml_get8(mscope->pos++);
> > + flags |= aml_get8(mscope->pos++) << 8;
> >   break;
> >   case 0x02: /* connection */
> >   mscope->pos++;
> > Index: dev/acpi/dwiic_acpi.c
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/acpi/dwiic_acpi.c,v
> > retrieving revision 1.3
> > diff -u -p -r1.3 dwiic_acpi.c
> > --- dev/acpi/dwiic_acpi.c 19 Jan 2018 18:20:38 -0000 1.3
> > +++ dev/acpi/dwiic_acpi.c 13 May 2018 13:49:47 -0000
> > @@ -193,6 +193,9 @@ dwiic_acpi_attach(struct device *parent,
> >  
> >   config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
> >  
> > + sc->sc_devnode->i2c = &sc->sc_i2c_tag;
> > + acpi_register_gsb(sc->sc_acpi, sc->sc_devnode);
> > +
> >   return;
> >  }
> >  
> >
>

Reply | Threaded
Open this post in threaded view
|

Re: acpi(4): GenericSerialBus OperationRegion support

Mike Larkin
On Mon, May 14, 2018 at 08:22:47PM +0200, Mark Kettenis wrote:

> > Date: Sun, 13 May 2018 22:27:09 -0700
> > From: Mike Larkin <[hidden email]>
> >
> > On Sun, May 13, 2018 at 03:57:50PM +0200, Mark Kettenis wrote:
> > > The diff below implements functionality that allows AML access to
> > > devices that sit on an I2C bus.  Only a subset of the various access
> > > methods is implemented; some of the missing ones are not a very good
> > > fit for our AML implementation.  But this is enough to make reading
> > > the battery status on the little Lenovo that mlarkin@ handed me at Elk
> > > Lakes work.
> > >
> >
> > Can you elaborate on what isn't a good fit? Just curious.
>
> Our i2c layer makes implementing the "Block" access types awkward, at
> least for reads.  At least it isn't obvious to me what implementation
> would work.
>
> The AML interpreter makes implementing the "ProcessCall" interfaces
> hard at least for reads as in that case the code doesn't see the
> buffer that contains the values that have to be written.
>
> We can probably find a way to make this work, but I don't seem to have
> any devices that use these access types.
>
> BTW, this stuff is important for the "suspend to idle" (S0ix) stuff.
> Most platforms supporting S0ix have some sort of Power Management IC
> (PMIC) ooked up over I2C that is involved in powering stuff down for
> the deepest idle states.

The ones I've seen so far while researching this have been all MMIO based,
but I wouldn't put it past someone to build something like you've described.

Thanks for taking the time to explain things above. Diff looks ok,
(see below for two nits), and ok mlarkin whenever you're ready. I'm pretty
sure this will also fix the GPD pocket battery status, which I'll check
tonight.

-ml

>
> > > Probably needs some wider testing.
> > >
> > > After that's done, ok?
> > >
> > >
> > > Index: dev/acpi/acpi.c
> > > ===================================================================
> > > RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
> > > retrieving revision 1.341
> > > diff -u -p -r1.341 acpi.c
> > > --- dev/acpi/acpi.c 27 Mar 2018 21:11:16 -0000 1.341
> > > +++ dev/acpi/acpi.c 13 May 2018 13:49:46 -0000
> > > @@ -920,6 +920,23 @@ acpi_register_gpio(struct acpi_softc *sc
> > >  }
> > >  
> > >  void
> > > +acpi_register_gsb(struct acpi_softc *sc, struct aml_node *devnode)
> > > +{
> > > + struct aml_value arg[2];
> > > + struct aml_node *node;
> > > +
> > > + /* Register GenericSerialBus address space. */
> > > + memset(&arg, 0, sizeof(arg));
> > > + arg[0].type = AML_OBJTYPE_INTEGER;
> > > + arg[0].v_integer = ACPI_OPREG_GSB;
> > > + arg[1].type = AML_OBJTYPE_INTEGER;
> > > + arg[1].v_integer = 1;
> > > + node = aml_searchname(devnode, "_REG");
> > > + if (node && aml_evalnode(sc, node, 2, arg, NULL))
> > > + printf("%s: _REG failed\n", node->name);
> > > +}
> > > +
> > > +void
> > >  acpi_attach(struct device *parent, struct device *self, void *aux)
> > >  {
> > >   struct bios_attach_args *ba = aux;
> > > Index: dev/acpi/acpivar.h
> > > ===================================================================
> > > RCS file: /cvs/src/sys/dev/acpi/acpivar.h,v
> > > retrieving revision 1.89
> > > diff -u -p -r1.89 acpivar.h
> > > --- dev/acpi/acpivar.h 29 Nov 2017 22:51:01 -0000 1.89
> > > +++ dev/acpi/acpivar.h 13 May 2018 13:49:46 -0000
> > > @@ -333,6 +333,7 @@ void acpi_wakeup(void *);
> > >  int acpi_gasio(struct acpi_softc *, int, int, uint64_t, int, int, void *);
> > >  
> > >  void acpi_register_gpio(struct acpi_softc *, struct aml_node *);
> > > +void acpi_register_gsb(struct acpi_softc *, struct aml_node *);
> > >  
> > >  int acpi_set_gpehandler(struct acpi_softc *, int,
> > >      int (*)(struct acpi_softc *, int, void *), void *, int);
> > > Index: dev/acpi/amltypes.h
> > > ===================================================================
> > > RCS file: /cvs/src/sys/dev/acpi/amltypes.h,v
> > > retrieving revision 1.45
> > > diff -u -p -r1.45 amltypes.h
> > > --- dev/acpi/amltypes.h 8 May 2016 11:08:01 -0000 1.45
> > > +++ dev/acpi/amltypes.h 13 May 2018 13:49:46 -0000
> > > @@ -371,6 +371,8 @@ struct acpi_gpio {
> > >   void (*intr_establish)(void *, int, int, int (*)(void *), void *);
> > >  };
> > >  
> > > +struct i2c_controller;
> > > +
> > >  struct aml_node {
> > >   struct aml_node *parent;
> > >  
> > > @@ -385,8 +387,9 @@ struct aml_node {
> > >   u_int8_t *end;
> > >  
> > >   struct aml_value *value;
> > > - struct acpi_pci  *pci;
> > > + struct acpi_pci *pci;
> > >   struct acpi_gpio *gpio;
> > > + struct i2c_controller *i2c;
> > >  };
> > >  
> > >  #define aml_bitmask(n) (1L << ((n) & 0x7))
> > > Index: dev/acpi/dsdt.c
> > > ===================================================================
> > > RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v
> > > retrieving revision 1.236
> > > diff -u -p -r1.236 dsdt.c
> > > --- dev/acpi/dsdt.c 29 Nov 2017 15:22:22 -0000 1.236
> > > +++ dev/acpi/dsdt.c 13 May 2018 13:49:47 -0000
> > > @@ -33,6 +33,8 @@
> > >  #include <dev/acpi/amltypes.h>
> > >  #include <dev/acpi/dsdt.h>
> > >  
> > > +#include <dev/i2c/i2cvar.h>
> > > +
> > >  #ifdef SMALL_KERNEL
> > >  #undef ACPI_DEBUG
> > >  #endif
> > > @@ -2288,6 +2290,7 @@ aml_register_regionspace(struct aml_node
> > >  
> > >  void aml_rwgen(struct aml_value *, int, int, struct aml_value *, int, int);
> > >  void aml_rwgpio(struct aml_value *, int, int, struct aml_value *, int, int);
> > > +void aml_rwgsb(struct aml_value *, int, int, struct aml_value *, int, int);
> > >  void aml_rwindexfield(struct aml_value *, struct aml_value *val, int);
> > >  void aml_rwfield(struct aml_value *, int, int, struct aml_value *, int);
> > >  
> > > @@ -2512,6 +2515,96 @@ aml_rwgpio(struct aml_value *conn, int b
> > >  }
> > >  
> > >  void
> > > +aml_rwgsb(struct aml_value *conn, int bpos, int blen, struct aml_value *val,
> > > +    int mode, int flag)
> > > +{
> > > + union acpi_resource *crs = (union acpi_resource *)conn->v_buffer;
> > > + struct aml_node *node;
> > > + i2c_tag_t tag;
> > > + i2c_op_t op;
> > > + i2c_addr_t addr;
> > > + int cmdlen, buflen;
> > > + uint8_t cmd;
> > > + uint8_t *buf;
> > > + int err;
> > > +
> > > + if (conn->type != AML_OBJTYPE_BUFFER || conn->length < 5 ||
> > > +    AML_CRSTYPE(crs) != LR_SERBUS || AML_CRSLEN(crs) > conn->length ||
> > > +    crs->lr_i2cbus.revid != 1 || crs->lr_i2cbus.type != LR_SERBUS_I2C)
> > > + aml_die("Invalid GenericSerialBus");
> > > + if (AML_FIELD_ACCESS(flag) != AML_FIELD_BUFFERACC ||
> > > +    bpos & 0x3 || blen != 8)
> > > + aml_die("Invalid GenericSerialBus access");
> > > +
> > > + node = aml_searchname(conn->node,
> > > +    (char *)&crs->lr_i2cbus.vdata[crs->lr_i2cbus.tlength - 6]);
> > > +
> > > + if (node == NULL || node->i2c == NULL)
> > > + aml_die("Could not find GenericSerialBus controller");
> > > +
> > > + switch (((flag >> 6) & 0x3)) {

too many parenthesis?

> > > + case 0: /* Normal */
> > > + switch (AML_FIELD_ATTR(flag)) {
> > > + case 0x02: /* AttribQuick */
> > > + cmdlen = 0;
> > > + buflen = 0;
> > > + break;
> > > + case 0x04: /* AttribSendReceive */
> > > + cmdlen = 0;
> > > + buflen = 1;
> > > + break;
> > > + case 0x06: /* AttribByte */
> > > + cmdlen = 1;
> > > + buflen = 1;
> > > + break;
> > > + case 0x08: /* AttribWord */
> > > + cmdlen = 1;
> > > + buflen = 2;
> > > + break;
> > > + default:
> > > + aml_die("unsupported access type 0x%x", flag);
> > > + break;
> > > + }
> > > + break;
> > > + case 1: /* AttribBytes */
> > > + cmdlen = 1;
> > > + buflen = AML_FIELD_ATTR(flag);
> > > + break;
> > > + case 2: /* AttribRawBytes */
> > > + cmdlen = 0;
> > > + buflen = AML_FIELD_ATTR(flag);
> > > + break;
> > > + default:
> > > + aml_die("unsupported access type 0x%x", flag);
> > > + break;
> > > + }
> > > +
> > > + if (mode == ACPI_IOREAD) {
> > > + _aml_setvalue(val, AML_OBJTYPE_BUFFER, buflen + 2, NULL);
> > > + op = I2C_OP_READ_WITH_STOP;
> > > + } else {
> > > + op = I2C_OP_WRITE_WITH_STOP;
> > > + }
> > > +
> > > + tag = node->i2c;
> > > + addr = crs->lr_i2cbus._adr;
> > > + cmd = bpos >> 3;
> > > + buf = val->v_buffer;
> > > +
> > > + iic_acquire_bus(tag, 0);
> > > + err = iic_exec(tag, op, addr, &cmd, cmdlen, &buf[2], buflen, 0);
> > > + iic_release_bus(tag, 0);
> > > +
> > > + /*
> > > + * The ACPI specification doesn't tell us what the status
> > > + * codes mean beyond implying that zero means success.  So use
> > > + * the error returned from the transfer.  All possible error
> > > + * numbers should fit in a single bit.

byte?

> > > + */
> > > + buf[0] = err;
> > > +}
> > > +
> > > +void
> > >  aml_rwindexfield(struct aml_value *fld, struct aml_value *val, int mode)
> > >  {
> > >   struct aml_value tmp, *ref1, *ref2;
> > > @@ -2612,6 +2705,10 @@ aml_rwfield(struct aml_value *fld, int b
> > >   aml_rwgpio(ref2, bpos, blen, val, mode,
> > >      fld->v_field.flags);
> > >   break;
> > > + case ACPI_OPREG_GSB:
> > > + aml_rwgsb(ref2, fld->v_field.bitpos + bpos, blen,
> > > +    val, mode, fld->v_field.flags);
> > > + break;
> > >   default:
> > >   aml_rwgen(ref1, fld->v_field.bitpos + bpos, blen,
> > >      val, mode, fld->v_field.flags);
> > > @@ -2699,9 +2796,11 @@ aml_parsefieldlist(struct aml_scope *msc
> > >   mscope->pos++;
> > >   blen = aml_parselength(mscope);
> > >   break;
> > > - case 0x01: /* flags */
> > > - mscope->pos += 3;
> > > + case 0x01: /* attrib */
> > > + mscope->pos++;
> > >   blen = 0;
> > > + flags = aml_get8(mscope->pos++);
> > > + flags |= aml_get8(mscope->pos++) << 8;
> > >   break;
> > >   case 0x02: /* connection */
> > >   mscope->pos++;
> > > Index: dev/acpi/dwiic_acpi.c
> > > ===================================================================
> > > RCS file: /cvs/src/sys/dev/acpi/dwiic_acpi.c,v
> > > retrieving revision 1.3
> > > diff -u -p -r1.3 dwiic_acpi.c
> > > --- dev/acpi/dwiic_acpi.c 19 Jan 2018 18:20:38 -0000 1.3
> > > +++ dev/acpi/dwiic_acpi.c 13 May 2018 13:49:47 -0000
> > > @@ -193,6 +193,9 @@ dwiic_acpi_attach(struct device *parent,
> > >  
> > >   config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
> > >  
> > > + sc->sc_devnode->i2c = &sc->sc_i2c_tag;
> > > + acpi_register_gsb(sc->sc_acpi, sc->sc_devnode);
> > > +
> > >   return;
> > >  }
> > >  
> > >
> >

Reply | Threaded
Open this post in threaded view
|

Re: acpi(4): GenericSerialBus OperationRegion support

Mike Larkin
In reply to this post by Mark Kettenis
On Mon, May 14, 2018 at 08:22:47PM +0200, Mark Kettenis wrote:

> > Date: Sun, 13 May 2018 22:27:09 -0700
> > From: Mike Larkin <[hidden email]>
> >
> > On Sun, May 13, 2018 at 03:57:50PM +0200, Mark Kettenis wrote:
> > > The diff below implements functionality that allows AML access to
> > > devices that sit on an I2C bus.  Only a subset of the various access
> > > methods is implemented; some of the missing ones are not a very good
> > > fit for our AML implementation.  But this is enough to make reading
> > > the battery status on the little Lenovo that mlarkin@ handed me at Elk
> > > Lakes work.
> > >
> >
> > Can you elaborate on what isn't a good fit? Just curious.
>
> Our i2c layer makes implementing the "Block" access types awkward, at
> least for reads.  At least it isn't obvious to me what implementation
> would work.
>
> The AML interpreter makes implementing the "ProcessCall" interfaces
> hard at least for reads as in that case the code doesn't see the
> buffer that contains the values that have to be written.
>
> We can probably find a way to make this work, but I don't seem to have
> any devices that use these access types.
>
> BTW, this stuff is important for the "suspend to idle" (S0ix) stuff.
> Most platforms supporting S0ix have some sort of Power Management IC
> (PMIC) ooked up over I2C that is involved in powering stuff down for
> the deepest idle states.
>
> > > Probably needs some wider testing.
> > >
> > > After that's done, ok?
> > >

Just to follow up, this did not fix the battery issue (still "absent" and
0%) on the GPD.

-ml

> > >
> > > Index: dev/acpi/acpi.c
> > > ===================================================================
> > > RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
> > > retrieving revision 1.341
> > > diff -u -p -r1.341 acpi.c
> > > --- dev/acpi/acpi.c 27 Mar 2018 21:11:16 -0000 1.341
> > > +++ dev/acpi/acpi.c 13 May 2018 13:49:46 -0000
> > > @@ -920,6 +920,23 @@ acpi_register_gpio(struct acpi_softc *sc
> > >  }
> > >  
> > >  void
> > > +acpi_register_gsb(struct acpi_softc *sc, struct aml_node *devnode)
> > > +{
> > > + struct aml_value arg[2];
> > > + struct aml_node *node;
> > > +
> > > + /* Register GenericSerialBus address space. */
> > > + memset(&arg, 0, sizeof(arg));
> > > + arg[0].type = AML_OBJTYPE_INTEGER;
> > > + arg[0].v_integer = ACPI_OPREG_GSB;
> > > + arg[1].type = AML_OBJTYPE_INTEGER;
> > > + arg[1].v_integer = 1;
> > > + node = aml_searchname(devnode, "_REG");
> > > + if (node && aml_evalnode(sc, node, 2, arg, NULL))
> > > + printf("%s: _REG failed\n", node->name);
> > > +}
> > > +
> > > +void
> > >  acpi_attach(struct device *parent, struct device *self, void *aux)
> > >  {
> > >   struct bios_attach_args *ba = aux;
> > > Index: dev/acpi/acpivar.h
> > > ===================================================================
> > > RCS file: /cvs/src/sys/dev/acpi/acpivar.h,v
> > > retrieving revision 1.89
> > > diff -u -p -r1.89 acpivar.h
> > > --- dev/acpi/acpivar.h 29 Nov 2017 22:51:01 -0000 1.89
> > > +++ dev/acpi/acpivar.h 13 May 2018 13:49:46 -0000
> > > @@ -333,6 +333,7 @@ void acpi_wakeup(void *);
> > >  int acpi_gasio(struct acpi_softc *, int, int, uint64_t, int, int, void *);
> > >  
> > >  void acpi_register_gpio(struct acpi_softc *, struct aml_node *);
> > > +void acpi_register_gsb(struct acpi_softc *, struct aml_node *);
> > >  
> > >  int acpi_set_gpehandler(struct acpi_softc *, int,
> > >      int (*)(struct acpi_softc *, int, void *), void *, int);
> > > Index: dev/acpi/amltypes.h
> > > ===================================================================
> > > RCS file: /cvs/src/sys/dev/acpi/amltypes.h,v
> > > retrieving revision 1.45
> > > diff -u -p -r1.45 amltypes.h
> > > --- dev/acpi/amltypes.h 8 May 2016 11:08:01 -0000 1.45
> > > +++ dev/acpi/amltypes.h 13 May 2018 13:49:46 -0000
> > > @@ -371,6 +371,8 @@ struct acpi_gpio {
> > >   void (*intr_establish)(void *, int, int, int (*)(void *), void *);
> > >  };
> > >  
> > > +struct i2c_controller;
> > > +
> > >  struct aml_node {
> > >   struct aml_node *parent;
> > >  
> > > @@ -385,8 +387,9 @@ struct aml_node {
> > >   u_int8_t *end;
> > >  
> > >   struct aml_value *value;
> > > - struct acpi_pci  *pci;
> > > + struct acpi_pci *pci;
> > >   struct acpi_gpio *gpio;
> > > + struct i2c_controller *i2c;
> > >  };
> > >  
> > >  #define aml_bitmask(n) (1L << ((n) & 0x7))
> > > Index: dev/acpi/dsdt.c
> > > ===================================================================
> > > RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v
> > > retrieving revision 1.236
> > > diff -u -p -r1.236 dsdt.c
> > > --- dev/acpi/dsdt.c 29 Nov 2017 15:22:22 -0000 1.236
> > > +++ dev/acpi/dsdt.c 13 May 2018 13:49:47 -0000
> > > @@ -33,6 +33,8 @@
> > >  #include <dev/acpi/amltypes.h>
> > >  #include <dev/acpi/dsdt.h>
> > >  
> > > +#include <dev/i2c/i2cvar.h>
> > > +
> > >  #ifdef SMALL_KERNEL
> > >  #undef ACPI_DEBUG
> > >  #endif
> > > @@ -2288,6 +2290,7 @@ aml_register_regionspace(struct aml_node
> > >  
> > >  void aml_rwgen(struct aml_value *, int, int, struct aml_value *, int, int);
> > >  void aml_rwgpio(struct aml_value *, int, int, struct aml_value *, int, int);
> > > +void aml_rwgsb(struct aml_value *, int, int, struct aml_value *, int, int);
> > >  void aml_rwindexfield(struct aml_value *, struct aml_value *val, int);
> > >  void aml_rwfield(struct aml_value *, int, int, struct aml_value *, int);
> > >  
> > > @@ -2512,6 +2515,96 @@ aml_rwgpio(struct aml_value *conn, int b
> > >  }
> > >  
> > >  void
> > > +aml_rwgsb(struct aml_value *conn, int bpos, int blen, struct aml_value *val,
> > > +    int mode, int flag)
> > > +{
> > > + union acpi_resource *crs = (union acpi_resource *)conn->v_buffer;
> > > + struct aml_node *node;
> > > + i2c_tag_t tag;
> > > + i2c_op_t op;
> > > + i2c_addr_t addr;
> > > + int cmdlen, buflen;
> > > + uint8_t cmd;
> > > + uint8_t *buf;
> > > + int err;
> > > +
> > > + if (conn->type != AML_OBJTYPE_BUFFER || conn->length < 5 ||
> > > +    AML_CRSTYPE(crs) != LR_SERBUS || AML_CRSLEN(crs) > conn->length ||
> > > +    crs->lr_i2cbus.revid != 1 || crs->lr_i2cbus.type != LR_SERBUS_I2C)
> > > + aml_die("Invalid GenericSerialBus");
> > > + if (AML_FIELD_ACCESS(flag) != AML_FIELD_BUFFERACC ||
> > > +    bpos & 0x3 || blen != 8)
> > > + aml_die("Invalid GenericSerialBus access");
> > > +
> > > + node = aml_searchname(conn->node,
> > > +    (char *)&crs->lr_i2cbus.vdata[crs->lr_i2cbus.tlength - 6]);
> > > +
> > > + if (node == NULL || node->i2c == NULL)
> > > + aml_die("Could not find GenericSerialBus controller");
> > > +
> > > + switch (((flag >> 6) & 0x3)) {
> > > + case 0: /* Normal */
> > > + switch (AML_FIELD_ATTR(flag)) {
> > > + case 0x02: /* AttribQuick */
> > > + cmdlen = 0;
> > > + buflen = 0;
> > > + break;
> > > + case 0x04: /* AttribSendReceive */
> > > + cmdlen = 0;
> > > + buflen = 1;
> > > + break;
> > > + case 0x06: /* AttribByte */
> > > + cmdlen = 1;
> > > + buflen = 1;
> > > + break;
> > > + case 0x08: /* AttribWord */
> > > + cmdlen = 1;
> > > + buflen = 2;
> > > + break;
> > > + default:
> > > + aml_die("unsupported access type 0x%x", flag);
> > > + break;
> > > + }
> > > + break;
> > > + case 1: /* AttribBytes */
> > > + cmdlen = 1;
> > > + buflen = AML_FIELD_ATTR(flag);
> > > + break;
> > > + case 2: /* AttribRawBytes */
> > > + cmdlen = 0;
> > > + buflen = AML_FIELD_ATTR(flag);
> > > + break;
> > > + default:
> > > + aml_die("unsupported access type 0x%x", flag);
> > > + break;
> > > + }
> > > +
> > > + if (mode == ACPI_IOREAD) {
> > > + _aml_setvalue(val, AML_OBJTYPE_BUFFER, buflen + 2, NULL);
> > > + op = I2C_OP_READ_WITH_STOP;
> > > + } else {
> > > + op = I2C_OP_WRITE_WITH_STOP;
> > > + }
> > > +
> > > + tag = node->i2c;
> > > + addr = crs->lr_i2cbus._adr;
> > > + cmd = bpos >> 3;
> > > + buf = val->v_buffer;
> > > +
> > > + iic_acquire_bus(tag, 0);
> > > + err = iic_exec(tag, op, addr, &cmd, cmdlen, &buf[2], buflen, 0);
> > > + iic_release_bus(tag, 0);
> > > +
> > > + /*
> > > + * The ACPI specification doesn't tell us what the status
> > > + * codes mean beyond implying that zero means success.  So use
> > > + * the error returned from the transfer.  All possible error
> > > + * numbers should fit in a single bit.
> > > + */
> > > + buf[0] = err;
> > > +}
> > > +
> > > +void
> > >  aml_rwindexfield(struct aml_value *fld, struct aml_value *val, int mode)
> > >  {
> > >   struct aml_value tmp, *ref1, *ref2;
> > > @@ -2612,6 +2705,10 @@ aml_rwfield(struct aml_value *fld, int b
> > >   aml_rwgpio(ref2, bpos, blen, val, mode,
> > >      fld->v_field.flags);
> > >   break;
> > > + case ACPI_OPREG_GSB:
> > > + aml_rwgsb(ref2, fld->v_field.bitpos + bpos, blen,
> > > +    val, mode, fld->v_field.flags);
> > > + break;
> > >   default:
> > >   aml_rwgen(ref1, fld->v_field.bitpos + bpos, blen,
> > >      val, mode, fld->v_field.flags);
> > > @@ -2699,9 +2796,11 @@ aml_parsefieldlist(struct aml_scope *msc
> > >   mscope->pos++;
> > >   blen = aml_parselength(mscope);
> > >   break;
> > > - case 0x01: /* flags */
> > > - mscope->pos += 3;
> > > + case 0x01: /* attrib */
> > > + mscope->pos++;
> > >   blen = 0;
> > > + flags = aml_get8(mscope->pos++);
> > > + flags |= aml_get8(mscope->pos++) << 8;
> > >   break;
> > >   case 0x02: /* connection */
> > >   mscope->pos++;
> > > Index: dev/acpi/dwiic_acpi.c
> > > ===================================================================
> > > RCS file: /cvs/src/sys/dev/acpi/dwiic_acpi.c,v
> > > retrieving revision 1.3
> > > diff -u -p -r1.3 dwiic_acpi.c
> > > --- dev/acpi/dwiic_acpi.c 19 Jan 2018 18:20:38 -0000 1.3
> > > +++ dev/acpi/dwiic_acpi.c 13 May 2018 13:49:47 -0000
> > > @@ -193,6 +193,9 @@ dwiic_acpi_attach(struct device *parent,
> > >  
> > >   config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
> > >  
> > > + sc->sc_devnode->i2c = &sc->sc_i2c_tag;
> > > + acpi_register_gsb(sc->sc_acpi, sc->sc_devnode);
> > > +
> > >   return;
> > >  }
> > >  
> > >
> >

Reply | Threaded
Open this post in threaded view
|

Re: acpi(4): GenericSerialBus OperationRegion support

Joseph Mayer
In reply to this post by Mark Kettenis
Hi Mike,

About the GPDPocket laptop specifically, my best awareness is that its
battery status reporting has been reported to be quirky, and that it
might work in some BIOS versions and not in other.

The GPDPocket's BIOS comes in two flavors, "unlocked" with more options
and "locked" with less.

To my best awareness the best "unlocked" one is dated 2017-06-28 [1],
and the best "locked" one is dated 2017-08-07 [2].

I think GPD's skill is hardware rather than software.

Below some related references [3]. Take care BIOS options as they could
brick the laptop.

Joseph

[1]
"P7-20170628-Ubuntu-BIOS.zip"

http://www.gpd.hk/news.asp?id=1519&selectclassid=002002

http://forum.gpd.hk/t135-as-of-21-august-2017-what-is-the-latest-unlocked-firmware-for-the-gpd-pocket

[2]
"P7 BIOS-20170807.zip"

[3]
http://forum.gpd.hk/t167-how-enable-battery-status-with-the-unlocked-bios-2017-06-28

http://forum.gpd.hk/t175-gpd-pocket-win-10-pro-and-charging-issues

https://www.reddit.com/r/GPDPocket/comments/6s7zck/my_unlocked_bios_working_settings_dptf_limit/

https://boards.dingoonity.org/gpd-windows-devices/gpd-win-either-not-charging-properly-or-battery-display-broken/

https://github.com/stockmind/gpd-pocket-ubuntu-respin , "It also let you boot on zero battery charge (previous versions require at least 15-20% of battery charge to boot)."

"Other than that your BIOS is known to have something different related to enumerating devices and management of battery that gave some trouble on past kernels" https://github.com/stockmind/gpd-pocket-ubuntu-respin/issues/63

2018-05-17 15:09 GMT+08:00 Mike Larkin <[hidden email]>:
> Just to follow up, this did not fix the battery issue (still "absent" and
> 0%) on the GPD.

Reply | Threaded
Open this post in threaded view
|

Re: acpi(4): GenericSerialBus OperationRegion support

Mike Larkin
On Thu, May 17, 2018 at 03:59:04AM -0400, Joseph Mayer wrote:

> Hi Mike,
>
> About the GPDPocket laptop specifically, my best awareness is that its
> battery status reporting has been reported to be quirky, and that it
> might work in some BIOS versions and not in other.
>
> The GPDPocket's BIOS comes in two flavors, "unlocked" with more options
> and "locked" with less.
>
> To my best awareness the best "unlocked" one is dated 2017-06-28 [1],
> and the best "locked" one is dated 2017-08-07 [2].
>
> I think GPD's skill is hardware rather than software.
>
> Below some related references [3]. Take care BIOS options as they could
> brick the laptop.
>
> Joseph
>

Thanks. Looks like I have the latest locked firmware, will try the other one..

-ml


> [1]
> "P7-20170628-Ubuntu-BIOS.zip"
>
> http://www.gpd.hk/news.asp?id=1519&selectclassid=002002
>
> http://forum.gpd.hk/t135-as-of-21-august-2017-what-is-the-latest-unlocked-firmware-for-the-gpd-pocket
>
> [2]
> "P7 BIOS-20170807.zip"
>
> [3]
> http://forum.gpd.hk/t167-how-enable-battery-status-with-the-unlocked-bios-2017-06-28
>
> http://forum.gpd.hk/t175-gpd-pocket-win-10-pro-and-charging-issues
>
> https://www.reddit.com/r/GPDPocket/comments/6s7zck/my_unlocked_bios_working_settings_dptf_limit/
>
> https://boards.dingoonity.org/gpd-windows-devices/gpd-win-either-not-charging-properly-or-battery-display-broken/
>
> https://github.com/stockmind/gpd-pocket-ubuntu-respin , "It also let you boot on zero battery charge (previous versions require at least 15-20% of battery charge to boot)."
>
> "Other than that your BIOS is known to have something different related to enumerating devices and management of battery that gave some trouble on past kernels" https://github.com/stockmind/gpd-pocket-ubuntu-respin/issues/63
>
> 2018-05-17 15:09 GMT+08:00 Mike Larkin <[hidden email]>:
> > Just to follow up, this did not fix the battery issue (still "absent" and
> > 0%) on the GPD.